summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
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->hashjointable = NULL;
+ node->hashjointablekey = 0;
+ node->hashjointablesize = 0;
+ node->hashdone = false;
+
+ return (node);
}
-static Hash *
-make_hash(List *tlist, Var *hashkey, Plan *lefttree)
+static Hash *
+make_hash(List * tlist, Var * hashkey, Plan * lefttree)
{
- Hash *node = makeNode(Hash);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = NULL;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->hashkey = hashkey;
- node->hashtable = NULL;
- node->hashtablekey = 0;
- node->hashtablesize = 0;
-
- return(node);
+ Hash *node = makeNode(Hash);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NULL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->hashkey = hashkey;
+ node->hashtable = NULL;
+ node->hashtablekey = 0;
+ node->hashtablesize = 0;
+
+ return (node);
}
static MergeJoin *
-make_mergesort(List *tlist,
- List *qpqual,
- List *mergeclauses,
- Oid opcode,
- Oid *rightorder,
- Oid *leftorder,
- Plan *righttree,
- Plan *lefttree)
+make_mergesort(List * tlist,
+ List * qpqual,
+ List * mergeclauses,
+ Oid opcode,
+ Oid * rightorder,
+ Oid * leftorder,
+ Plan * righttree,
+ Plan * lefttree)
{
- MergeJoin *node = makeNode(MergeJoin);
- 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->mergeclauses = mergeclauses;
- node->mergesortop = opcode;
- node->mergerightorder = rightorder;
- node->mergeleftorder = leftorder;
-
- return(node);
+ MergeJoin *node = makeNode(MergeJoin);
+ 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->mergeclauses = mergeclauses;
+ node->mergesortop = opcode;
+ node->mergerightorder = rightorder;
+ node->mergeleftorder = leftorder;
+
+ return (node);
}
-Sort *
-make_sort(List *tlist, Oid tempid, Plan *lefttree, int keycount)
+Sort *
+make_sort(List * tlist, Oid tempid, Plan * lefttree, int keycount)
{
- Sort *node = makeNode(Sort);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = NIL;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->tempid = tempid;
- node->keycount = keycount;
-
- return(node);
+ Sort *node = makeNode(Sort);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NIL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->tempid = tempid;
+ node->keycount = keycount;
+
+ return (node);
}
static Material *
-make_material(List *tlist,
- Oid tempid,
- Plan *lefttree,
- int keycount)
+make_material(List * tlist,
+ Oid tempid,
+ Plan * lefttree,
+ int keycount)
{
- Material *node = makeNode(Material);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = NIL;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->tempid = tempid;
- node->keycount = keycount;
-
- return(node);
+ Material *node = makeNode(Material);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NIL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->tempid = tempid;
+ node->keycount = keycount;
+
+ return (node);
}
-Agg *
-make_agg(List *tlist, int nagg, Aggreg **aggs)
+Agg *
+make_agg(List * tlist, int nagg, Aggreg ** aggs)
{
- Agg *node = makeNode(Agg);
-
- node->plan.cost = 0.0;
- node->plan.state = (EState*)NULL;
- node->plan.qual = NULL;
- node->plan.targetlist = tlist;
- node->plan.lefttree = (Plan*)NULL;
- node->plan.righttree = (Plan*)NULL;
- node->numAgg = nagg;
- node->aggs = aggs;
-
- return(node);
+ Agg *node = makeNode(Agg);
+
+ node->plan.cost = 0.0;
+ node->plan.state = (EState *) NULL;
+ node->plan.qual = NULL;
+ node->plan.targetlist = tlist;
+ node->plan.lefttree = (Plan *) NULL;
+ node->plan.righttree = (Plan *) NULL;
+ node->numAgg = nagg;
+ node->aggs = aggs;
+
+ return (node);
}
-Group *
-make_group(List *tlist,
- bool tuplePerGroup,
- int ngrp,
- AttrNumber *grpColIdx,
- Sort *lefttree)
+Group *
+make_group(List * tlist,
+ bool tuplePerGroup,
+ int ngrp,
+ AttrNumber * grpColIdx,
+ Sort * lefttree)
{
- Group *node = makeNode(Group);
-
- node->plan.cost = 0.0;
- node->plan.state = (EState*)NULL;
- node->plan.qual = NULL;
- node->plan.targetlist = tlist;
- node->plan.lefttree = (Plan*)lefttree;
- node->plan.righttree = (Plan*)NULL;
- node->tuplePerGroup = tuplePerGroup;
- node->numCols = ngrp;
- node->grpColIdx = grpColIdx;
-
- return(node);
+ Group *node = makeNode(Group);
+
+ node->plan.cost = 0.0;
+ node->plan.state = (EState *) NULL;
+ node->plan.qual = NULL;
+ node->plan.targetlist = tlist;
+ node->plan.lefttree = (Plan *) lefttree;
+ node->plan.righttree = (Plan *) NULL;
+ node->tuplePerGroup = tuplePerGroup;
+ node->numCols = ngrp;
+ node->grpColIdx = grpColIdx;
+
+ return (node);
}
/*
- * A unique node always has a SORT node in the lefttree.
+ * A unique node always has a SORT node in the lefttree.
*
- * the uniqueAttr argument must be a null-terminated string,
- * either the name of the attribute to select unique on
+ * the uniqueAttr argument must be a null-terminated string,
+ * either the name of the attribute to select unique on
* or "*"
*/
-Unique *
-make_unique(List *tlist, Plan *lefttree, char* uniqueAttr)
+Unique *
+make_unique(List * tlist, Plan * lefttree, char *uniqueAttr)
{
- Unique *node = makeNode(Unique);
- Plan *plan = &node->plan;
-
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->qual = NIL;
- plan->lefttree = lefttree;
- plan->righttree = NULL;
- node->tempid = _TEMP_RELATION_ID_;
- node->keycount = 0;
- if (strcmp(uniqueAttr,"*") == 0)
- node->uniqueAttr = NULL;
- else
- {
- node->uniqueAttr=pstrdup(uniqueAttr);
- }
- return(node);
+ Unique *node = makeNode(Unique);
+ Plan *plan = &node->plan;
+
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->qual = NIL;
+ plan->lefttree = lefttree;
+ plan->righttree = NULL;
+ node->tempid = _TEMP_RELATION_ID_;
+ node->keycount = 0;
+ if (strcmp(uniqueAttr, "*") == 0)
+ node->uniqueAttr = NULL;
+ else
+ {
+ node->uniqueAttr = pstrdup(uniqueAttr);
+ }
+ return (node);
}
-List *generate_fjoin(List *tlist)
+List *
+generate_fjoin(List * tlist)
{
#if 0
- List tlistP;
- List newTlist = NIL;
- List fjoinList = NIL;
- int nIters = 0;
-
- /*
- * Break the target list into elements with Iter nodes,
- * and those without them.
- */
- foreach(tlistP, tlist) {
- List tlistElem;
-
- tlistElem = lfirst(tlistP);
- if (IsA(lsecond(tlistElem),Iter)) {
- nIters++;
- fjoinList = lappend(fjoinList, tlistElem);
- } else {
- newTlist = lappend(newTlist, tlistElem);
+ List tlistP;
+ List newTlist = NIL;
+ List fjoinList = NIL;
+ int nIters = 0;
+
+ /*
+ * Break the target list into elements with Iter nodes, and those
+ * without them.
+ */
+ foreach(tlistP, tlist)
+ {
+ List tlistElem;
+
+ tlistElem = lfirst(tlistP);
+ if (IsA(lsecond(tlistElem), Iter))
+ {
+ nIters++;
+ fjoinList = lappend(fjoinList, tlistElem);
+ }
+ else
+ {
+ newTlist = lappend(newTlist, tlistElem);
+ }
+ }
+
+ /*
+ * if we have an Iter node then we need to flatten.
+ */
+ if (nIters > 0)
+ {
+ List *inner;
+ List *tempList;
+ Fjoin *fjoinNode;
+ DatumPtr results = (DatumPtr) palloc(nIters * sizeof(Datum));
+ BoolPtr alwaysDone = (BoolPtr) palloc(nIters * sizeof(bool));
+
+ inner = lfirst(fjoinList);
+ fjoinList = lnext(fjoinList);
+ fjoinNode = (Fjoin) MakeFjoin(false,
+ nIters,
+ inner,
+ results,
+ alwaysDone);
+ tempList = lcons(fjoinNode, NIL);
+ tempList = nconc(tempList, fjoinList);
+ newTlist = lappend(newTlist, tempList);
}
- }
-
- /*
- * if we have an Iter node then we need to flatten.
- */
- if (nIters > 0) {
- List *inner;
- List *tempList;
- Fjoin *fjoinNode;
- DatumPtr results = (DatumPtr)palloc(nIters*sizeof(Datum));
- BoolPtr alwaysDone = (BoolPtr)palloc(nIters*sizeof(bool));
-
- inner = lfirst(fjoinList);
- fjoinList = lnext(fjoinList);
- fjoinNode = (Fjoin)MakeFjoin(false,
- nIters,
- inner,
- results,
- alwaysDone);
- tempList = lcons(fjoinNode, NIL);
- tempList = nconc(tempList, fjoinList);
- newTlist = lappend(newTlist, tempList);
- }
- return newTlist;
+ return newTlist;
#endif
- return tlist; /* do nothing for now - ay 10/94 */
+ return tlist; /* do nothing for now - ay 10/94 */
}
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 35b3969b702..62ff23f207e 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* initsplan.c--
- * Target list, qualification, joininfo initialization routines
+ * Target list, qualification, joininfo initialization routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.5 1997/04/24 16:04:23 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.6 1997/09/07 04:44:00 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,370 +33,397 @@
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
-extern int Quiet;
+extern int Quiet;
-static void add_clause_to_rels(Query *root, List *clause);
-static void add_join_clause_info_to_rels(Query *root, CInfo *clauseinfo,
- List *join_relids);
-static void add_vars_to_rels(Query *root, List *vars, List *join_relids);
+static void add_clause_to_rels(Query * root, List * clause);
+static void
+add_join_clause_info_to_rels(Query * root, CInfo * clauseinfo,
+ List * join_relids);
+static void add_vars_to_rels(Query * root, List * vars, List * join_relids);
-static MergeOrder *mergesortop(Expr *clause);
-static Oid hashjoinop(Expr *clause);
+static MergeOrder *mergesortop(Expr * clause);
+static Oid hashjoinop(Expr * clause);
/*****************************************************************************
*
- * TARGET LISTS
+ * TARGET LISTS
*
*****************************************************************************/
-/*
+/*
* initialize_rel_nodes--
- * Creates rel nodes for every relation mentioned in the target list
- * 'tlist' (if a node hasn't already been created) and adds them to
- * *query-relation-list*. Creates targetlist entries for each member of
- * 'tlist' and adds them to the tlist field of the appropriate rel node.
- *
- * Returns nothing.
+ * Creates rel nodes for every relation mentioned in the target list
+ * 'tlist' (if a node hasn't already been created) and adds them to
+ * *query-relation-list*. Creates targetlist entries for each member of
+ * 'tlist' and adds them to the tlist field of the appropriate rel node.
+ *
+ * Returns nothing.
*/
void
-initialize_base_rels_list(Query *root, List *tlist)
+initialize_base_rels_list(Query * root, List * tlist)
{
- List *tlist_vars = NIL;
- List *l = NIL;
- List *tvar = NIL;
-
- foreach (l, tlist) {
- TargetEntry *entry = (TargetEntry *) lfirst(l);
-
- tlist_vars = append(tlist_vars, pull_var_clause(entry->expr));
- }
-
- /* now, the target list only contains Var nodes */
- foreach (tvar, tlist_vars) {
- Var *var;
- Index varno;
- Rel *result;
-
- var = (Var*)lfirst(tvar);
- varno = var->varno;
- result = get_base_rel(root, varno);
-
- add_tl_element(result, var);
- }
+ List *tlist_vars = NIL;
+ List *l = NIL;
+ List *tvar = NIL;
+
+ foreach(l, tlist)
+ {
+ TargetEntry *entry = (TargetEntry *) lfirst(l);
+
+ tlist_vars = append(tlist_vars, pull_var_clause(entry->expr));
+ }
+
+ /* now, the target list only contains Var nodes */
+ foreach(tvar, tlist_vars)
+ {
+ Var *var;
+ Index varno;
+ Rel *result;
+
+ var = (Var *) lfirst(tvar);
+ varno = var->varno;
+ result = get_base_rel(root, varno);
+
+ add_tl_element(result, var);
+ }
}
/*
* add_missing_variables_to_base_rels -
- * If we have range variable(s) in the FROM clause that does not appear
- * in the target list nor qualifications, we add it to the base relation
- * list. For instance, "select f.x from foo f, foo f2" is a join of f and
- * f2. Note that if we have "select foo.x from foo f", it also gets turned
- * into a join.
+ * If we have range variable(s) in the FROM clause that does not appear
+ * in the target list nor qualifications, we add it to the base relation
+ * list. For instance, "select f.x from foo f, foo f2" is a join of f and
+ * f2. Note that if we have "select foo.x from foo f", it also gets turned
+ * into a join.
*/
void
-add_missing_vars_to_base_rels(Query *root, List *tlist)
+add_missing_vars_to_base_rels(Query * root, List * tlist)
{
- List *l;
- int varno;
-
- varno = 1;
- foreach (l, root->rtable) {
- RangeTblEntry *rte = (RangeTblEntry *)lfirst(l);
- List *relids;
- Rel *result;
- Var *var;
-
- relids = lconsi(varno, NIL);
- if (rte->inFromCl &&
- !rel_member(relids, root->base_relation_list_)) {
-
- var = makeVar(varno, -2 , 26, varno, -2);
- /* add it to base_relation_list_ */
- result = get_base_rel(root, varno);
- add_tl_element(result, var);
+ List *l;
+ int varno;
+
+ varno = 1;
+ foreach(l, root->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
+ List *relids;
+ Rel *result;
+ Var *var;
+
+ relids = lconsi(varno, NIL);
+ if (rte->inFromCl &&
+ !rel_member(relids, root->base_relation_list_))
+ {
+
+ var = makeVar(varno, -2, 26, varno, -2);
+ /* add it to base_relation_list_ */
+ result = get_base_rel(root, varno);
+ add_tl_element(result, var);
+ }
+ pfree(relids);
+ varno++;
}
- pfree(relids);
- varno++;
- }
- return;
+ return;
}
/*****************************************************************************
*
- * QUALIFICATIONS
+ * QUALIFICATIONS
*
*****************************************************************************/
-/*
+/*
* initialize-qualification--
- * Initializes ClauseInfo and JoinInfo fields of relation entries for all
- * relations appearing within clauses. Creates new relation entries if
- * necessary, adding them to *query-relation-list*.
- *
- * Returns nothing of interest.
+ * Initializes ClauseInfo and JoinInfo fields of relation entries for all
+ * relations appearing within clauses. Creates new relation entries if
+ * necessary, adding them to *query-relation-list*.
+ *
+ * Returns nothing of interest.
*/
void
-initialize_base_rels_jinfo(Query *root, List *clauses)
+initialize_base_rels_jinfo(Query * root, List * clauses)
{
- List *clause;
+ List *clause;
- foreach (clause, clauses) {
- add_clause_to_rels(root, lfirst(clause));
- }
- return;
+ foreach(clause, clauses)
+ {
+ add_clause_to_rels(root, lfirst(clause));
+ }
+ return;
}
-/*
+/*
* add-clause-to-rels--
- * Add clause information to either the 'ClauseInfo' or 'JoinInfo' field
- * of a relation entry(depending on whether or not the clause is a join)
- * by creating a new ClauseInfo node and setting appropriate fields
- * within the nodes.
- *
- * Returns nothing of interest.
+ * Add clause information to either the 'ClauseInfo' or 'JoinInfo' field
+ * of a relation entry(depending on whether or not the clause is a join)
+ * by creating a new ClauseInfo node and setting appropriate fields
+ * within the nodes.
+ *
+ * Returns nothing of interest.
*/
static void
-add_clause_to_rels(Query *root, List *clause)
+add_clause_to_rels(Query * root, List * clause)
{
- List *relids;
- List *vars;
- CInfo *clauseinfo = makeNode(CInfo);
+ List *relids;
+ List *vars;
+ CInfo *clauseinfo = makeNode(CInfo);
- /*
- * Retrieve all relids and vars contained within the clause.
- */
- clause_relids_vars((Node*)clause, &relids, &vars);
+ /*
+ * Retrieve all relids and vars contained within the clause.
+ */
+ clause_relids_vars((Node *) clause, &relids, &vars);
- clauseinfo->clause = (Expr*)clause;
- clauseinfo->notclause = contains_not((Node*)clause);
- clauseinfo->selectivity = 0;
- clauseinfo->indexids = NIL;
- clauseinfo->mergesortorder = (MergeOrder*)NULL;
- clauseinfo->hashjoinoperator = (Oid)0;
-
+ clauseinfo->clause = (Expr *) clause;
+ clauseinfo->notclause = contains_not((Node *) clause);
+ clauseinfo->selectivity = 0;
+ clauseinfo->indexids = NIL;
+ clauseinfo->mergesortorder = (MergeOrder *) NULL;
+ clauseinfo->hashjoinoperator = (Oid) 0;
- if(length(relids) == 1) {
- Rel *rel = get_base_rel(root, lfirsti(relids));
-
- /*
- * There is only one relation participating in 'clause',
- * so 'clause' must be a restriction clause.
- */
- /* the selectivity of the clause must be computed
- regardless of whether it's a restriction or a join clause */
- if (is_funcclause((Node*)clause))
- {
+ if (length(relids) == 1)
+ {
+ Rel *rel = get_base_rel(root, lfirsti(relids));
+
/*
- * XXX If we have a func clause set selectivity to 1/3,
- * really need a true selectivity function.
+ * There is only one relation participating in 'clause', so
+ * 'clause' must be a restriction clause.
*/
- clauseinfo->selectivity = (Cost)0.3333333;
- }
- else
- {
- clauseinfo->selectivity =
- compute_clause_selec(root, (Node*)clause,
- NIL);
- }
- rel->clauseinfo = lcons(clauseinfo,
- rel->clauseinfo);
- } else {
- /*
- * 'clause' is a join clause, since there is more than one
- * atom in the relid list.
- */
-
- if (is_funcclause((Node*)clause))
- {
+
/*
- * XXX If we have a func clause set selectivity to 1/3,
- * really need a true selectivity function.
+ * the selectivity of the clause must be computed regardless of
+ * whether it's a restriction or a join clause
*/
- clauseinfo->selectivity = (Cost)0.3333333;
- }
+ if (is_funcclause((Node *) clause))
+ {
+
+ /*
+ * XXX If we have a func clause set selectivity to 1/3, really
+ * need a true selectivity function.
+ */
+ clauseinfo->selectivity = (Cost) 0.3333333;
+ }
+ else
+ {
+ clauseinfo->selectivity =
+ compute_clause_selec(root, (Node *) clause,
+ NIL);
+ }
+ rel->clauseinfo = lcons(clauseinfo,
+ rel->clauseinfo);
+ }
else
- {
- clauseinfo->selectivity =
- compute_clause_selec(root, (Node*)clause,
- NIL);
- }
- add_join_clause_info_to_rels(root, clauseinfo, relids);
- add_vars_to_rels(root,vars, relids);
- }
+ {
+
+ /*
+ * 'clause' is a join clause, since there is more than one atom in
+ * the relid list.
+ */
+
+ if (is_funcclause((Node *) clause))
+ {
+
+ /*
+ * XXX If we have a func clause set selectivity to 1/3, really
+ * need a true selectivity function.
+ */
+ clauseinfo->selectivity = (Cost) 0.3333333;
+ }
+ else
+ {
+ clauseinfo->selectivity =
+ compute_clause_selec(root, (Node *) clause,
+ NIL);
+ }
+ add_join_clause_info_to_rels(root, clauseinfo, relids);
+ add_vars_to_rels(root, vars, relids);
+ }
}
-/*
+/*
* add-join-clause-info-to-rels--
- * For every relation participating in a join clause, add 'clauseinfo' to
- * the appropriate joininfo node(creating a new one and adding it to the
- * appropriate rel node if necessary).
- *
+ * For every relation participating in a join clause, add 'clauseinfo' to
+ * the appropriate joininfo node(creating a new one and adding it to the
+ * appropriate rel node if necessary).
+ *
* 'clauseinfo' describes the join clause
* 'join-relids' is the list of relations participating in the join clause
- *
+ *
* Returns nothing.
- *
+ *
*/
static void
-add_join_clause_info_to_rels(Query *root, CInfo *clauseinfo, List *join_relids)
+add_join_clause_info_to_rels(Query * root, CInfo * clauseinfo, List * join_relids)
{
- List *join_relid;
-
- foreach (join_relid, join_relids) {
- JInfo *joininfo;
- List *other_rels = NIL;
- List *rel;
-
- foreach (rel, join_relids)
- {
- if ( lfirsti(rel) != lfirsti(join_relid) )
- other_rels = lappendi (other_rels, lfirsti(rel));
- }
-
- joininfo =
- find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
- other_rels);
- joininfo->jinfoclauseinfo =
- lcons(copyObject((void*)clauseinfo), joininfo->jinfoclauseinfo);
-
- }
+ List *join_relid;
+
+ foreach(join_relid, join_relids)
+ {
+ JInfo *joininfo;
+ List *other_rels = NIL;
+ List *rel;
+
+ foreach(rel, join_relids)
+ {
+ if (lfirsti(rel) != lfirsti(join_relid))
+ other_rels = lappendi(other_rels, lfirsti(rel));
+ }
+
+ joininfo =
+ find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
+ other_rels);
+ joininfo->jinfoclauseinfo =
+ lcons(copyObject((void *) clauseinfo), joininfo->jinfoclauseinfo);
+
+ }
}
-/*
+/*
* add-vars-to-rels--
- * For each variable appearing in a clause,
- * (1) If a targetlist entry for the variable is not already present in
- * the appropriate relation's target list, add one.
- * (2) If a targetlist entry is already present, but the var is part of a
- * join clause, add the relids of the join relations to the JoinList
- * entry of the targetlist entry.
- *
- * 'vars' is the list of var nodes
- * 'join-relids' is the list of relids appearing in the join clause
- * (if this is a join clause)
- *
- * Returns nothing.
+ * For each variable appearing in a clause,
+ * (1) If a targetlist entry for the variable is not already present in
+ * the appropriate relation's target list, add one.
+ * (2) If a targetlist entry is already present, but the var is part of a
+ * join clause, add the relids of the join relations to the JoinList
+ * entry of the targetlist entry.
+ *
+ * 'vars' is the list of var nodes
+ * 'join-relids' is the list of relids appearing in the join clause
+ * (if this is a join clause)
+ *
+ * Returns nothing.
*/
static void
-add_vars_to_rels(Query *root, List *vars, List *join_relids)
+add_vars_to_rels(Query * root, List * vars, List * join_relids)
{
- Var *var;
- List *temp = NIL;
- Rel *rel = (Rel*)NULL;
- TargetEntry *tlistentry;
-
- foreach (temp, vars) {
- var = (Var*)lfirst(temp);
- rel = get_base_rel(root, var->varno);
- tlistentry = tlistentry_member(var, rel->targetlist);
- if(tlistentry==NULL)
- /* add a new entry */
- add_tl_element(rel, var);
- }
+ Var *var;
+ List *temp = NIL;
+ Rel *rel = (Rel *) NULL;
+ TargetEntry *tlistentry;
+
+ foreach(temp, vars)
+ {
+ var = (Var *) lfirst(temp);
+ rel = get_base_rel(root, var->varno);
+ tlistentry = tlistentry_member(var, rel->targetlist);
+ if (tlistentry == NULL)
+ /* add a new entry */
+ add_tl_element(rel, var);
+ }
}
/*****************************************************************************
*
- * JOININFO
+ * JOININFO
*
*****************************************************************************/
-/*
+/*
* initialize-join-clause-info--
- * Set the MergeSortable or HashJoinable field for every joininfo node
- * (within a rel node) and the MergeSortOrder or HashJoinOp field for
- * each clauseinfo node(within a joininfo node) for all relations in a
- * query.
- *
- * Returns nothing.
+ * Set the MergeSortable or HashJoinable field for every joininfo node
+ * (within a rel node) and the MergeSortOrder or HashJoinOp field for
+ * each clauseinfo node(within a joininfo node) for all relations in a
+ * query.
+ *
+ * Returns nothing.
*/
void
-initialize_join_clause_info(List *rel_list)
+initialize_join_clause_info(List * rel_list)
{
- List *x, *y, *z;
- Rel *rel;
- JInfo *joininfo;
- CInfo *clauseinfo;
- Expr *clause;
-
- foreach (x, rel_list) {
- rel = (Rel*)lfirst(x);
- foreach (y, rel->joininfo) {
- joininfo = (JInfo*)lfirst(y);
- foreach (z, joininfo->jinfoclauseinfo) {
- clauseinfo = (CInfo*)lfirst(z);
- clause = clauseinfo->clause;
- if(join_clause_p((Node*)clause)) {
- MergeOrder *sortop = (MergeOrder*)NULL;
- Oid hashop = (Oid)NULL;
-
- if (_enable_mergesort_)
- sortop = mergesortop(clause);
- if (_enable_hashjoin_)
- hashop = hashjoinop(clause);
-
- if (sortop) {
- clauseinfo->mergesortorder = sortop;
- joininfo->mergesortable = true;
- }
- if (hashop) {
- clauseinfo->hashjoinoperator = hashop;
- joininfo->hashjoinable = true;
- }
+ List *x,
+ *y,
+ *z;
+ Rel *rel;
+ JInfo *joininfo;
+ CInfo *clauseinfo;
+ Expr *clause;
+
+ foreach(x, rel_list)
+ {
+ rel = (Rel *) lfirst(x);
+ foreach(y, rel->joininfo)
+ {
+ joininfo = (JInfo *) lfirst(y);
+ foreach(z, joininfo->jinfoclauseinfo)
+ {
+ clauseinfo = (CInfo *) lfirst(z);
+ clause = clauseinfo->clause;
+ if (join_clause_p((Node *) clause))
+ {
+ MergeOrder *sortop = (MergeOrder *) NULL;
+ Oid hashop = (Oid) NULL;
+
+ if (_enable_mergesort_)
+ sortop = mergesortop(clause);
+ if (_enable_hashjoin_)
+ hashop = hashjoinop(clause);
+
+ if (sortop)
+ {
+ clauseinfo->mergesortorder = sortop;
+ joininfo->mergesortable = true;
+ }
+ if (hashop)
+ {
+ clauseinfo->hashjoinoperator = hashop;
+ joininfo->hashjoinable = true;
+ }
+ }
+ }
}
- }
}
- }
}
-/*
+/*
* mergesortop--
- * Returns the mergesort operator of an operator iff 'clause' is
- * mergesortable, i.e., both operands are single vars and the operator is
- * a mergesortable operator.
+ * Returns the mergesort operator of an operator iff 'clause' is
+ * mergesortable, i.e., both operands are single vars and the operator is
+ * a mergesortable operator.
*/
static MergeOrder *
-mergesortop(Expr *clause)
+mergesortop(Expr * clause)
{
- Oid leftOp, rightOp;
- bool sortable;
-
- sortable = op_mergesortable(((Oper*)clause->oper)->opno,
- (get_leftop(clause))->vartype,
- (get_rightop(clause))->vartype,
- &leftOp,
- &rightOp);
-
- if (sortable) {
- MergeOrder *morder = makeNode(MergeOrder);
-
- morder->join_operator = ((Oper*)clause->oper)->opno;
- morder->left_operator = leftOp;
- morder->right_operator = rightOp;
- morder->left_type = (get_leftop(clause))->vartype;
- morder->right_type = (get_rightop(clause))->vartype;
- return (morder);
- } else
- return(NULL);
+ Oid leftOp,
+ rightOp;
+ bool sortable;
+
+ sortable = op_mergesortable(((Oper *) clause->oper)->opno,
+ (get_leftop(clause))->vartype,
+ (get_rightop(clause))->vartype,
+ &leftOp,
+ &rightOp);
+
+ if (sortable)
+ {
+ MergeOrder *morder = makeNode(MergeOrder);
+
+ morder->join_operator = ((Oper *) clause->oper)->opno;
+ morder->left_operator = leftOp;
+ morder->right_operator = rightOp;
+ morder->left_type = (get_leftop(clause))->vartype;
+ morder->right_type = (get_rightop(clause))->vartype;
+ return (morder);
+ }
+ else
+ return (NULL);
}
-/*
+/*
* hashjoinop--
- * Returns the hashjoin operator of an operator iff 'clause' is
- * hashjoinable, i.e., both operands are single vars and the operator is
- * a hashjoinable operator.
+ * Returns the hashjoin operator of an operator iff 'clause' is
+ * hashjoinable, i.e., both operands are single vars and the operator is
+ * a hashjoinable operator.
*/
-static Oid
-hashjoinop(Expr *clause)
+static Oid
+hashjoinop(Expr * clause)
{
- return(op_hashjoinable(((Oper*)clause->oper)->opno,
- (get_leftop(clause))->vartype,
- (get_rightop(clause))->vartype));
+ return (op_hashjoinable(((Oper *) clause->oper)->opno,
+ (get_leftop(clause))->vartype,
+ (get_rightop(clause))->vartype));
}
diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c
index 7f70d76ac6c..630ed12d2a1 100644
--- a/src/backend/optimizer/plan/planmain.c
+++ b/src/backend/optimizer/plan/planmain.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* planmain.c--
- * Routines to plan a single query
+ * Routines to plan a single query
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.4 1997/04/29 04:32:50 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.5 1997/09/07 04:44:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,506 +38,536 @@
#include "utils/mcxt.h"
#include "utils/lsyscache.h"
-static Plan *subplanner(Query *root, List *flat_tlist, List *qual);
-static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
+static Plan *subplanner(Query * root, List * flat_tlist, List * qual);
+static Result *make_result(List * tlist, Node * resconstantqual, Plan * subplan);
-static Plan *make_groupPlan(List **tlist, bool tuplePerGroup,
- List *groupClause, Plan *subplan);
+static Plan *
+make_groupPlan(List ** tlist, bool tuplePerGroup,
+ List * groupClause, Plan * subplan);
-/*
+/*
* query_planner--
- * Routine to create a query plan. It does so by first creating a
- * subplan for the topmost level of attributes in the query. Then,
- * it modifies all target list and qualifications to consider the next
- * level of nesting and creates a plan for this modified query by
- * recursively calling itself. The two pieces are then merged together
- * by creating a result node that indicates which attributes should
- * be placed where and any relation level qualifications to be
- * satisfied.
- *
- * command-type is the query command, e.g., retrieve, delete, etc.
- * tlist is the target list of the query
- * qual is the qualification of the query
- *
- * Returns a query plan.
+ * Routine to create a query plan. It does so by first creating a
+ * subplan for the topmost level of attributes in the query. Then,
+ * it modifies all target list and qualifications to consider the next
+ * level of nesting and creates a plan for this modified query by
+ * recursively calling itself. The two pieces are then merged together
+ * by creating a result node that indicates which attributes should
+ * be placed where and any relation level qualifications to be
+ * satisfied.
+ *
+ * command-type is the query command, e.g., retrieve, delete, etc.
+ * tlist is the target list of the query
+ * qual is the qualification of the query
+ *
+ * Returns a query plan.
*/
-Plan *
-query_planner(Query *root,
- int command_type,
- List *tlist,
- List *qual)
+Plan *
+query_planner(Query * root,
+ int command_type,
+ List * tlist,
+ List * qual)
{
- List *constant_qual = NIL;
- List *flattened_tlist = NIL;
- List *level_tlist = NIL;
- Plan *subplan = (Plan*)NULL;
- Agg *aggplan = NULL;
-
- /*
- * A command without a target list or qualification is an error,
- * except for "delete foo".
- */
- if (tlist==NIL && qual==NULL) {
- if (command_type == CMD_DELETE ||
- /* Total hack here. I don't know how to handle
- statements like notify in action bodies.
- Notify doesn't return anything but
- scans a system table. */
- command_type == CMD_NOTIFY) {
- return ((Plan*)make_seqscan(NIL,
- NIL,
- root->resultRelation,
- (Plan*)NULL));
- } else
- return((Plan*)NULL);
- }
-
- /*
- * Pull out any non-variable qualifications so these can be put in
- * the topmost result node. The opids for the remaining
- * qualifications will be changed to regprocs later.
- */
- qual = pull_constant_clauses(qual, &constant_qual);
- fix_opids(constant_qual);
-
- /*
- * Create a target list that consists solely of (resdom var) target
- * list entries, i.e., contains no arbitrary expressions.
- */
- flattened_tlist = flatten_tlist(tlist);
- if (flattened_tlist) {
- level_tlist = flattened_tlist;
- } else {
- /* from old code. the logic is beyond me. - ay 2/95 */
- level_tlist = tlist;
- }
-
- /*
- * A query may have a non-variable target list and a non-variable
- * qualification only under certain conditions:
- * - the query creates all-new tuples, or
- * - the query is a replace (a scan must still be done in this case).
- */
- if (flattened_tlist==NULL && qual==NULL) {
-
- switch (command_type) {
- case CMD_SELECT:
- case CMD_INSERT:
- return ((Plan*)make_result(tlist,
- (Node*)constant_qual,
- (Plan*)NULL));
- break;
-
- case CMD_DELETE:
- case CMD_UPDATE:
- {
- SeqScan *scan = make_seqscan(tlist,
- (List *)NULL,
- root->resultRelation,
- (Plan*)NULL);
- if (constant_qual!=NULL) {
- return ((Plan*)make_result(tlist,
- (Node*)constant_qual,
- (Plan*)scan));
- } else {
- return ((Plan*)scan);
- }
- }
- break;
-
- default:
- return ((Plan*)NULL);
+ List *constant_qual = NIL;
+ List *flattened_tlist = NIL;
+ List *level_tlist = NIL;
+ Plan *subplan = (Plan *) NULL;
+ Agg *aggplan = NULL;
+
+ /*
+ * A command without a target list or qualification is an error,
+ * except for "delete foo".
+ */
+ if (tlist == NIL && qual == NULL)
+ {
+ if (command_type == CMD_DELETE ||
+
+ /*
+ * Total hack here. I don't know how to handle statements like
+ * notify in action bodies. Notify doesn't return anything but
+ * scans a system table.
+ */
+ command_type == CMD_NOTIFY)
+ {
+ return ((Plan *) make_seqscan(NIL,
+ NIL,
+ root->resultRelation,
+ (Plan *) NULL));
+ }
+ else
+ return ((Plan *) NULL);
+ }
+
+ /*
+ * Pull out any non-variable qualifications so these can be put in the
+ * topmost result node. The opids for the remaining qualifications
+ * will be changed to regprocs later.
+ */
+ qual = pull_constant_clauses(qual, &constant_qual);
+ fix_opids(constant_qual);
+
+ /*
+ * Create a target list that consists solely of (resdom var) target
+ * list entries, i.e., contains no arbitrary expressions.
+ */
+ flattened_tlist = flatten_tlist(tlist);
+ if (flattened_tlist)
+ {
+ level_tlist = flattened_tlist;
+ }
+ else
+ {
+ /* from old code. the logic is beyond me. - ay 2/95 */
+ level_tlist = tlist;
}
- }
-
- /*
- * Find the subplan (access path) and destructively modify the
- * target list of the newly created subplan to contain the appropriate
- * join references.
- */
- subplan = subplanner(root, level_tlist, qual);
-
- set_tlist_references(subplan);
-
- /*
- * If we have a GROUP BY clause, insert a group node (with the appropriate
- * sort node.)
- */
- if (root->groupClause != NULL) {
- bool tuplePerGroup;
/*
- * decide whether how many tuples per group the Group node needs
- * to return. (Needs only one tuple per group if no aggregate is
- * present. Otherwise, need every tuple from the group to do the
- * aggregation.)
+ * A query may have a non-variable target list and a non-variable
+ * qualification only under certain conditions: - the query creates
+ * all-new tuples, or - the query is a replace (a scan must still be
+ * done in this case).
*/
- tuplePerGroup = ( root->qry_aggs ) ? TRUE : FALSE;
-
- subplan =
- make_groupPlan(&tlist, tuplePerGroup, root->groupClause, subplan);
-
- }
-
- /*
- * If aggregate is present, insert the agg node
- */
- if ( root->qry_aggs )
- {
- aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs);
- aggplan->plan.lefttree = subplan;
+ if (flattened_tlist == NULL && qual == NULL)
+ {
+
+ switch (command_type)
+ {
+ case CMD_SELECT:
+ case CMD_INSERT:
+ return ((Plan *) make_result(tlist,
+ (Node *) constant_qual,
+ (Plan *) NULL));
+ break;
+
+ case CMD_DELETE:
+ case CMD_UPDATE:
+ {
+ SeqScan *scan = make_seqscan(tlist,
+ (List *) NULL,
+ root->resultRelation,
+ (Plan *) NULL);
+
+ if (constant_qual != NULL)
+ {
+ return ((Plan *) make_result(tlist,
+ (Node *) constant_qual,
+ (Plan *) scan));
+ }
+ else
+ {
+ return ((Plan *) scan);
+ }
+ }
+ break;
+
+ default:
+ return ((Plan *) NULL);
+ }
+ }
+
/*
- * set the varno/attno entries to the appropriate references to
- * the result tuple of the subplans. (We need to set those in the
- * array of aggreg's in the Agg node also. Even though they're
- * pointers, after a few dozen's of copying, they're not the same as
- * those in the target list.)
+ * Find the subplan (access path) and destructively modify the target
+ * list of the newly created subplan to contain the appropriate join
+ * references.
*/
- set_agg_tlist_references (aggplan);
- set_agg_agglist_references (aggplan);
-
- subplan = (Plan*)aggplan;
-
- tlist = aggplan->plan.targetlist;
- }
-
- /*
- * Build a result node linking the plan if we have constant quals
- */
- if (constant_qual) {
- Plan *plan;
-
- plan = (Plan*)make_result(tlist,
- (Node*)constant_qual,
- subplan);
+ subplan = subplanner(root, level_tlist, qual);
+
+ set_tlist_references(subplan);
+
/*
- * Change all varno's of the Result's node target list.
+ * If we have a GROUP BY clause, insert a group node (with the
+ * appropriate sort node.)
*/
- set_result_tlist_references((Result*)plan);
-
- return (plan);
- }
-
- /*
- * fix up the flattened target list of the plan root node so that
- * expressions are evaluated. this forces expression evaluations
- * that may involve expensive function calls to be delayed to
- * the very last stage of query execution. this could be bad.
- * but it is joey's responsibility to optimally push these
- * expressions down the plan tree. -- Wei
- *
- * But now nothing to do if there are GroupBy and/or Aggregates:
- * 1. make_groupPlan fixes tlist; 2. flatten_tlist_vars does nothing
- * with aggregates fixing only other entries (i.e. - GroupBy-ed and
- * so fixed by make_groupPlan). - vadim 04/05/97
- */
- if ( root->groupClause == NULL && aggplan == NULL )
- {
- subplan->targetlist = flatten_tlist_vars(tlist,
- subplan->targetlist);
- }
-
- /*
- * Destructively modify the query plan's targetlist to add fjoin
- * lists to flatten functions that return sets of base types
- */
- subplan->targetlist = generate_fjoin(subplan->targetlist);
-
- return (subplan);
+ if (root->groupClause != NULL)
+ {
+ bool tuplePerGroup;
+
+ /*
+ * decide whether how many tuples per group the Group node needs
+ * to return. (Needs only one tuple per group if no aggregate is
+ * present. Otherwise, need every tuple from the group to do the
+ * aggregation.)
+ */
+ tuplePerGroup = (root->qry_aggs) ? TRUE : FALSE;
+
+ subplan =
+ make_groupPlan(&tlist, tuplePerGroup, root->groupClause, subplan);
+
+ }
+
+ /*
+ * If aggregate is present, insert the agg node
+ */
+ if (root->qry_aggs)
+ {
+ aggplan = make_agg(tlist, root->qry_numAgg, root->qry_aggs);
+ aggplan->plan.lefttree = subplan;
+
+ /*
+ * set the varno/attno entries to the appropriate references to
+ * the result tuple of the subplans. (We need to set those in the
+ * array of aggreg's in the Agg node also. Even though they're
+ * pointers, after a few dozen's of copying, they're not the same
+ * as those in the target list.)
+ */
+ set_agg_tlist_references(aggplan);
+ set_agg_agglist_references(aggplan);
+
+ subplan = (Plan *) aggplan;
+
+ tlist = aggplan->plan.targetlist;
+ }
+
+ /*
+ * Build a result node linking the plan if we have constant quals
+ */
+ if (constant_qual)
+ {
+ Plan *plan;
+
+ plan = (Plan *) make_result(tlist,
+ (Node *) constant_qual,
+ subplan);
+
+ /*
+ * Change all varno's of the Result's node target list.
+ */
+ set_result_tlist_references((Result *) plan);
+
+ return (plan);
+ }
+
+ /*
+ * fix up the flattened target list of the plan root node so that
+ * expressions are evaluated. this forces expression evaluations that
+ * may involve expensive function calls to be delayed to the very last
+ * stage of query execution. this could be bad. but it is joey's
+ * responsibility to optimally push these expressions down the plan
+ * tree. -- Wei
+ *
+ * But now nothing to do if there are GroupBy and/or Aggregates: 1.
+ * make_groupPlan fixes tlist; 2. flatten_tlist_vars does nothing with
+ * aggregates fixing only other entries (i.e. - GroupBy-ed and so
+ * fixed by make_groupPlan). - vadim 04/05/97
+ */
+ if (root->groupClause == NULL && aggplan == NULL)
+ {
+ subplan->targetlist = flatten_tlist_vars(tlist,
+ subplan->targetlist);
+ }
+
+ /*
+ * Destructively modify the query plan's targetlist to add fjoin lists
+ * to flatten functions that return sets of base types
+ */
+ subplan->targetlist = generate_fjoin(subplan->targetlist);
+
+ return (subplan);
}
-/*
+/*
* subplanner
- *
- * Subplanner creates an entire plan consisting of joins and scans
- * for processing a single level of attributes.
- *
- * flat-tlist is the flattened target list
- * qual is the qualification to be satisfied
- *
- * Returns a subplan.
- *
+ *
+ * Subplanner creates an entire plan consisting of joins and scans
+ * for processing a single level of attributes.
+ *
+ * flat-tlist is the flattened target list
+ * qual is the qualification to be satisfied
+ *
+ * Returns a subplan.
+ *
*/
-static Plan *
-subplanner(Query *root,
- List *flat_tlist,
- List *qual)
+static Plan *
+subplanner(Query * root,
+ List * flat_tlist,
+ List * qual)
{
- Rel *final_relation;
- List *final_relation_list;
-
- /* Initialize the targetlist and qualification, adding entries to
- * *query-relation-list* as relation references are found (e.g., in the
- * qualification, the targetlist, etc.)
- */
- root->base_relation_list_ = NIL;
- root->join_relation_list_ = NIL;
- initialize_base_rels_list(root, flat_tlist);
- initialize_base_rels_jinfo(root, qual);
- add_missing_vars_to_base_rels(root, flat_tlist);
-
- /* Find all possible scan and join paths.
- * Mark all the clauses and relations that can be processed using special
- * join methods, then do the exhaustive path search.
- */
- initialize_join_clause_info(root->base_relation_list_);
- final_relation_list = find_paths(root,
- root->base_relation_list_);
-
- if (final_relation_list)
- final_relation = (Rel*)lfirst (final_relation_list);
- else
- final_relation = (Rel*)NIL;
-
-#if 0 /* fix xfunc */
- /*
- * Perform Predicate Migration on each path, to optimize and correctly
- * assess the cost of each before choosing the cheapest one.
- * -- JMH, 11/16/92
- *
- * Needn't do so if the top rel is pruneable: that means there's no
- * expensive functions left to pull up. -- JMH, 11/22/92
- */
- if (XfuncMode != XFUNC_OFF && XfuncMode != XFUNC_NOPM &&
- XfuncMode != XFUNC_NOPULL && !final_relation->pruneable)
+ Rel *final_relation;
+ List *final_relation_list;
+
+ /*
+ * Initialize the targetlist and qualification, adding entries to
+ * *query-relation-list* as relation references are found (e.g., in
+ * the qualification, the targetlist, etc.)
+ */
+ root->base_relation_list_ = NIL;
+ root->join_relation_list_ = NIL;
+ initialize_base_rels_list(root, flat_tlist);
+ initialize_base_rels_jinfo(root, qual);
+ add_missing_vars_to_base_rels(root, flat_tlist);
+
+ /*
+ * Find all possible scan and join paths. Mark all the clauses and
+ * relations that can be processed using special join methods, then do
+ * the exhaustive path search.
+ */
+ initialize_join_clause_info(root->base_relation_list_);
+ final_relation_list = find_paths(root,
+ root->base_relation_list_);
+
+ if (final_relation_list)
+ final_relation = (Rel *) lfirst(final_relation_list);
+ else
+ final_relation = (Rel *) NIL;
+
+#if 0 /* fix xfunc */
+
+ /*
+ * Perform Predicate Migration on each path, to optimize and correctly
+ * assess the cost of each before choosing the cheapest one. -- JMH,
+ * 11/16/92
+ *
+ * Needn't do so if the top rel is pruneable: that means there's no
+ * expensive functions left to pull up. -- JMH, 11/22/92
+ */
+ if (XfuncMode != XFUNC_OFF && XfuncMode != XFUNC_NOPM &&
+ XfuncMode != XFUNC_NOPULL && !final_relation->pruneable)
{
- List *pathnode;
- foreach(pathnode, final_relation->pathlist)
+ List *pathnode;
+
+ foreach(pathnode, final_relation->pathlist)
{
- if (xfunc_do_predmig((Path*)lfirst(pathnode)))
- set_cheapest(final_relation, final_relation->pathlist);
+ if (xfunc_do_predmig((Path *) lfirst(pathnode)))
+ set_cheapest(final_relation, final_relation->pathlist);
}
}
#endif
-
- /*
- * Determine the cheapest path and create a subplan corresponding to it.
- */
- if (final_relation) {
- return (create_plan ((Path*)final_relation->cheapestpath));
- }else {
- elog(NOTICE, "final relation is nil");
- return(create_plan ((Path*)NULL));
- }
-
+
+ /*
+ * Determine the cheapest path and create a subplan corresponding to
+ * it.
+ */
+ if (final_relation)
+ {
+ return (create_plan((Path *) final_relation->cheapestpath));
+ }
+ else
+ {
+ elog(NOTICE, "final relation is nil");
+ return (create_plan((Path *) NULL));
+ }
+
}
/*****************************************************************************
*
*****************************************************************************/
-static Result *
-make_result(List *tlist,
- Node *resconstantqual,
- Plan *subplan)
+static Result *
+make_result(List * tlist,
+ Node * resconstantqual,
+ Plan * subplan)
{
- Result *node = makeNode(Result);
- Plan *plan = &node->plan;
-
- tlist = generate_fjoin(tlist);
- plan->cost = 0.0;
- plan->state = (EState *)NULL;
- plan->targetlist = tlist;
- plan->lefttree = subplan;
- plan->righttree = NULL;
- node->resconstantqual = resconstantqual;
- node->resstate = NULL;
-
- return(node);
-}
+ Result *node = makeNode(Result);
+ Plan *plan = &node->plan;
+
+ tlist = generate_fjoin(tlist);
+ plan->cost = 0.0;
+ plan->state = (EState *) NULL;
+ plan->targetlist = tlist;
+ plan->lefttree = subplan;
+ plan->righttree = NULL;
+ node->resconstantqual = resconstantqual;
+ node->resstate = NULL;
+
+ return (node);
+}
/*****************************************************************************
*
*****************************************************************************/
-static Plan *
-make_groupPlan(List **tlist,
- bool tuplePerGroup,
- List *groupClause,
- Plan *subplan)
+static Plan *
+make_groupPlan(List ** tlist,
+ bool tuplePerGroup,
+ List * groupClause,
+ Plan * subplan)
{
- List *sort_tlist;
- List *sl, *gl;
- List *glc = listCopy (groupClause);
- List *otles = NIL; /* list of removed non-GroupBy entries */
- List *otlvars = NIL; /* list of var in them */
- int otlvcnt;
- Sort *sortplan;
- Group *grpplan;
- int numCols;
- AttrNumber *grpColIdx;
- int keyno = 1;
- int last_resno = 1;
-
- numCols = length(groupClause);
- grpColIdx = (AttrNumber *)palloc(sizeof(AttrNumber)*numCols);
-
- sort_tlist = new_unsorted_tlist(*tlist); /* it's copy */
-
- /*
- * Make template TL for subplan, Sort & Group:
- * 1. If there are aggregates (tuplePerGroup is true) then take
- * away non-GroupBy entries and re-set resno-s accordantly.
- * 2. Make grpColIdx
- *
- * Note: we assume that TLEs in *tlist are ordered in accordance
- * with their resdom->resno.
- */
- foreach (sl, sort_tlist)
- {
- Resdom *resdom = NULL;
- TargetEntry *te = (TargetEntry *) lfirst (sl);
-
- foreach (gl, glc)
- {
- GroupClause *grpcl = (GroupClause*)lfirst(gl);
-
- if ( grpcl->entry->resdom->resno == te->resdom->resno )
- {
-
- resdom = te->resdom;
- resdom->reskey = keyno;
- resdom->reskeyop = get_opcode (grpcl->grpOpoid);
- resdom->resno = last_resno; /* re-set */
- grpColIdx[keyno-1] = last_resno++;
- keyno++;
- glc = lremove (lfirst (gl), glc); /* TLE found for it */
- break;
- }
- }
- /*
- * Non-GroupBy entry: remove it from Group/Sort TL if there are
- * aggregates in query - it will be evaluated by Aggregate plan
+ List *sort_tlist;
+ List *sl,
+ *gl;
+ List *glc = listCopy(groupClause);
+ List *otles = NIL;/* list of removed non-GroupBy entries */
+ List *otlvars = NIL; /* list of var in them */
+ int otlvcnt;
+ Sort *sortplan;
+ Group *grpplan;
+ int numCols;
+ AttrNumber *grpColIdx;
+ int keyno = 1;
+ int last_resno = 1;
+
+ numCols = length(groupClause);
+ grpColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
+
+ sort_tlist = new_unsorted_tlist(*tlist); /* it's copy */
+
+ /*
+ * Make template TL for subplan, Sort & Group: 1. If there are
+ * aggregates (tuplePerGroup is true) then take away non-GroupBy
+ * entries and re-set resno-s accordantly. 2. Make grpColIdx
+ *
+ * Note: we assume that TLEs in *tlist are ordered in accordance with
+ * their resdom->resno.
*/
- if ( resdom == NULL )
+ foreach(sl, sort_tlist)
{
- if ( tuplePerGroup )
- {
- otlvars = nconc (otlvars, pull_var_clause (te->expr));
- otles = lcons (te, otles);
- sort_tlist = lremove (te, sort_tlist);
- }
- else
- te->resdom->resno = last_resno++;
+ Resdom *resdom = NULL;
+ TargetEntry *te = (TargetEntry *) lfirst(sl);
+
+ foreach(gl, glc)
+ {
+ GroupClause *grpcl = (GroupClause *) lfirst(gl);
+
+ if (grpcl->entry->resdom->resno == te->resdom->resno)
+ {
+
+ resdom = te->resdom;
+ resdom->reskey = keyno;
+ resdom->reskeyop = get_opcode(grpcl->grpOpoid);
+ resdom->resno = last_resno; /* re-set */
+ grpColIdx[keyno - 1] = last_resno++;
+ keyno++;
+ glc = lremove(lfirst(gl), glc); /* TLE found for it */
+ break;
+ }
+ }
+
+ /*
+ * Non-GroupBy entry: remove it from Group/Sort TL if there are
+ * aggregates in query - it will be evaluated by Aggregate plan
+ */
+ if (resdom == NULL)
+ {
+ if (tuplePerGroup)
+ {
+ otlvars = nconc(otlvars, pull_var_clause(te->expr));
+ otles = lcons(te, otles);
+ sort_tlist = lremove(te, sort_tlist);
+ }
+ else
+ te->resdom->resno = last_resno++;
+ }
}
- }
-
- if ( length (glc) != 0 )
- {
- elog(WARN, "group attribute disappeared from target list");
- }
-
- /*
- * If non-GroupBy entries were removed from TL - we are to add Vars for
- * them to the end of TL if there are no such Vars in TL already.
- */
-
- otlvcnt = length (otlvars);
- foreach (gl, otlvars)
- {
- Var *v = (Var*)lfirst (gl);
-
- if ( tlist_member (v, sort_tlist) == NULL )
+
+ if (length(glc) != 0)
{
- sort_tlist = lappend (sort_tlist,
- create_tl_element (v, last_resno));
- last_resno++;
+ elog(WARN, "group attribute disappeared from target list");
}
- else /* already in TL */
- otlvcnt--;
- }
- /* Now otlvcnt is number of Vars added in TL for non-GroupBy entries */
-
- /* Make TL for subplan: substitute Vars from subplan TL into new TL */
- sl = flatten_tlist_vars (sort_tlist, subplan->targetlist);
-
- subplan->targetlist = new_unsorted_tlist (sl); /* there */
-
- /*
- * Make Sort/Group TL :
- * 1. make Var nodes (with varno = 1 and varnoold = -1) for all
- * functions, 'couse they will be evaluated by subplan;
- * 2. for real Vars: set varno = 1 and varattno to its resno in subplan
- */
- foreach (sl, sort_tlist)
- {
- TargetEntry *te = (TargetEntry *) lfirst (sl);
- Resdom *resdom = te->resdom;
- Node *expr = te->expr;
-
- if ( IsA (expr, Var) )
- {
-#if 0 /* subplanVar->resdom->resno expected to be = te->resdom->resno */
- TargetEntry *subplanVar;
-
- subplanVar = match_varid ((Var*)expr, subplan->targetlist);
- ((Var*)expr)->varattno = subplanVar->resdom->resno;
+
+ /*
+ * If non-GroupBy entries were removed from TL - we are to add Vars
+ * for them to the end of TL if there are no such Vars in TL already.
+ */
+
+ otlvcnt = length(otlvars);
+ foreach(gl, otlvars)
+ {
+ Var *v = (Var *) lfirst(gl);
+
+ if (tlist_member(v, sort_tlist) == NULL)
+ {
+ sort_tlist = lappend(sort_tlist,
+ create_tl_element(v, last_resno));
+ last_resno++;
+ }
+ else
+/* already in TL */
+ otlvcnt--;
+ }
+ /* Now otlvcnt is number of Vars added in TL for non-GroupBy entries */
+
+ /* Make TL for subplan: substitute Vars from subplan TL into new TL */
+ sl = flatten_tlist_vars(sort_tlist, subplan->targetlist);
+
+ subplan->targetlist = new_unsorted_tlist(sl); /* there */
+
+ /*
+ * Make Sort/Group TL : 1. make Var nodes (with varno = 1 and varnoold
+ * = -1) for all functions, 'couse they will be evaluated by subplan;
+ * 2. for real Vars: set varno = 1 and varattno to its resno in
+ * subplan
+ */
+ foreach(sl, sort_tlist)
+ {
+ TargetEntry *te = (TargetEntry *) lfirst(sl);
+ Resdom *resdom = te->resdom;
+ Node *expr = te->expr;
+
+ if (IsA(expr, Var))
+ {
+#if 0 /* subplanVar->resdom->resno expected to
+ * be = te->resdom->resno */
+ TargetEntry *subplanVar;
+
+ subplanVar = match_varid((Var *) expr, subplan->targetlist);
+ ((Var *) expr)->varattno = subplanVar->resdom->resno;
#endif
- ((Var*)expr)->varattno = te->resdom->resno;
- ((Var*)expr)->varno = 1;
- }
- else
- te->expr = (Node*) makeVar (1, resdom->resno,
- resdom->restype,
- -1, resdom->resno);
- }
-
- sortplan = make_sort(sort_tlist,
- _TEMP_RELATION_ID_,
- subplan,
- numCols);
- sortplan->plan.cost = subplan->cost; /* XXX assume no cost */
-
- /*
- * make the Group node
- */
- sort_tlist = copyObject (sort_tlist);
- grpplan = make_group(sort_tlist, tuplePerGroup, numCols,
- grpColIdx, sortplan);
-
- /*
- * Make TL for parent: "restore" non-GroupBy entries (if they
- * were removed) and set resno-s of others accordantly.
- */
- sl = sort_tlist;
- sort_tlist = NIL; /* to be new parent TL */
- foreach (gl, *tlist)
- {
- List *temp = NIL;
- TargetEntry *te = (TargetEntry *) lfirst (gl);
-
- foreach (temp, otles) /* Is it removed non-GroupBy entry ? */
- {
- TargetEntry *ote = (TargetEntry *) lfirst (temp);
-
- if ( ote->resdom->resno == te->resdom->resno )
- {
- otles = lremove (ote, otles);
- break;
- }
- }
- if ( temp == NIL ) /* It's "our" TLE - we're to return */
- { /* it from Sort/Group plans */
- TargetEntry *my = (TargetEntry *) lfirst (sl); /* get it */
-
- sl = sl->next; /* prepare for the next "our" */
- my = copyObject (my);
- my->resdom->resno = te->resdom->resno; /* order of parent TL */
- sort_tlist = lappend (sort_tlist, my);
- continue;
+ ((Var *) expr)->varattno = te->resdom->resno;
+ ((Var *) expr)->varno = 1;
+ }
+ else
+ te->expr = (Node *) makeVar(1, resdom->resno,
+ resdom->restype,
+ -1, resdom->resno);
}
- /* else - it's TLE of an non-GroupBy entry */
- sort_tlist = lappend (sort_tlist, copyObject(te));
- }
- /*
- * Pure non-GroupBy entries Vars were at the end of Group' TL.
- * They shouldn't appear in parent TL, all others shouldn't
- * disappear.
- */
- Assert ( otlvcnt == length (sl) );
- Assert ( length (otles) == 0 );
-
- *tlist = sort_tlist;
-
- return (Plan*)grpplan;
+
+ sortplan = make_sort(sort_tlist,
+ _TEMP_RELATION_ID_,
+ subplan,
+ numCols);
+ sortplan->plan.cost = subplan->cost; /* XXX assume no cost */
+
+ /*
+ * make the Group node
+ */
+ sort_tlist = copyObject(sort_tlist);
+ grpplan = make_group(sort_tlist, tuplePerGroup, numCols,
+ grpColIdx, sortplan);
+
+ /*
+ * Make TL for parent: "restore" non-GroupBy entries (if they were
+ * removed) and set resno-s of others accordantly.
+ */
+ sl = sort_tlist;
+ sort_tlist = NIL; /* to be new parent TL */
+ foreach(gl, *tlist)
+ {
+ List *temp = NIL;
+ TargetEntry *te = (TargetEntry *) lfirst(gl);
+
+ foreach(temp, otles) /* Is it removed non-GroupBy entry ? */
+ {
+ TargetEntry *ote = (TargetEntry *) lfirst(temp);
+
+ if (ote->resdom->resno == te->resdom->resno)
+ {
+ otles = lremove(ote, otles);
+ break;
+ }
+ }
+ if (temp == NIL) /* It's "our" TLE - we're to return */
+ { /* it from Sort/Group plans */
+ TargetEntry *my = (TargetEntry *) lfirst(sl); /* get it */
+
+ sl = sl->next; /* prepare for the next "our" */
+ my = copyObject(my);
+ my->resdom->resno = te->resdom->resno; /* order of parent TL */
+ sort_tlist = lappend(sort_tlist, my);
+ continue;
+ }
+ /* else - it's TLE of an non-GroupBy entry */
+ sort_tlist = lappend(sort_tlist, copyObject(te));
+ }
+
+ /*
+ * Pure non-GroupBy entries Vars were at the end of Group' TL. They
+ * shouldn't appear in parent TL, all others shouldn't disappear.
+ */
+ Assert(otlvcnt == length(sl));
+ Assert(length(otles) == 0);
+
+ *tlist = sort_tlist;
+
+ return (Plan *) grpplan;
}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 5a6b78384b6..43441a3b7ff 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* planner.c--
- * The query optimizer external interface.
+ * The query optimizer external interface.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.6 1997/09/05 20:20:48 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.7 1997/09/07 04:44:03 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,7 +28,7 @@
#include "optimizer/internal.h"
#include "optimizer/planner.h"
-#include "optimizer/plancat.h"
+#include "optimizer/plancat.h"
#include "optimizer/prep.h"
#include "optimizer/planmain.h"
#include "optimizer/paths.h"
@@ -47,215 +47,225 @@
#include "executor/executor.h"
-static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode);
-static Plan *init_query_planner(Query *parse);
-static Existential *make_existential(Plan *left, Plan *right);
+static Plan *make_sortplan(List * tlist, List * sortcls, Plan * plannode);
+static Plan *init_query_planner(Query * parse);
+static Existential *make_existential(Plan * left, Plan * right);
/*****************************************************************************
*
- * Query optimizer entry point
- *
+ * Query optimizer entry point
+ *
*****************************************************************************/
-/*
+/*
* planner--
- * Main query optimizer routine.
- *
- * Invokes the planner on union queries if there are any left,
- * recursing if necessary to get them all, then processes normal plans.
- *
+ * Main query optimizer routine.
+ *
+ * Invokes the planner on union queries if there are any left,
+ * recursing if necessary to get them all, then processes normal plans.
+ *
* Returns a query plan.
- *
+ *
*/
-Plan*
-planner(Query *parse)
+Plan *
+planner(Query * parse)
{
- List *tlist = parse->targetList;
- List *rangetable = parse->rtable;
- char* uniqueflag = parse->uniqueFlag;
- List *sortclause = parse->sortClause;
- Plan *special_plans = (Plan*)NULL;
-
- Plan *result_plan = (Plan*) NULL;
-
- int rt_index;
-
- /*
- * plan inheritance
- */
- rt_index = first_matching_rt_entry(rangetable, INHERITS_FLAG);
- if (rt_index != -1) {
- special_plans = (Plan *)plan_union_queries((Index)rt_index,
- parse,
- INHERITS_FLAG);
- }
-
- /*
- * plan archive queries
- */
- rt_index = first_matching_rt_entry(rangetable, ARCHIVE_FLAG);
- if (rt_index != -1) {
- special_plans = (Plan *)plan_union_queries((Index)rt_index,
- parse,
- ARCHIVE_FLAG);
- }
-
- if (special_plans)
- result_plan = special_plans;
- else
- result_plan = init_query_planner(parse); /* regular plans */
-
- /*
- * For now, before we hand back the plan, check to see if there
- * is a user-specified sort that needs to be done. Eventually, this
- * will be moved into the guts of the planner s.t. user specified
- * sorts will be considered as part of the planning process.
- * Since we can only make use of user-specified sorts in
- * special cases, we can do the optimization step later.
- */
-
- if (uniqueflag) {
- Plan *sortplan = make_sortplan(tlist, sortclause, result_plan);
-
- return((Plan*)make_unique(tlist,sortplan,uniqueflag));
- } else {
- if (sortclause)
- return(make_sortplan(tlist,sortclause,result_plan));
- else
- return((Plan*)result_plan);
- }
+ List *tlist = parse->targetList;
+ List *rangetable = parse->rtable;
+ char *uniqueflag = parse->uniqueFlag;
+ List *sortclause = parse->sortClause;
+ Plan *special_plans = (Plan *) NULL;
+
+ Plan *result_plan = (Plan *) NULL;
+
+ int rt_index;
+
+ /*
+ * plan inheritance
+ */
+ rt_index = first_matching_rt_entry(rangetable, INHERITS_FLAG);
+ if (rt_index != -1)
+ {
+ special_plans = (Plan *) plan_union_queries((Index) rt_index,
+ parse,
+ INHERITS_FLAG);
+ }
+
+ /*
+ * plan archive queries
+ */
+ rt_index = first_matching_rt_entry(rangetable, ARCHIVE_FLAG);
+ if (rt_index != -1)
+ {
+ special_plans = (Plan *) plan_union_queries((Index) rt_index,
+ parse,
+ ARCHIVE_FLAG);
+ }
+
+ if (special_plans)
+ result_plan = special_plans;
+ else
+ result_plan = init_query_planner(parse); /* regular plans */
+
+ /*
+ * For now, before we hand back the plan, check to see if there is a
+ * user-specified sort that needs to be done. Eventually, this will
+ * be moved into the guts of the planner s.t. user specified sorts
+ * will be considered as part of the planning process. Since we can
+ * only make use of user-specified sorts in special cases, we can do
+ * the optimization step later.
+ */
+
+ if (uniqueflag)
+ {
+ Plan *sortplan = make_sortplan(tlist, sortclause, result_plan);
+
+ return ((Plan *) make_unique(tlist, sortplan, uniqueflag));
+ }
+ else
+ {
+ if (sortclause)
+ return (make_sortplan(tlist, sortclause, result_plan));
+ else
+ return ((Plan *) result_plan);
+ }
}
/*
* make_sortplan--
- * Returns a sortplan which is basically a SORT node attached to the
- * top of the plan returned from the planner. It also adds the
- * cost of sorting into the plan.
- *
+ * Returns a sortplan which is basically a SORT node attached to the
+ * top of the plan returned from the planner. It also adds the
+ * cost of sorting into the plan.
+ *
* sortkeys: ( resdom1 resdom2 resdom3 ...)
* sortops: (sortop1 sortop2 sortop3 ...)
*/
-static Plan *
-make_sortplan(List *tlist, List *sortcls, Plan *plannode)
+static Plan *
+make_sortplan(List * tlist, List * sortcls, Plan * plannode)
{
- Plan *sortplan = (Plan*)NULL;
- List *temp_tlist = NIL;
- List *i = NIL;
- Resdom *resnode = (Resdom*)NULL;
- Resdom *resdom = (Resdom*)NULL;
- int keyno =1;
-
- /* First make a copy of the tlist so that we don't corrupt the
- * the original .
- */
-
- temp_tlist = new_unsorted_tlist(tlist);
-
- foreach (i, sortcls) {
- SortClause *sortcl = (SortClause*)lfirst(i);
-
- resnode = sortcl->resdom;
- resdom = tlist_resdom(temp_tlist, resnode);
-
- /* Order the resdom keys and replace the operator OID for each
- * key with the regproc OID.
+ Plan *sortplan = (Plan *) NULL;
+ List *temp_tlist = NIL;
+ List *i = NIL;
+ Resdom *resnode = (Resdom *) NULL;
+ Resdom *resdom = (Resdom *) NULL;
+ int keyno = 1;
+
+ /*
+ * First make a copy of the tlist so that we don't corrupt the the
+ * original .
+ */
+
+ temp_tlist = new_unsorted_tlist(tlist);
+
+ foreach(i, sortcls)
+ {
+ SortClause *sortcl = (SortClause *) lfirst(i);
+
+ resnode = sortcl->resdom;
+ resdom = tlist_resdom(temp_tlist, resnode);
+
+ /*
+ * Order the resdom keys and replace the operator OID for each key
+ * with the regproc OID.
+ */
+ resdom->reskey = keyno;
+ resdom->reskeyop = get_opcode(sortcl->opoid);
+ keyno += 1;
+ }
+
+ sortplan = (Plan *) make_sort(temp_tlist,
+ _TEMP_RELATION_ID_,
+ (Plan *) plannode,
+ length(sortcls));
+
+ /*
+ * XXX Assuming that an internal sort has no. cost. This is wrong, but
+ * given that at this point, we don't know the no. of tuples returned,
+ * etc, we can't do better than to add a constant cost. This will be
+ * fixed once we move the sort further into the planner, but for now
+ * ... functionality....
*/
- resdom->reskey = keyno;
- resdom->reskeyop = get_opcode(sortcl->opoid);
- keyno += 1;
- }
-
- sortplan = (Plan*)make_sort(temp_tlist,
- _TEMP_RELATION_ID_,
- (Plan*)plannode,
- length(sortcls));
-
- /*
- * XXX Assuming that an internal sort has no. cost.
- * This is wrong, but given that at this point, we don't
- * know the no. of tuples returned, etc, we can't do
- * better than to add a constant cost.
- * This will be fixed once we move the sort further into the planner,
- * but for now ... functionality....
- */
-
- sortplan->cost = plannode->cost;
-
- return(sortplan);
+
+ sortplan->cost = plannode->cost;
+
+ return (sortplan);
}
-/*
+/*
* init-query-planner--
- * Deals with all non-union preprocessing, including existential
- * qualifications and CNFifying the qualifications.
- *
+ * Deals with all non-union preprocessing, including existential
+ * qualifications and CNFifying the qualifications.
+ *
* Returns a query plan.
* MODIFIES: tlist,qual
- *
+ *
*/
-static Plan *
-init_query_planner(Query *root)
+static Plan *
+init_query_planner(Query * root)
{
- List *primary_qual;
- List *existential_qual;
- Existential *exist_plan;
- List *tlist = root->targetList;
-
- tlist = preprocess_targetlist(tlist,
- root->commandType,
- root->resultRelation,
- root->rtable);
-
- primary_qual =
- preprocess_qualification((Expr*)root->qual,
- tlist,
- &existential_qual);
-
- if(existential_qual==NULL) {
- return(query_planner(root,
- root->commandType,
- tlist,
- primary_qual));
- } else {
- int temp = root->commandType;
- Plan *existential_plan;
-
- root->commandType = CMD_SELECT;
- existential_plan = query_planner(root,
- temp,
- NIL,
- existential_qual);
-
- exist_plan = make_existential(existential_plan,
- query_planner(root,
- root->commandType,
- tlist,
- primary_qual));
- return((Plan*)exist_plan);
- }
+ List *primary_qual;
+ List *existential_qual;
+ Existential *exist_plan;
+ List *tlist = root->targetList;
+
+ tlist = preprocess_targetlist(tlist,
+ root->commandType,
+ root->resultRelation,
+ root->rtable);
+
+ primary_qual =
+ preprocess_qualification((Expr *) root->qual,
+ tlist,
+ &existential_qual);
+
+ if (existential_qual == NULL)
+ {
+ return (query_planner(root,
+ root->commandType,
+ tlist,
+ primary_qual));
+ }
+ else
+ {
+ int temp = root->commandType;
+ Plan *existential_plan;
+
+ root->commandType = CMD_SELECT;
+ existential_plan = query_planner(root,
+ temp,
+ NIL,
+ existential_qual);
+
+ exist_plan = make_existential(existential_plan,
+ query_planner(root,
+ root->commandType,
+ tlist,
+ primary_qual));
+ return ((Plan *) exist_plan);
+ }
}
-/*
+/*
* make_existential--
- * Instantiates an existential plan node and fills in
- * the left and right subtree slots.
+ * Instantiates an existential plan node and fills in
+ * the left and right subtree slots.
*/
static Existential *
-make_existential(Plan *left, Plan *right)
+make_existential(Plan * left, Plan * right)
{
- Existential *node = makeNode(Existential);
+ Existential *node = makeNode(Existential);
- node->lefttree = left;
- node->righttree = left;
- return(node);
+ node->lefttree = left;
+ node->righttree = left;
+ return (node);
}
/*
* pg_checkretval() -- check return value of a list of sql parse
- * trees.
+ * trees.
*
* The return value of a sql function is the value returned by
* the final query in the function. We do some ad-hoc define-time
@@ -263,145 +273,152 @@ make_existential(Plan *left, Plan *right)
* type he claims.
*/
void
-pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
+pg_checkretval(Oid rettype, QueryTreeList * queryTreeList)
{
- Query *parse;
- List *tlist;
- List *rt;
- int cmd;
- Type typ;
- Resdom *resnode;
- Relation reln;
- Oid relid;
- Oid tletype;
- int relnatts;
- int i;
-
- /* find the final query */
- parse = queryTreeList->qtrees[queryTreeList->len - 1];
-
- /*
- * test 1: if the last query is a utility invocation, then there
- * had better not be a return value declared.
- */
- if (parse->commandType == CMD_UTILITY) {
+ Query *parse;
+ List *tlist;
+ List *rt;
+ int cmd;
+ Type typ;
+ Resdom *resnode;
+ Relation reln;
+ Oid relid;
+ Oid tletype;
+ int relnatts;
+ int i;
+
+ /* find the final query */
+ parse = queryTreeList->qtrees[queryTreeList->len - 1];
+
+ /*
+ * test 1: if the last query is a utility invocation, then there had
+ * better not be a return value declared.
+ */
+ if (parse->commandType == CMD_UTILITY)
+ {
+ if (rettype == InvalidOid)
+ return;
+ else
+ elog(WARN, "return type mismatch in function decl: final query is a catalog utility");
+ }
+
+ /* okay, it's an ordinary query */
+ tlist = parse->targetList;
+ rt = parse->rtable;
+ cmd = parse->commandType;
+
+ /*
+ * test 2: if the function is declared to return no value, then the
+ * final query had better not be a retrieve.
+ */
if (rettype == InvalidOid)
- return;
- else
- elog(WARN, "return type mismatch in function decl: final query is a catalog utility");
- }
-
- /* okay, it's an ordinary query */
- tlist = parse->targetList;
- rt = parse->rtable;
- cmd = parse->commandType;
-
- /*
- * test 2: if the function is declared to return no value, then the
- * final query had better not be a retrieve.
- */
- if (rettype == InvalidOid) {
- if (cmd == CMD_SELECT)
- elog(WARN,
- "function declared with no return type, but final query is a retrieve");
- else
- return;
- }
-
- /* by here, the function is declared to return some type */
- if ((typ = (Type)get_id_type(rettype)) == NULL)
- elog(WARN, "can't find return type %d for function\n", rettype);
-
- /*
- * test 3: if the function is declared to return a value, then the
- * final query had better be a retrieve.
- */
- if (cmd != CMD_SELECT)
- elog(WARN, "function declared to return type %s, but final query is not a retrieve", tname(typ));
-
- /*
- * test 4: for base type returns, the target list should have exactly
- * one entry, and its type should agree with what the user declared.
- */
-
- if (get_typrelid(typ) == InvalidOid) {
- if (exec_tlist_length(tlist) > 1)
- elog(WARN, "function declared to return %s returns multiple values in final retrieve", tname(typ));
-
- resnode = (Resdom*) ((TargetEntry*)lfirst(tlist))->resdom;
- if (resnode->restype != rettype)
- elog(WARN, "return type mismatch in function: declared to return %s, returns %s", tname(typ), tname(get_id_type(resnode->restype)));
-
- /* by here, base return types match */
- return;
- }
-
- /*
- * If the target list is of length 1, and the type of the varnode
- * in the target list is the same as the declared return type, this
- * is okay. This can happen, for example, where the body of the
- * function is 'retrieve (x = func2())', where func2 has the same
- * return type as the function that's calling it.
- */
- if (exec_tlist_length(tlist) == 1) {
- resnode = (Resdom*) ((TargetEntry*)lfirst(tlist))->resdom;
- if (resnode->restype == rettype)
- return;
- }
-
- /*
- * By here, the procedure returns a (set of) tuples. This part of
- * the typechecking is a hack. We look up the relation that is
- * the declared return type, and be sure that attributes 1 .. n
- * in the target list match the declared types.
- */
- reln = heap_open(get_typrelid(typ));
-
- if (!RelationIsValid(reln))
- elog(WARN, "cannot open relation relid %d", get_typrelid(typ));
-
- relid = reln->rd_id;
- relnatts = reln->rd_rel->relnatts;
-
- if (exec_tlist_length(tlist) != relnatts)
- elog(WARN, "function declared to return type %s does not retrieve (%s.*)", tname(typ), tname(typ));
-
- /* expect attributes 1 .. n in order */
- for (i = 1; i <= relnatts; i++) {
- TargetEntry *tle = lfirst(tlist);
- Node *thenode = tle->expr;
-
- tlist = lnext(tlist);
- tletype = exprType(thenode);
-
-#if 0 /* fix me */
- /* this is tedious */
- if (IsA(thenode,Var))
- tletype = (Oid) ((Var*)thenode)->vartype;
- else if (IsA(thenode,Const))
- tletype = (Oid) ((Const*)thenode)->consttype;
- else if (IsA(thenode,Param))
- tletype = (Oid) ((Param*)thenode)->paramtype;
- else if (IsA(thenode,Expr))
- tletype = Expr;
- else if (IsA(thenode,LispList)) {
- thenode = lfirst(thenode);
- if (IsA(thenode,Oper))
- tletype = (Oid) get_opresulttype((Oper*)thenode);
- else if (IsA(thenode,Func))
- tletype = (Oid) get_functype((Func*)thenode);
- else
- elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
- } else
- elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+ {
+ if (cmd == CMD_SELECT)
+ elog(WARN,
+ "function declared with no return type, but final query is a retrieve");
+ else
+ return;
+ }
+
+ /* by here, the function is declared to return some type */
+ if ((typ = (Type) get_id_type(rettype)) == NULL)
+ elog(WARN, "can't find return type %d for function\n", rettype);
+
+ /*
+ * test 3: if the function is declared to return a value, then the
+ * final query had better be a retrieve.
+ */
+ if (cmd != CMD_SELECT)
+ elog(WARN, "function declared to return type %s, but final query is not a retrieve", tname(typ));
+
+ /*
+ * test 4: for base type returns, the target list should have exactly
+ * one entry, and its type should agree with what the user declared.
+ */
+
+ if (get_typrelid(typ) == InvalidOid)
+ {
+ if (exec_tlist_length(tlist) > 1)
+ elog(WARN, "function declared to return %s returns multiple values in final retrieve", tname(typ));
+
+ resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
+ if (resnode->restype != rettype)
+ elog(WARN, "return type mismatch in function: declared to return %s, returns %s", tname(typ), tname(get_id_type(resnode->restype)));
+
+ /* by here, base return types match */
+ return;
+ }
+
+ /*
+ * If the target list is of length 1, and the type of the varnode in
+ * the target list is the same as the declared return type, this is
+ * okay. This can happen, for example, where the body of the function
+ * is 'retrieve (x = func2())', where func2 has the same return type
+ * as the function that's calling it.
+ */
+ if (exec_tlist_length(tlist) == 1)
+ {
+ resnode = (Resdom *) ((TargetEntry *) lfirst(tlist))->resdom;
+ if (resnode->restype == rettype)
+ return;
+ }
+
+ /*
+ * By here, the procedure returns a (set of) tuples. This part of the
+ * typechecking is a hack. We look up the relation that is the
+ * declared return type, and be sure that attributes 1 .. n in the
+ * target list match the declared types.
+ */
+ reln = heap_open(get_typrelid(typ));
+
+ if (!RelationIsValid(reln))
+ elog(WARN, "cannot open relation relid %d", get_typrelid(typ));
+
+ relid = reln->rd_id;
+ relnatts = reln->rd_rel->relnatts;
+
+ if (exec_tlist_length(tlist) != relnatts)
+ elog(WARN, "function declared to return type %s does not retrieve (%s.*)", tname(typ), tname(typ));
+
+ /* expect attributes 1 .. n in order */
+ for (i = 1; i <= relnatts; i++)
+ {
+ TargetEntry *tle = lfirst(tlist);
+ Node *thenode = tle->expr;
+
+ tlist = lnext(tlist);
+ tletype = exprType(thenode);
+
+#if 0 /* fix me */
+ /* this is tedious */
+ if (IsA(thenode, Var))
+ tletype = (Oid) ((Var *) thenode)->vartype;
+ else if (IsA(thenode, Const))
+ tletype = (Oid) ((Const *) thenode)->consttype;
+ else if (IsA(thenode, Param))
+ tletype = (Oid) ((Param *) thenode)->paramtype;
+ else if (IsA(thenode, Expr))
+ tletype = Expr;
+ else if (IsA(thenode, LispList))
+ {
+ thenode = lfirst(thenode);
+ if (IsA(thenode, Oper))
+ tletype = (Oid) get_opresulttype((Oper *) thenode);
+ else if (IsA(thenode, Func))
+ tletype = (Oid) get_functype((Func *) thenode);
+ else
+ elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+ }
+ else
+ elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
#endif
- /* reach right in there, why don't you? */
- if (tletype != reln->rd_att->attrs[i-1]->atttypid)
- elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
- }
+ /* reach right in there, why don't you? */
+ if (tletype != reln->rd_att->attrs[i - 1]->atttypid)
+ elog(WARN, "function declared to return type %s does not retrieve (%s.all)", tname(typ), tname(typ));
+ }
- heap_close(reln);
+ heap_close(reln);
- /* success */
- return;
+ /* success */
+ return;
}
diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c
index 4527837e9d4..19cee246a58 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* setrefs.c--
- * Routines to change varno/attno entries to contain references
+ * Routines to change varno/attno entries to contain references
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.4 1997/06/12 17:26:15 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.5 1997/09/07 04:44:05 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -33,419 +33,468 @@
#include "optimizer/var.h"
#include "optimizer/tlist.h"
-static void set_join_tlist_references(Join *join);
-static void set_tempscan_tlist_references(SeqScan *tempscan);
-static void set_temp_tlist_references(Temp *temp);
-static List *replace_clause_joinvar_refs(Expr *clause,
- List *outer_tlist, List *inner_tlist);
-static List *replace_subclause_joinvar_refs(List *clauses,
- List *outer_tlist, List *inner_tlist);
-static Var *replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist);
-static List *tlist_temp_references(Oid tempid, List *tlist);
-static void replace_result_clause(List *clause, List *subplanTargetList);
-static bool OperandIsInner(Node *opnd, int inner_relid);
-static void replace_agg_clause(Node *expr, List *targetlist);
+static void set_join_tlist_references(Join * join);
+static void set_tempscan_tlist_references(SeqScan * tempscan);
+static void set_temp_tlist_references(Temp * temp);
+static List *
+replace_clause_joinvar_refs(Expr * clause,
+ List * outer_tlist, List * inner_tlist);
+static List *
+replace_subclause_joinvar_refs(List * clauses,
+ List * outer_tlist, List * inner_tlist);
+static Var *replace_joinvar_refs(Var * var, List * outer_tlist, List * inner_tlist);
+static List *tlist_temp_references(Oid tempid, List * tlist);
+static void replace_result_clause(List * clause, List * subplanTargetList);
+static bool OperandIsInner(Node * opnd, int inner_relid);
+static void replace_agg_clause(Node * expr, List * targetlist);
/*****************************************************************************
- *
- * SUBPLAN REFERENCES
- *
+ *
+ * SUBPLAN REFERENCES
+ *
*****************************************************************************/
-/*
+/*
* set-tlist-references--
- * Modifies the target list of nodes in a plan to reference target lists
- * at lower levels.
- *
+ * Modifies the target list of nodes in a plan to reference target lists
+ * at lower levels.
+ *
* 'plan' is the plan whose target list and children's target lists will
- * be modified
- *
+ * be modified
+ *
* Returns nothing of interest, but modifies internal fields of nodes.
- *
+ *
*/
void
-set_tlist_references(Plan *plan)
+set_tlist_references(Plan * plan)
{
- if(plan==NULL)
- return;
-
- if (IsA_Join(plan)) {
- set_join_tlist_references((Join*)plan);
- } else if (IsA(plan,SeqScan) && plan->lefttree &&
- IsA_Temp(plan->lefttree)) {
- set_tempscan_tlist_references((SeqScan*)plan);
- } else if (IsA(plan,Sort)) {
- set_temp_tlist_references ((Temp*)plan);
- } else if (IsA(plan,Result)) {
- set_result_tlist_references((Result*)plan);
- } else if (IsA(plan,Hash)) {
- set_tlist_references(plan->lefttree);
- } else if (IsA(plan,Choose)) {
- List *x;
- foreach (x, ((Choose*)plan)->chooseplanlist) {
- set_tlist_references((Plan*)lfirst(x));
- }
- }
+ if (plan == NULL)
+ return;
+
+ if (IsA_Join(plan))
+ {
+ set_join_tlist_references((Join *) plan);
+ }
+ else if (IsA(plan, SeqScan) && plan->lefttree &&
+ IsA_Temp(plan->lefttree))
+ {
+ set_tempscan_tlist_references((SeqScan *) plan);
+ }
+ else if (IsA(plan, Sort))
+ {
+ set_temp_tlist_references((Temp *) plan);
+ }
+ else if (IsA(plan, Result))
+ {
+ set_result_tlist_references((Result *) plan);
+ }
+ else if (IsA(plan, Hash))
+ {
+ set_tlist_references(plan->lefttree);
+ }
+ else if (IsA(plan, Choose))
+ {
+ List *x;
+
+ foreach(x, ((Choose *) plan)->chooseplanlist)
+ {
+ set_tlist_references((Plan *) lfirst(x));
+ }
+ }
}
-/*
+/*
* set-join-tlist-references--
- * Modifies the target list of a join node by setting the varnos and
- * varattnos to reference the target list of the outer and inner join
- * relations.
- *
- * Creates a target list for a join node to contain references by setting
- * varno values to OUTER or INNER and setting attno values to the
- * result domain number of either the corresponding outer or inner join
- * tuple.
- *
+ * Modifies the target list of a join node by setting the varnos and
+ * varattnos to reference the target list of the outer and inner join
+ * relations.
+ *
+ * Creates a target list for a join node to contain references by setting
+ * varno values to OUTER or INNER and setting attno values to the
+ * result domain number of either the corresponding outer or inner join
+ * tuple.
+ *
* 'join' is a join plan node
- *
+ *
* Returns nothing of interest, but modifies internal fields of nodes.
- *
+ *
*/
static void
-set_join_tlist_references(Join *join)
+set_join_tlist_references(Join * join)
{
- Plan *outer = ((Plan*)join)->lefttree;
- Plan *inner = ((Plan*)join)->righttree;
- List *new_join_targetlist = NIL;
- TargetEntry *temp = (TargetEntry *)NULL;
- List *entry = NIL;
- List *inner_tlist = NULL;
- List *outer_tlist = NULL;
- TargetEntry *xtl = (TargetEntry *)NULL;
- List *qptlist = ((Plan*)join)->targetlist;
-
- foreach(entry, qptlist) {
- List *joinvar;
-
- xtl = (TargetEntry *)lfirst(entry);
- inner_tlist = ((inner==NULL) ? NIL : inner->targetlist);
- outer_tlist = ((outer==NULL) ? NIL : outer->targetlist);
- joinvar = replace_clause_joinvar_refs((Expr*)get_expr(xtl),
- outer_tlist,
- inner_tlist);
-
- temp = MakeTLE(xtl->resdom, (Node*)joinvar);
- new_join_targetlist = lappend(new_join_targetlist,temp);
- }
-
- ((Plan*)join)->targetlist = new_join_targetlist;
- if (outer!=NULL)
- set_tlist_references(outer);
- if (inner!=NULL)
- set_tlist_references(inner);
+ Plan *outer = ((Plan *) join)->lefttree;
+ Plan *inner = ((Plan *) join)->righttree;
+ List *new_join_targetlist = NIL;
+ TargetEntry *temp = (TargetEntry *) NULL;
+ List *entry = NIL;
+ List *inner_tlist = NULL;
+ List *outer_tlist = NULL;
+ TargetEntry *xtl = (TargetEntry *) NULL;
+ List *qptlist = ((Plan *) join)->targetlist;
+
+ foreach(entry, qptlist)
+ {
+ List *joinvar;
+
+ xtl = (TargetEntry *) lfirst(entry);
+ inner_tlist = ((inner == NULL) ? NIL : inner->targetlist);
+ outer_tlist = ((outer == NULL) ? NIL : outer->targetlist);
+ joinvar = replace_clause_joinvar_refs((Expr *) get_expr(xtl),
+ outer_tlist,
+ inner_tlist);
+
+ temp = MakeTLE(xtl->resdom, (Node *) joinvar);
+ new_join_targetlist = lappend(new_join_targetlist, temp);
+ }
+
+ ((Plan *) join)->targetlist = new_join_targetlist;
+ if (outer != NULL)
+ set_tlist_references(outer);
+ if (inner != NULL)
+ set_tlist_references(inner);
}
-/*
+/*
* set-tempscan-tlist-references--
- * Modifies the target list of a node that scans a temp relation (i.e., a
- * sort or hash node) so that the varnos refer to the child temporary.
- *
+ * Modifies the target list of a node that scans a temp relation (i.e., a
+ * sort or hash node) so that the varnos refer to the child temporary.
+ *
* 'tempscan' is a seqscan node
- *
+ *
* Returns nothing of interest, but modifies internal fields of nodes.
- *
+ *
*/
static void
-set_tempscan_tlist_references(SeqScan *tempscan)
+set_tempscan_tlist_references(SeqScan * tempscan)
{
- Temp *temp = (Temp*)((Plan*)tempscan)->lefttree;
+ Temp *temp = (Temp *) ((Plan *) tempscan)->lefttree;
- ((Plan*)tempscan)->targetlist =
- tlist_temp_references(temp->tempid,
- ((Plan*)tempscan)->targetlist);
- set_temp_tlist_references(temp);
+ ((Plan *) tempscan)->targetlist =
+ tlist_temp_references(temp->tempid,
+ ((Plan *) tempscan)->targetlist);
+ set_temp_tlist_references(temp);
}
-/*
+/*
* set-temp-tlist-references--
- * The temp's vars are made consistent with (actually, identical to) the
- * modified version of the target list of the node from which temp node
- * receives its tuples.
- *
+ * The temp's vars are made consistent with (actually, identical to) the
+ * modified version of the target list of the node from which temp node
+ * receives its tuples.
+ *
* 'temp' is a temp (e.g., sort, hash) plan node
- *
+ *
* Returns nothing of interest, but modifies internal fields of nodes.
- *
+ *
*/
static void
-set_temp_tlist_references(Temp *temp)
+set_temp_tlist_references(Temp * temp)
{
- Plan *source = ((Plan*)temp)->lefttree;
-
- if (source!=NULL) {
- set_tlist_references(source);
- ((Plan*)temp)->targetlist =
- copy_vars(((Plan*)temp)->targetlist ,
- (source)->targetlist);
- } else {
- elog(WARN, "calling set_temp_tlist_references with empty lefttree");
- }
+ Plan *source = ((Plan *) temp)->lefttree;
+
+ if (source != NULL)
+ {
+ set_tlist_references(source);
+ ((Plan *) temp)->targetlist =
+ copy_vars(((Plan *) temp)->targetlist,
+ (source)->targetlist);
+ }
+ else
+ {
+ elog(WARN, "calling set_temp_tlist_references with empty lefttree");
+ }
}
-/*
+/*
* join-references--
- * Creates a new set of join clauses by replacing the varno/varattno
- * values of variables in the clauses to reference target list values
- * from the outer and inner join relation target lists.
- *
+ * Creates a new set of join clauses by replacing the varno/varattno
+ * values of variables in the clauses to reference target list values
+ * from the outer and inner join relation target lists.
+ *
* 'clauses' is the list of join clauses
* 'outer-tlist' is the target list of the outer join relation
* 'inner-tlist' is the target list of the inner join relation
- *
+ *
* Returns the new join clauses.
- *
+ *
*/
-List *
-join_references(List *clauses,
- List *outer_tlist,
- List *inner_tlist)
+List *
+join_references(List * clauses,
+ List * outer_tlist,
+ List * inner_tlist)
{
- return (replace_subclause_joinvar_refs(clauses,
- outer_tlist,
- inner_tlist));
+ return (replace_subclause_joinvar_refs(clauses,
+ outer_tlist,
+ inner_tlist));
}
-/*
+/*
* index-outerjoin-references--
- * Given a list of join clauses, replace the operand corresponding to the
- * outer relation in the join with references to the corresponding target
- * list element in 'outer-tlist' (the outer is rather obscurely
- * identified as the side that doesn't contain a var whose varno equals
- * 'inner-relid').
- *
- * As a side effect, the operator is replaced by the regproc id.
- *
+ * Given a list of join clauses, replace the operand corresponding to the
+ * outer relation in the join with references to the corresponding target
+ * list element in 'outer-tlist' (the outer is rather obscurely
+ * identified as the side that doesn't contain a var whose varno equals
+ * 'inner-relid').
+ *
+ * As a side effect, the operator is replaced by the regproc id.
+ *
* 'inner-indxqual' is the list of join clauses (so-called because they
* are used as qualifications for the inner (inbex) scan of a nestloop)
- *
+ *
* Returns the new list of clauses.
- *
+ *
*/
-List *
-index_outerjoin_references(List *inner_indxqual,
- List *outer_tlist,
- Index inner_relid)
+List *
+index_outerjoin_references(List * inner_indxqual,
+ List * outer_tlist,
+ Index inner_relid)
{
- List *t_list = NIL;
- Expr *temp = NULL;
- List *t_clause = NIL;
- Expr *clause = NULL;
+ List *t_list = NIL;
+ Expr *temp = NULL;
+ List *t_clause = NIL;
+ Expr *clause = NULL;
- foreach (t_clause,inner_indxqual) {
- clause = lfirst(t_clause);
- /*
- * if inner scan on the right.
- */
- if (OperandIsInner((Node*)get_rightop(clause), inner_relid)) {
- Var *joinvar = (Var*)
- replace_clause_joinvar_refs((Expr*)get_leftop(clause),
- outer_tlist,
- NIL);
- temp = make_opclause(replace_opid((Oper*)((Expr*)clause)->oper),
- joinvar,
- get_rightop(clause));
- t_list = lappend(t_list,temp);
- } else {
- /* inner scan on left */
- Var *joinvar = (Var*)
- replace_clause_joinvar_refs((Expr*)get_rightop(clause),
- outer_tlist,
- NIL);
- temp = make_opclause(replace_opid((Oper*)((Expr*)clause)->oper),
- get_leftop(clause),
- joinvar);
- t_list = lappend(t_list,temp);
- }
-
- }
- return(t_list);
+ foreach(t_clause, inner_indxqual)
+ {
+ clause = lfirst(t_clause);
+
+ /*
+ * if inner scan on the right.
+ */
+ if (OperandIsInner((Node *) get_rightop(clause), inner_relid))
+ {
+ Var *joinvar = (Var *)
+ replace_clause_joinvar_refs((Expr *) get_leftop(clause),
+ outer_tlist,
+ NIL);
+
+ temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
+ joinvar,
+ get_rightop(clause));
+ t_list = lappend(t_list, temp);
+ }
+ else
+ {
+ /* inner scan on left */
+ Var *joinvar = (Var *)
+ replace_clause_joinvar_refs((Expr *) get_rightop(clause),
+ outer_tlist,
+ NIL);
+
+ temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
+ get_leftop(clause),
+ joinvar);
+ t_list = lappend(t_list, temp);
+ }
+
+ }
+ return (t_list);
}
-/*
+/*
* replace-clause-joinvar-refs
* replace-subclause-joinvar-refs
* replace-joinvar-refs
- *
- * Replaces all variables within a join clause with a new var node
- * whose varno/varattno fields contain a reference to a target list
- * element from either the outer or inner join relation.
- *
+ *
+ * Replaces all variables within a join clause with a new var node
+ * whose varno/varattno fields contain a reference to a target list
+ * element from either the outer or inner join relation.
+ *
* 'clause' is the join clause
* 'outer-tlist' is the target list of the outer join relation
* 'inner-tlist' is the target list of the inner join relation
- *
+ *
* Returns the new join clause.
- *
+ *
*/
-static List *
-replace_clause_joinvar_refs(Expr *clause,
- List *outer_tlist,
- List *inner_tlist)
+static List *
+replace_clause_joinvar_refs(Expr * clause,
+ List * outer_tlist,
+ List * inner_tlist)
{
- List *temp = NULL;
+ List *temp = NULL;
- if(IsA (clause,Var)) {
- temp = (List*)replace_joinvar_refs((Var*)clause,
- outer_tlist,inner_tlist);
- if(temp)
- return(temp);
- else
- if (clause != NULL)
- return((List*)clause);
- else
- return(NIL);
- } else if (single_node((Node*)clause)) {
- return ((List*)clause);
- } else if (or_clause((Node*)clause)) {
- List *orclause =
- replace_subclause_joinvar_refs(((Expr*)clause)->args,
- outer_tlist,
- inner_tlist);
- return ((List*)make_orclause(orclause));
- } else if (IsA(clause,ArrayRef)) {
- ArrayRef *aref = (ArrayRef *)clause;
-
- temp = replace_subclause_joinvar_refs(aref->refupperindexpr,
- outer_tlist,
- inner_tlist);
- aref->refupperindexpr = (List*)temp;
- temp = replace_subclause_joinvar_refs(aref->reflowerindexpr,
- outer_tlist,
- inner_tlist);
- aref->reflowerindexpr = (List*)temp;
- temp = replace_clause_joinvar_refs((Expr*)aref->refexpr,
- outer_tlist,
- inner_tlist);
- aref->refexpr = (Node*)temp;
+ if (IsA(clause, Var))
+ {
+ temp = (List *) replace_joinvar_refs((Var *) clause,
+ outer_tlist, inner_tlist);
+ if (temp)
+ return (temp);
+ else if (clause != NULL)
+ return ((List *) clause);
+ else
+ return (NIL);
+ }
+ else if (single_node((Node *) clause))
+ {
+ return ((List *) clause);
+ }
+ else if (or_clause((Node *) clause))
+ {
+ List *orclause =
+ replace_subclause_joinvar_refs(((Expr *) clause)->args,
+ outer_tlist,
+ inner_tlist);
- /*
- * no need to set refassgnexpr. we only set that in the
- * target list on replaces, and this is an array reference
- * in the qualification. if we got this far, it's 0x0 in
- * the ArrayRef structure 'clause'.
- */
+ return ((List *) make_orclause(orclause));
+ }
+ else if (IsA(clause, ArrayRef))
+ {
+ ArrayRef *aref = (ArrayRef *) clause;
+
+ temp = replace_subclause_joinvar_refs(aref->refupperindexpr,
+ outer_tlist,
+ inner_tlist);
+ aref->refupperindexpr = (List *) temp;
+ temp = replace_subclause_joinvar_refs(aref->reflowerindexpr,
+ outer_tlist,
+ inner_tlist);
+ aref->reflowerindexpr = (List *) temp;
+ temp = replace_clause_joinvar_refs((Expr *) aref->refexpr,
+ outer_tlist,
+ inner_tlist);
+ aref->refexpr = (Node *) temp;
+
+ /*
+ * no need to set refassgnexpr. we only set that in the target
+ * list on replaces, and this is an array reference in the
+ * qualification. if we got this far, it's 0x0 in the ArrayRef
+ * structure 'clause'.
+ */
+
+ return ((List *) clause);
+ }
+ else if (is_funcclause((Node *) clause))
+ {
+ List *funcclause =
+ replace_subclause_joinvar_refs(((Expr *) clause)->args,
+ outer_tlist,
+ inner_tlist);
+
+ return ((List *) make_funcclause((Func *) ((Expr *) clause)->oper,
+ funcclause));
+ }
+ else if (not_clause((Node *) clause))
+ {
+ List *notclause =
+ replace_clause_joinvar_refs(get_notclausearg(clause),
+ outer_tlist,
+ inner_tlist);
- return((List*)clause);
- } else if (is_funcclause((Node*)clause)) {
- List *funcclause =
- replace_subclause_joinvar_refs(((Expr*)clause)->args,
- outer_tlist,
- inner_tlist);
- return ((List*)make_funcclause((Func*)((Expr*)clause)->oper,
- funcclause));
- } else if (not_clause((Node*)clause)) {
- List *notclause =
- replace_clause_joinvar_refs(get_notclausearg(clause),
- outer_tlist,
- inner_tlist);
- return ((List*)make_notclause((Expr*)notclause));
- } else if (is_opclause((Node*)clause)) {
- Var *leftvar =
- (Var*)replace_clause_joinvar_refs((Expr*)get_leftop(clause),
- outer_tlist,
- inner_tlist);
- Var *rightvar =
- (Var*)replace_clause_joinvar_refs((Expr*)get_rightop(clause),
- outer_tlist,
- inner_tlist);
- return ((List*)make_opclause(replace_opid((Oper*)((Expr*)clause)->oper),
- leftvar,
- rightvar));
- }
- /* shouldn't reach here */
- return NULL;
+ return ((List *) make_notclause((Expr *) notclause));
+ }
+ else if (is_opclause((Node *) clause))
+ {
+ Var *leftvar =
+ (Var *) replace_clause_joinvar_refs((Expr *) get_leftop(clause),
+ outer_tlist,
+ inner_tlist);
+ Var *rightvar =
+ (Var *) replace_clause_joinvar_refs((Expr *) get_rightop(clause),
+ outer_tlist,
+ inner_tlist);
+
+ return ((List *) make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
+ leftvar,
+ rightvar));
+ }
+ /* shouldn't reach here */
+ return NULL;
}
-static List *
-replace_subclause_joinvar_refs(List *clauses,
- List *outer_tlist,
- List *inner_tlist)
+static List *
+replace_subclause_joinvar_refs(List * clauses,
+ List * outer_tlist,
+ List * inner_tlist)
{
- List *t_list = NIL;
- List *temp = NIL;
- List *clause = NIL;
-
- foreach (clause,clauses) {
- temp = replace_clause_joinvar_refs(lfirst(clause),
- outer_tlist,
- inner_tlist);
- t_list = lappend(t_list,temp);
- }
- return(t_list);
+ List *t_list = NIL;
+ List *temp = NIL;
+ List *clause = NIL;
+
+ foreach(clause, clauses)
+ {
+ temp = replace_clause_joinvar_refs(lfirst(clause),
+ outer_tlist,
+ inner_tlist);
+ t_list = lappend(t_list, temp);
+ }
+ return (t_list);
}
-static Var *
-replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist)
+static Var *
+replace_joinvar_refs(Var * var, List * outer_tlist, List * inner_tlist)
{
- Resdom *outer_resdom =(Resdom*)NULL;
-
- outer_resdom= tlist_member(var,outer_tlist);
-
- if (outer_resdom!=NULL && IsA (outer_resdom,Resdom) ) {
- return (makeVar (OUTER,
- outer_resdom->resno,
- var->vartype,
- var->varnoold,
- var->varoattno));
- } else {
- Resdom *inner_resdom;
- inner_resdom = tlist_member(var,inner_tlist);
- if ( inner_resdom!=NULL && IsA (inner_resdom,Resdom) ) {
- return (makeVar (INNER,
- inner_resdom->resno,
- var->vartype,
- var->varnoold,
- var->varoattno));
- }
- }
- return (Var*)NULL;
+ Resdom *outer_resdom = (Resdom *) NULL;
+
+ outer_resdom = tlist_member(var, outer_tlist);
+
+ if (outer_resdom != NULL && IsA(outer_resdom, Resdom))
+ {
+ return (makeVar(OUTER,
+ outer_resdom->resno,
+ var->vartype,
+ var->varnoold,
+ var->varoattno));
+ }
+ else
+ {
+ Resdom *inner_resdom;
+
+ inner_resdom = tlist_member(var, inner_tlist);
+ if (inner_resdom != NULL && IsA(inner_resdom, Resdom))
+ {
+ return (makeVar(INNER,
+ inner_resdom->resno,
+ var->vartype,
+ var->varnoold,
+ var->varoattno));
+ }
+ }
+ return (Var *) NULL;
}
-/*
+/*
* tlist-temp-references--
- * Creates a new target list for a node that scans a temp relation,
- * setting the varnos to the id of the temp relation and setting varids
- * if necessary (varids are only needed if this is a targetlist internal
- * to the tree, in which case the targetlist entry always contains a var
- * node, so we can just copy it from the temp).
- *
+ * Creates a new target list for a node that scans a temp relation,
+ * setting the varnos to the id of the temp relation and setting varids
+ * if necessary (varids are only needed if this is a targetlist internal
+ * to the tree, in which case the targetlist entry always contains a var
+ * node, so we can just copy it from the temp).
+ *
* 'tempid' is the id of the temp relation
* 'tlist' is the target list to be modified
- *
+ *
* Returns new target list
- *
+ *
*/
-static List *
-tlist_temp_references(Oid tempid,
- List *tlist)
+static List *
+tlist_temp_references(Oid tempid,
+ List * tlist)
{
- List *t_list = NIL;
- TargetEntry *temp = (TargetEntry *)NULL;
- TargetEntry *xtl = NULL;
- List *entry;
-
- foreach (entry, tlist) {
- AttrNumber oattno;
-
- xtl = lfirst(entry);
- if (IsA(get_expr(xtl), Var))
- oattno = ((Var*)xtl->expr)->varoattno;
- else
- oattno = 0;
-
- temp = MakeTLE(xtl->resdom,
- (Node*)makeVar(tempid,
- xtl->resdom->resno,
- xtl->resdom->restype,
- tempid,
- oattno));
-
- t_list = lappend(t_list,temp);
- }
- return(t_list);
+ List *t_list = NIL;
+ TargetEntry *temp = (TargetEntry *) NULL;
+ TargetEntry *xtl = NULL;
+ List *entry;
+
+ foreach(entry, tlist)
+ {
+ AttrNumber oattno;
+
+ xtl = lfirst(entry);
+ if (IsA(get_expr(xtl), Var))
+ oattno = ((Var *) xtl->expr)->varoattno;
+ else
+ oattno = 0;
+
+ temp = MakeTLE(xtl->resdom,
+ (Node *) makeVar(tempid,
+ xtl->resdom->resno,
+ xtl->resdom->restype,
+ tempid,
+ oattno));
+
+ t_list = lappend(t_list, temp);
+ }
+ return (t_list);
}
/*---------------------------------------------------------
@@ -456,45 +505,49 @@ tlist_temp_references(Oid tempid,
* addresses the tuples returned by its left tree subplan.
*
* NOTE:
- * 1) we ignore the right tree! (in the current implementation
- * it is always nil
- * 2) this routine will probably *NOT* work with nested dot
- * fields....
+ * 1) we ignore the right tree! (in the current implementation
+ * it is always nil
+ * 2) this routine will probably *NOT* work with nested dot
+ * fields....
*/
void
-set_result_tlist_references(Result *resultNode)
+set_result_tlist_references(Result * resultNode)
{
- Plan *subplan;
- List *resultTargetList;
- List *subplanTargetList;
- List *t;
- TargetEntry *entry;
- Expr *expr;
-
- resultTargetList= ((Plan*)resultNode)->targetlist;
-
- /*
- * NOTE: we only consider the left tree subplan.
- * This is usually a seq scan.
- */
- subplan = ((Plan*)resultNode)->lefttree;
- if (subplan != NULL) {
- subplanTargetList = subplan->targetlist;
- } else {
- subplanTargetList = NIL;
- }
-
- /*
- * now for traverse all the entris of the target list.
- * These should be of the form (Resdom_Node Expression).
- * For every expression clause, call "replace_result_clause()"
- * to appropriatelly change all the Var nodes.
- */
- foreach (t, resultTargetList) {
- entry = (TargetEntry *)lfirst(t);
- expr = (Expr*) get_expr(entry);
- replace_result_clause((List*)expr, subplanTargetList);
- }
+ Plan *subplan;
+ List *resultTargetList;
+ List *subplanTargetList;
+ List *t;
+ TargetEntry *entry;
+ Expr *expr;
+
+ resultTargetList = ((Plan *) resultNode)->targetlist;
+
+ /*
+ * NOTE: we only consider the left tree subplan. This is usually a seq
+ * scan.
+ */
+ subplan = ((Plan *) resultNode)->lefttree;
+ if (subplan != NULL)
+ {
+ subplanTargetList = subplan->targetlist;
+ }
+ else
+ {
+ subplanTargetList = NIL;
+ }
+
+ /*
+ * now for traverse all the entris of the target list. These should be
+ * of the form (Resdom_Node Expression). For every expression clause,
+ * call "replace_result_clause()" to appropriatelly change all the Var
+ * nodes.
+ */
+ foreach(t, resultTargetList)
+ {
+ entry = (TargetEntry *) lfirst(t);
+ expr = (Expr *) get_expr(entry);
+ replace_result_clause((List *) expr, subplanTargetList);
+ }
}
/*---------------------------------------------------------
@@ -504,100 +557,121 @@ set_result_tlist_references(Result *resultNode)
* This routine is called from set_result_tlist_references().
* and modifies the expressions of the target list of a Result
* node so that all Var nodes reference the target list of its subplan.
- *
+ *
*/
static void
-replace_result_clause(List *clause,
- List *subplanTargetList) /* target list of the
- subplan */
+replace_result_clause(List * clause,
+ List * subplanTargetList) /* target list of the
+ * subplan */
{
- List *t;
- List *subClause;
- TargetEntry *subplanVar;
+ List *t;
+ List *subClause;
+ TargetEntry *subplanVar;
- if (IsA(clause,Var)) {
- /*
- * Ha! A Var node!
- */
- subplanVar = match_varid((Var*)clause, subplanTargetList);
- /*
- * Change the varno & varattno fields of the
- * var node.
- *
- */
- ((Var*)clause)->varno = (Index)OUTER;
- ((Var*)clause)->varattno = subplanVar->resdom->resno;
- } else if (is_funcclause((Node*)clause)) {
- /*
- * This is a function. Recursively call this routine
- * for its arguments...
- */
- subClause = ((Expr*)clause)->args;
- foreach (t, subClause) {
- replace_result_clause(lfirst(t),subplanTargetList);
- }
- } else if (IsA(clause,ArrayRef)) {
- ArrayRef *aref = (ArrayRef *)clause;
- /*
- * This is an arrayref. Recursively call this routine
- * for its expression and its index expression...
- */
- subClause = aref->refupperindexpr;
- foreach (t, subClause) {
- replace_result_clause(lfirst(t),subplanTargetList);
- }
- subClause = aref->reflowerindexpr;
- foreach (t, subClause) {
- replace_result_clause(lfirst(t),subplanTargetList);
- }
- replace_result_clause((List*)aref->refexpr,
- subplanTargetList);
- replace_result_clause((List*)aref->refassgnexpr,
- subplanTargetList);
- } else if (is_opclause((Node*)clause)) {
- /*
- * This is an operator. Recursively call this routine
- * for both its left and right operands
- */
- subClause = (List*)get_leftop((Expr*)clause);
- replace_result_clause(subClause,subplanTargetList);
- subClause = (List*)get_rightop((Expr*)clause);
- replace_result_clause(subClause,subplanTargetList);
- } else if (IsA(clause,Param) || IsA(clause,Const)) {
- /* do nothing! */
- } else {
- /*
- * Ooops! we can not handle that!
- */
- elog(WARN,"replace_result_clause: Can not handle this tlist!\n");
- }
+ if (IsA(clause, Var))
+ {
+
+ /*
+ * Ha! A Var node!
+ */
+ subplanVar = match_varid((Var *) clause, subplanTargetList);
+
+ /*
+ * Change the varno & varattno fields of the var node.
+ *
+ */
+ ((Var *) clause)->varno = (Index) OUTER;
+ ((Var *) clause)->varattno = subplanVar->resdom->resno;
+ }
+ else if (is_funcclause((Node *) clause))
+ {
+
+ /*
+ * This is a function. Recursively call this routine for its
+ * arguments...
+ */
+ subClause = ((Expr *) clause)->args;
+ foreach(t, subClause)
+ {
+ replace_result_clause(lfirst(t), subplanTargetList);
+ }
+ }
+ else if (IsA(clause, ArrayRef))
+ {
+ ArrayRef *aref = (ArrayRef *) clause;
+
+ /*
+ * This is an arrayref. Recursively call this routine for its
+ * expression and its index expression...
+ */
+ subClause = aref->refupperindexpr;
+ foreach(t, subClause)
+ {
+ replace_result_clause(lfirst(t), subplanTargetList);
+ }
+ subClause = aref->reflowerindexpr;
+ foreach(t, subClause)
+ {
+ replace_result_clause(lfirst(t), subplanTargetList);
+ }
+ replace_result_clause((List *) aref->refexpr,
+ subplanTargetList);
+ replace_result_clause((List *) aref->refassgnexpr,
+ subplanTargetList);
+ }
+ else if (is_opclause((Node *) clause))
+ {
+
+ /*
+ * This is an operator. Recursively call this routine for both its
+ * left and right operands
+ */
+ subClause = (List *) get_leftop((Expr *) clause);
+ replace_result_clause(subClause, subplanTargetList);
+ subClause = (List *) get_rightop((Expr *) clause);
+ replace_result_clause(subClause, subplanTargetList);
+ }
+ else if (IsA(clause, Param) || IsA(clause, Const))
+ {
+ /* do nothing! */
+ }
+ else
+ {
+
+ /*
+ * Ooops! we can not handle that!
+ */
+ elog(WARN, "replace_result_clause: Can not handle this tlist!\n");
+ }
}
static
-bool OperandIsInner(Node *opnd, int inner_relid)
+bool
+OperandIsInner(Node * opnd, int inner_relid)
{
- /*
- * Can be the inner scan if its a varnode or a function and the
- * inner_relid is equal to the varnode's var number or in the
- * case of a function the first argument's var number (all args
- * in a functional index are from the same relation).
- */
- if ( IsA (opnd,Var) &&
- (inner_relid == ((Var*)opnd)->varno) )
+
+ /*
+ * Can be the inner scan if its a varnode or a function and the
+ * inner_relid is equal to the varnode's var number or in the case of
+ * a function the first argument's var number (all args in a
+ * functional index are from the same relation).
+ */
+ if (IsA(opnd, Var) &&
+ (inner_relid == ((Var *) opnd)->varno))
{
- return true;
+ return true;
}
- if (is_funcclause(opnd))
+ if (is_funcclause(opnd))
{
- List *firstArg = lfirst(((Expr*)opnd)->args);
+ List *firstArg = lfirst(((Expr *) opnd)->args);
- if ( IsA (firstArg,Var) &&
- (inner_relid == ((Var*)firstArg)->varno) )
+ if (IsA(firstArg, Var) &&
+ (inner_relid == ((Var *) firstArg)->varno))
{
- return true;
+ return true;
}
}
- return false;
+ return false;
}
/*****************************************************************************
@@ -607,105 +681,125 @@ bool OperandIsInner(Node *opnd, int inner_relid)
/*---------------------------------------------------------
*
* set_agg_tlist_references -
- * changes the target list of an Agg node so that it points to
- * the tuples returned by its left tree subplan.
+ * changes the target list of an Agg node so that it points to
+ * the tuples returned by its left tree subplan.
*
*/
void
-set_agg_tlist_references(Agg *aggNode)
+set_agg_tlist_references(Agg * aggNode)
{
- List *aggTargetList;
- List *subplanTargetList;
- List *tl;
+ List *aggTargetList;
+ List *subplanTargetList;
+ List *tl;
- aggTargetList = aggNode->plan.targetlist;
- subplanTargetList = aggNode->plan.lefttree->targetlist;
+ aggTargetList = aggNode->plan.targetlist;
+ subplanTargetList = aggNode->plan.lefttree->targetlist;
- foreach (tl, aggTargetList) {
- TargetEntry *tle = lfirst(tl);
+ foreach(tl, aggTargetList)
+ {
+ TargetEntry *tle = lfirst(tl);
- replace_agg_clause(tle->expr, subplanTargetList);
- }
+ replace_agg_clause(tle->expr, subplanTargetList);
+ }
}
void
-set_agg_agglist_references(Agg *aggNode)
+set_agg_agglist_references(Agg * aggNode)
{
- List *subplanTargetList;
- Aggreg **aggs;
- int i;
+ List *subplanTargetList;
+ Aggreg **aggs;
+ int i;
- aggs = aggNode->aggs;
- subplanTargetList = aggNode->plan.lefttree->targetlist;
+ aggs = aggNode->aggs;
+ subplanTargetList = aggNode->plan.lefttree->targetlist;
- for (i = 0; i < aggNode->numAgg; i++) {
- replace_agg_clause(aggs[i]->target, subplanTargetList);
- }
+ for (i = 0; i < aggNode->numAgg; i++)
+ {
+ replace_agg_clause(aggs[i]->target, subplanTargetList);
+ }
}
static void
-replace_agg_clause(Node *clause, List *subplanTargetList)
+replace_agg_clause(Node * clause, List * subplanTargetList)
{
- List *t;
- TargetEntry *subplanVar;
+ List *t;
+ TargetEntry *subplanVar;
- if (IsA(clause,Var)) {
- /*
- * Ha! A Var node!
- */
- subplanVar = match_varid((Var*)clause, subplanTargetList);
- /*
- * Change the varno & varattno fields of the
- * var node.
- *
- */
- ((Var*)clause)->varattno = subplanVar->resdom->resno;
- } else if (is_funcclause(clause)) {
- /*
- * This is a function. Recursively call this routine
- * for its arguments...
- */
- foreach (t, ((Expr*)clause)->args) {
- replace_agg_clause(lfirst(t), subplanTargetList);
- }
- } else if (IsA(clause,Aggreg)) {
- replace_agg_clause(((Aggreg*)clause)->target, subplanTargetList);
- } else if (IsA(clause,ArrayRef)) {
- ArrayRef *aref = (ArrayRef *)clause;
+ if (IsA(clause, Var))
+ {
- /*
- * This is an arrayref. Recursively call this routine
- * for its expression and its index expression...
- */
- foreach (t, aref->refupperindexpr) {
- replace_agg_clause(lfirst(t),subplanTargetList);
+ /*
+ * Ha! A Var node!
+ */
+ subplanVar = match_varid((Var *) clause, subplanTargetList);
+
+ /*
+ * Change the varno & varattno fields of the var node.
+ *
+ */
+ ((Var *) clause)->varattno = subplanVar->resdom->resno;
+ }
+ else if (is_funcclause(clause))
+ {
+
+ /*
+ * This is a function. Recursively call this routine for its
+ * arguments...
+ */
+ foreach(t, ((Expr *) clause)->args)
+ {
+ replace_agg_clause(lfirst(t), subplanTargetList);
+ }
}
- foreach (t, aref->reflowerindexpr) {
- replace_agg_clause(lfirst(t),subplanTargetList);
+ else if (IsA(clause, Aggreg))
+ {
+ replace_agg_clause(((Aggreg *) clause)->target, subplanTargetList);
}
- replace_agg_clause(aref->refexpr, subplanTargetList);
- replace_agg_clause(aref->refassgnexpr, subplanTargetList);
- } else if (is_opclause(clause)) {
- /*
- * This is an operator. Recursively call this routine
- * for both its left and right operands
- */
- Node *left = (Node*)get_leftop((Expr*)clause);
- Node *right = (Node*)get_rightop((Expr*)clause);
-
- if ( left != (Node*) NULL )
- replace_agg_clause(left, subplanTargetList);
- if ( right != (Node*) NULL )
- replace_agg_clause(right, subplanTargetList);
- } else if (IsA(clause,Param) || IsA(clause,Const)) {
- /* do nothing! */
- } else {
- /*
- * Ooops! we can not handle that!
- */
- elog(WARN,"replace_agg_clause: Can not handle this tlist!\n");
- }
+ else if (IsA(clause, ArrayRef))
+ {
+ ArrayRef *aref = (ArrayRef *) clause;
-}
+ /*
+ * This is an arrayref. Recursively call this routine for its
+ * expression and its index expression...
+ */
+ foreach(t, aref->refupperindexpr)
+ {
+ replace_agg_clause(lfirst(t), subplanTargetList);
+ }
+ foreach(t, aref->reflowerindexpr)
+ {
+ replace_agg_clause(lfirst(t), subplanTargetList);
+ }
+ replace_agg_clause(aref->refexpr, subplanTargetList);
+ replace_agg_clause(aref->refassgnexpr, subplanTargetList);
+ }
+ else if (is_opclause(clause))
+ {
+
+ /*
+ * This is an operator. Recursively call this routine for both its
+ * left and right operands
+ */
+ Node *left = (Node *) get_leftop((Expr *) clause);
+ Node *right = (Node *) get_rightop((Expr *) clause);
+
+ if (left != (Node *) NULL)
+ replace_agg_clause(left, subplanTargetList);
+ if (right != (Node *) NULL)
+ replace_agg_clause(right, subplanTargetList);
+ }
+ else if (IsA(clause, Param) || IsA(clause, Const))
+ {
+ /* do nothing! */
+ }
+ else
+ {
+ /*
+ * Ooops! we can not handle that!
+ */
+ elog(WARN, "replace_agg_clause: Can not handle this tlist!\n");
+ }
+}
diff --git a/src/backend/optimizer/prep/archive.c b/src/backend/optimizer/prep/archive.c
index 0303eca70f1..bbc797234ac 100644
--- a/src/backend/optimizer/prep/archive.c
+++ b/src/backend/optimizer/prep/archive.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* archive.c--
- * Support for planning scans on archived relations
+ * Support for planning scans on archived relations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/Attic/archive.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/Attic/archive.c,v 1.2 1997/09/07 04:44:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
-#include <sys/types.h> /* for u_int in relcache.h */
+#include <stdio.h> /* for sprintf() */
+#include <sys/types.h> /* for u_int in relcache.h */
#include "postgres.h"
#include "utils/rel.h"
@@ -26,41 +26,44 @@
#include "commands/creatinh.h"
void
-plan_archive(List *rt)
+plan_archive(List * rt)
{
- List *rtitem;
- RangeTblEntry *rte;
- TimeRange *trange;
- Relation r;
- Oid reloid;
+ List *rtitem;
+ RangeTblEntry *rte;
+ TimeRange *trange;
+ Relation r;
+ Oid reloid;
- foreach(rtitem, rt) {
- rte = lfirst(rtitem);
- trange = rte->timeRange;
- if (trange) {
- reloid = rte->relid;
- r = RelationIdGetRelation(reloid);
- if (r->rd_rel->relarch != 'n') {
- rte->archive = true;
- }
+ foreach(rtitem, rt)
+ {
+ rte = lfirst(rtitem);
+ trange = rte->timeRange;
+ if (trange)
+ {
+ reloid = rte->relid;
+ r = RelationIdGetRelation(reloid);
+ if (r->rd_rel->relarch != 'n')
+ {
+ rte->archive = true;
+ }
+ }
}
- }
}
/*
- * find_archive_rels -- Given a particular relid, find the archive
- * relation's relid.
+ * find_archive_rels -- Given a particular relid, find the archive
+ * relation's relid.
*/
-List *
+List *
find_archive_rels(Oid relid)
{
- Relation arel;
- char *arelName;
+ Relation arel;
+ char *arelName;
- arelName = MakeArchiveName(relid);
- arel = RelationNameGetRelation(arelName);
- pfree(arelName);
+ arelName = MakeArchiveName(relid);
+ arel = RelationNameGetRelation(arelName);
+ pfree(arelName);
- return lconsi(arel->rd_id, lconsi(relid, NIL));
+ return lconsi(arel->rd_id, lconsi(relid, NIL));
}
diff --git a/src/backend/optimizer/prep/prepqual.c b/src/backend/optimizer/prep/prepqual.c
index 148f9638089..eac1eafa44f 100644
--- a/src/backend/optimizer/prep/prepqual.c
+++ b/src/backend/optimizer/prep/prepqual.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* prepqual.c--
- * Routines for preprocessing the parse tree qualification
+ * Routines for preprocessing the parse tree qualification
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.3 1997/08/20 14:53:30 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.4 1997/09/07 04:44:10 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,531 +24,608 @@
#include "utils/lsyscache.h"
-static Expr *pull_args(Expr *qual);
-static List *pull_ors(List *orlist);
-static List *pull_ands(List *andlist);
-static Expr *find_nots(Expr *qual);
-static Expr *push_nots(Expr *qual);
-static Expr *normalize(Expr *qual);
-static List *or_normalize(List *orlist);
-static List *distribute_args(List *item, List *args);
-static List *qualcleanup(Expr *qual);
-static List *remove_ands(Expr *qual);
-static List *remove_duplicates(List *list);
-
-/*
+static Expr *pull_args(Expr * qual);
+static List *pull_ors(List * orlist);
+static List *pull_ands(List * andlist);
+static Expr *find_nots(Expr * qual);
+static Expr *push_nots(Expr * qual);
+static Expr *normalize(Expr * qual);
+static List *or_normalize(List * orlist);
+static List *distribute_args(List * item, List * args);
+static List *qualcleanup(Expr * qual);
+static List *remove_ands(Expr * qual);
+static List *remove_duplicates(List * list);
+
+/*
* preprocess-qualification--
- * Driver routine for modifying the parse tree qualification.
- *
+ * Driver routine for modifying the parse tree qualification.
+ *
* Returns the new base qualification and the existential qualification
* in existentialQualPtr.
- *
- * XXX right now, update_clauses() does nothing so
- * preprocess-qualification simply converts the qual in conjunctive
- * normal form (see cnfify() below )
+ *
+ * XXX right now, update_clauses() does nothing so
+ * preprocess-qualification simply converts the qual in conjunctive
+ * normal form (see cnfify() below )
*/
-List *
-preprocess_qualification(Expr *qual, List *tlist, List **existentialQualPtr)
+List *
+preprocess_qualification(Expr * qual, List * tlist, List ** existentialQualPtr)
{
- List *cnf_qual = cnfify(qual, true);
+ List *cnf_qual = cnfify(qual, true);
+
/*
- List *existential_qual =
- update_clauses(intCons(_query_result_relation_,
- update_relations(tlist)),
- cnf_qual,
- _query_command_type_);
- if (existential_qual) {
- *existentialQualPtr = existential_qual;
- return set_difference(cnf_qual, existential_qual);
- } else {
+ List *existential_qual =
+ update_clauses(intCons(_query_result_relation_,
+ update_relations(tlist)),
+ cnf_qual,
+ _query_command_type_);
+ if (existential_qual) {
+ *existentialQualPtr = existential_qual;
+ return set_difference(cnf_qual, existential_qual);
+ } else {
+ *existentialQualPtr = NIL;
+ return cnf_qual;
+ }
+*/
+ /* update_clauses() is not working right now */
*existentialQualPtr = NIL;
return cnf_qual;
- }
-*/
- /* update_clauses() is not working right now */
- *existentialQualPtr = NIL;
- return cnf_qual;
}
/*****************************************************************************
*
- * CNF CONVERSION ROUTINES
- *
- * NOTES:
- * The basic algorithms for normalizing the qualification are taken
- * from ingres/source/qrymod/norml.c
- *
- * Remember that the initial qualification may consist of ARBITRARY
- * combinations of clauses. In addition, before this routine is called,
- * the qualification will contain explicit "AND"s.
- *
+ * CNF CONVERSION ROUTINES
+ *
+ * NOTES:
+ * The basic algorithms for normalizing the qualification are taken
+ * from ingres/source/qrymod/norml.c
+ *
+ * Remember that the initial qualification may consist of ARBITRARY
+ * combinations of clauses. In addition, before this routine is called,
+ * the qualification will contain explicit "AND"s.
+ *
*****************************************************************************/
-/*
+/*
* cnfify--
- * Convert a qualification to conjunctive normal form by applying
- * successive normalizations.
- *
+ * Convert a qualification to conjunctive normal form by applying
+ * successive normalizations.
+ *
* Returns the modified qualification with an extra level of nesting.
*
* If 'removeAndFlag' is true then it removes the explicit ANDs.
*
* NOTE: this routine is called by the planner (removeAndFlag = true)
- * and from the rule manager (removeAndFlag = false).
+ * and from the rule manager (removeAndFlag = false).
*
*/
-List *
-cnfify(Expr *qual, bool removeAndFlag)
+List *
+cnfify(Expr * qual, bool removeAndFlag)
{
- Expr *newqual = NULL;
-
- if (qual != NULL) {
- newqual = find_nots(pull_args(qual));
- newqual = normalize(pull_args(newqual));
- newqual = (Expr*)qualcleanup(pull_args(newqual));
- newqual = pull_args(newqual);;
-
- if (removeAndFlag) {
- if(and_clause((Node*)newqual))
- newqual=(Expr*)remove_ands(newqual);
- else
- newqual=(Expr*)remove_ands(make_andclause(lcons(newqual,NIL)));
- }
- }
- else if (qual!=NULL)
- newqual = (Expr*)lcons(qual, NIL);
-
- return (List*)(newqual);
+ Expr *newqual = NULL;
+
+ if (qual != NULL)
+ {
+ newqual = find_nots(pull_args(qual));
+ newqual = normalize(pull_args(newqual));
+ newqual = (Expr *) qualcleanup(pull_args(newqual));
+ newqual = pull_args(newqual);;
+
+ if (removeAndFlag)
+ {
+ if (and_clause((Node *) newqual))
+ newqual = (Expr *) remove_ands(newqual);
+ else
+ newqual = (Expr *) remove_ands(make_andclause(lcons(newqual, NIL)));
+ }
+ }
+ else if (qual != NULL)
+ newqual = (Expr *) lcons(qual, NIL);
+
+ return (List *) (newqual);
}
-/*
+/*
* pull-args--
- * Given a qualification, eliminate nested 'and' and 'or' clauses.
- *
+ * Given a qualification, eliminate nested 'and' and 'or' clauses.
+ *
* Returns the modified qualification.
- *
+ *
*/
-static Expr *
-pull_args(Expr *qual)
+static Expr *
+pull_args(Expr * qual)
{
- if (qual==NULL)
- return (NULL);
-
- if (is_opclause((Node*)qual)) {
- return(make_clause(qual->opType, qual->oper,
- lcons(pull_args((Expr*)get_leftop(qual)),
- lcons(pull_args((Expr*)get_rightop(qual)),
- NIL))));
- } else if (and_clause((Node*)qual)) {
- List *temp = NIL;
- List *t_list = NIL;
-
- foreach (temp, qual->args)
- t_list = lappend (t_list, pull_args(lfirst(temp)));
- return (make_andclause (pull_ands (t_list)));
- }else if (or_clause((Node*)qual)) {
- List *temp = NIL;
- List *t_list = NIL;
-
- foreach (temp, qual->args)
- t_list = lappend (t_list, pull_args(lfirst(temp)));
- return (make_orclause (pull_ors (t_list)));
- } else if (not_clause((Node*)qual)) {
- return (make_notclause (pull_args (get_notclausearg (qual))));
- } else {
- return (qual);
- }
+ if (qual == NULL)
+ return (NULL);
+
+ if (is_opclause((Node *) qual))
+ {
+ return (make_clause(qual->opType, qual->oper,
+ lcons(pull_args((Expr *) get_leftop(qual)),
+ lcons(pull_args((Expr *) get_rightop(qual)),
+ NIL))));
+ }
+ else if (and_clause((Node *) qual))
+ {
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ foreach(temp, qual->args)
+ t_list = lappend(t_list, pull_args(lfirst(temp)));
+ return (make_andclause(pull_ands(t_list)));
+ }
+ else if (or_clause((Node *) qual))
+ {
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ foreach(temp, qual->args)
+ t_list = lappend(t_list, pull_args(lfirst(temp)));
+ return (make_orclause(pull_ors(t_list)));
+ }
+ else if (not_clause((Node *) qual))
+ {
+ return (make_notclause(pull_args(get_notclausearg(qual))));
+ }
+ else
+ {
+ return (qual);
+ }
}
-/*
+/*
* pull-ors--
- * Pull the arguments of an 'or' clause nested within another 'or'
- * clause up into the argument list of the parent.
- *
+ * Pull the arguments of an 'or' clause nested within another 'or'
+ * clause up into the argument list of the parent.
+ *
* Returns the modified list.
*/
-static List *
-pull_ors(List *orlist)
+static List *
+pull_ors(List * orlist)
{
- if (orlist==NIL)
- return (NIL);
+ if (orlist == NIL)
+ return (NIL);
- if (or_clause(lfirst(orlist))) {
- List *args = ((Expr*)lfirst(orlist))->args;
- return (pull_ors(nconc(copyObject((Node*)args),
- copyObject((Node*)lnext(orlist)))));
- } else {
- return (lcons(lfirst(orlist), pull_ors(lnext(orlist))));
- }
+ if (or_clause(lfirst(orlist)))
+ {
+ List *args = ((Expr *) lfirst(orlist))->args;
+
+ return (pull_ors(nconc(copyObject((Node *) args),
+ copyObject((Node *) lnext(orlist)))));
+ }
+ else
+ {
+ return (lcons(lfirst(orlist), pull_ors(lnext(orlist))));
+ }
}
-/*
+/*
* pull-ands--
- * Pull the arguments of an 'and' clause nested within another 'and'
- * clause up into the argument list of the parent.
- *
+ * Pull the arguments of an 'and' clause nested within another 'and'
+ * clause up into the argument list of the parent.
+ *
* Returns the modified list.
*/
-static List *
-pull_ands(List *andlist)
+static List *
+pull_ands(List * andlist)
{
- if (andlist==NIL)
- return (NIL);
+ if (andlist == NIL)
+ return (NIL);
+
+ if (and_clause(lfirst(andlist)))
+ {
+ List *args = ((Expr *) lfirst(andlist))->args;
- if (and_clause (lfirst(andlist))) {
- List *args = ((Expr*)lfirst(andlist))->args;
- return (pull_ands(nconc(copyObject((Node*)args),
- copyObject((Node*)lnext(andlist)))));
- } else {
- return (lcons(lfirst(andlist), pull_ands(lnext(andlist))));
- }
+ return (pull_ands(nconc(copyObject((Node *) args),
+ copyObject((Node *) lnext(andlist)))));
+ }
+ else
+ {
+ return (lcons(lfirst(andlist), pull_ands(lnext(andlist))));
+ }
}
-/*
+/*
* find-nots--
- * Traverse the qualification, looking for 'not's to take care of.
- * For 'not' clauses, remove the 'not' and push it down to the clauses'
- * descendants.
- * For all other clause types, simply recurse.
- *
+ * Traverse the qualification, looking for 'not's to take care of.
+ * For 'not' clauses, remove the 'not' and push it down to the clauses'
+ * descendants.
+ * For all other clause types, simply recurse.
+ *
* Returns the modified qualification.
- *
+ *
*/
-static Expr *
-find_nots(Expr *qual)
+static Expr *
+find_nots(Expr * qual)
{
- if (qual==NULL)
- return (NULL);
-
- if (is_opclause((Node*)qual)) {
- return (make_clause(qual->opType, qual->oper,
- lcons(find_nots((Expr*)get_leftop(qual)),
- lcons(find_nots((Expr*)get_rightop(qual)),
- NIL))));
- } else if (and_clause ((Node*)qual)) {
- List *temp = NIL;
- List *t_list = NIL;
-
- foreach (temp, qual->args) {
- t_list = lappend(t_list,find_nots(lfirst(temp)));
- }
-
- return (make_andclause(t_list));
- } else if (or_clause((Node*)qual)) {
- List *temp = NIL;
- List *t_list = NIL;
-
- foreach (temp, qual->args) {
- t_list = lappend(t_list,find_nots(lfirst(temp)));
- }
- return (make_orclause (t_list));
- } else if (not_clause((Node*)qual))
- return (push_nots(get_notclausearg (qual)));
- else
- return (qual);
+ if (qual == NULL)
+ return (NULL);
+
+ if (is_opclause((Node *) qual))
+ {
+ return (make_clause(qual->opType, qual->oper,
+ lcons(find_nots((Expr *) get_leftop(qual)),
+ lcons(find_nots((Expr *) get_rightop(qual)),
+ NIL))));
+ }
+ else if (and_clause((Node *) qual))
+ {
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ foreach(temp, qual->args)
+ {
+ t_list = lappend(t_list, find_nots(lfirst(temp)));
+ }
+
+ return (make_andclause(t_list));
+ }
+ else if (or_clause((Node *) qual))
+ {
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ foreach(temp, qual->args)
+ {
+ t_list = lappend(t_list, find_nots(lfirst(temp)));
+ }
+ return (make_orclause(t_list));
+ }
+ else if (not_clause((Node *) qual))
+ return (push_nots(get_notclausearg(qual)));
+ else
+ return (qual);
}
-/*
+/*
* push-nots--
- * Negate the descendants of a 'not' clause.
- *
+ * Negate the descendants of a 'not' clause.
+ *
* Returns the modified qualification.
- *
+ *
*/
-static Expr *
-push_nots(Expr *qual)
+static Expr *
+push_nots(Expr * qual)
{
- if (qual==NULL)
- return (NULL);
-
- /*
- * Negate an operator clause if possible:
- * ("NOT" (< A B)) => (> A B)
- * Otherwise, retain the clause as it is (the 'not' can't be pushed
- * down any farther).
- */
- if (is_opclause((Node*)qual)) {
- Oper *oper = (Oper*)((Expr*)qual)->oper;
- Oid negator = get_negator(oper->opno);
-
- if(negator) {
- Oper *op = (Oper*) makeOper(negator,
- InvalidOid,
- oper->opresulttype,
- 0, NULL);
- op->op_fcache = (FunctionCache *) NULL;
- return
- (make_opclause(op, get_leftop(qual), get_rightop(qual)));
- } else {
- return (make_notclause(qual));
- }
- } else if (and_clause((Node*)qual)) {
- /* Apply DeMorgan's Laws:
- * ("NOT" ("AND" A B)) => ("OR" ("NOT" A) ("NOT" B))
- * ("NOT" ("OR" A B)) => ("AND" ("NOT" A) ("NOT" B))
- * i.e., continue negating down through the clause's descendants.
- */
- List *temp = NIL;
- List *t_list = NIL;
-
- foreach(temp, qual->args) {
- t_list = lappend(t_list,push_nots(lfirst(temp)));
- }
- return (make_orclause (t_list));
- } else if (or_clause((Node*)qual)) {
- List *temp = NIL;
- List *t_list = NIL;
-
- foreach(temp, qual->args) {
- t_list = lappend(t_list,push_nots(lfirst(temp)));
- }
- return (make_andclause (t_list));
- } else if (not_clause((Node*)qual))
- /* Another 'not' cancels this 'not', so eliminate the 'not' and
- * stop negating this branch.
- */
- return (find_nots (get_notclausearg (qual)));
- else
- /* We don't know how to negate anything else, place a 'not' at this
- * level.
+ if (qual == NULL)
+ return (NULL);
+
+ /*
+ * Negate an operator clause if possible: ("NOT" (< A B)) => (> A B)
+ * Otherwise, retain the clause as it is (the 'not' can't be pushed
+ * down any farther).
*/
- return (make_notclause (qual));
+ if (is_opclause((Node *) qual))
+ {
+ Oper *oper = (Oper *) ((Expr *) qual)->oper;
+ Oid negator = get_negator(oper->opno);
+
+ if (negator)
+ {
+ Oper *op = (Oper *) makeOper(negator,
+ InvalidOid,
+ oper->opresulttype,
+ 0, NULL);
+
+ op->op_fcache = (FunctionCache *) NULL;
+ return
+ (make_opclause(op, get_leftop(qual), get_rightop(qual)));
+ }
+ else
+ {
+ return (make_notclause(qual));
+ }
+ }
+ else if (and_clause((Node *) qual))
+ {
+
+ /*
+ * Apply DeMorgan's Laws: ("NOT" ("AND" A B)) => ("OR" ("NOT" A)
+ * ("NOT" B)) ("NOT" ("OR" A B)) => ("AND" ("NOT" A) ("NOT" B))
+ * i.e., continue negating down through the clause's descendants.
+ */
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ foreach(temp, qual->args)
+ {
+ t_list = lappend(t_list, push_nots(lfirst(temp)));
+ }
+ return (make_orclause(t_list));
+ }
+ else if (or_clause((Node *) qual))
+ {
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ foreach(temp, qual->args)
+ {
+ t_list = lappend(t_list, push_nots(lfirst(temp)));
+ }
+ return (make_andclause(t_list));
+ }
+ else if (not_clause((Node *) qual))
+
+ /*
+ * Another 'not' cancels this 'not', so eliminate the 'not' and
+ * stop negating this branch.
+ */
+ return (find_nots(get_notclausearg(qual)));
+ else
+
+ /*
+ * We don't know how to negate anything else, place a 'not' at
+ * this level.
+ */
+ return (make_notclause(qual));
}
-/*
+/*
* normalize--
- * Given a qualification tree with the 'not's pushed down, convert it
- * to a tree in CNF by repeatedly applying the rule:
- * ("OR" A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
- * bottom-up.
- * Note that 'or' clauses will always be turned into 'and' clauses.
- *
+ * Given a qualification tree with the 'not's pushed down, convert it
+ * to a tree in CNF by repeatedly applying the rule:
+ * ("OR" A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
+ * bottom-up.
+ * Note that 'or' clauses will always be turned into 'and' clauses.
+ *
* Returns the modified qualification.
- *
+ *
*/
-static Expr *
-normalize(Expr *qual)
+static Expr *
+normalize(Expr * qual)
{
- if (qual==NULL)
- return (NULL);
-
- if (is_opclause((Node*)qual)) {
- Expr *expr = (Expr*)qual;
- return (make_clause(expr->opType, expr->oper,
- lcons(normalize((Expr*)get_leftop(qual)),
- lcons(normalize((Expr*)get_rightop(qual)),
- NIL))));
- } else if (and_clause((Node*)qual)) {
- List *temp = NIL;
- List *t_list = NIL;
-
- foreach (temp, qual->args) {
- t_list = lappend(t_list,normalize(lfirst(temp)));
- }
- return (make_andclause (t_list));
- } else if (or_clause((Node*)qual)) {
- /* XXX - let form, maybe incorrect */
- List *orlist = NIL;
- List *temp = NIL;
- bool has_andclause = FALSE;
-
- foreach(temp, qual->args) {
- orlist = lappend(orlist,normalize(lfirst(temp)));
- }
- foreach (temp, orlist) {
- if (and_clause (lfirst(temp))) {
- has_andclause = TRUE;
- break;
- }
- }
- if (has_andclause == TRUE)
- return (make_andclause(or_normalize(orlist)));
- else
- return (make_orclause(orlist));
-
- } else if (not_clause((Node*)qual))
- return (make_notclause (normalize (get_notclausearg (qual))));
- else
- return (qual);
+ if (qual == NULL)
+ return (NULL);
+
+ if (is_opclause((Node *) qual))
+ {
+ Expr *expr = (Expr *) qual;
+
+ return (make_clause(expr->opType, expr->oper,
+ lcons(normalize((Expr *) get_leftop(qual)),
+ lcons(normalize((Expr *) get_rightop(qual)),
+ NIL))));
+ }
+ else if (and_clause((Node *) qual))
+ {
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ foreach(temp, qual->args)
+ {
+ t_list = lappend(t_list, normalize(lfirst(temp)));
+ }
+ return (make_andclause(t_list));
+ }
+ else if (or_clause((Node *) qual))
+ {
+ /* XXX - let form, maybe incorrect */
+ List *orlist = NIL;
+ List *temp = NIL;
+ bool has_andclause = FALSE;
+
+ foreach(temp, qual->args)
+ {
+ orlist = lappend(orlist, normalize(lfirst(temp)));
+ }
+ foreach(temp, orlist)
+ {
+ if (and_clause(lfirst(temp)))
+ {
+ has_andclause = TRUE;
+ break;
+ }
+ }
+ if (has_andclause == TRUE)
+ return (make_andclause(or_normalize(orlist)));
+ else
+ return (make_orclause(orlist));
+
+ }
+ else if (not_clause((Node *) qual))
+ return (make_notclause(normalize(get_notclausearg(qual))));
+ else
+ return (qual);
}
-/*
+/*
* or-normalize--
- * Given a list of exprs which are 'or'ed together, distribute any
- * 'and' clauses.
- *
+ * Given a list of exprs which are 'or'ed together, distribute any
+ * 'and' clauses.
+ *
* Returns the modified list.
- *
+ *
*/
-static List *
-or_normalize(List *orlist)
+static List *
+or_normalize(List * orlist)
{
- List *distributable = NIL;
- List *new_orlist = NIL;
- List *temp = NIL;
-
- if (orlist==NIL)
- return NIL;
-
- foreach(temp, orlist) {
- if (and_clause(lfirst(temp)))
- distributable = lfirst(temp);
- }
- if (distributable)
- new_orlist = LispRemove(distributable,orlist);
-
- if(new_orlist) {
- return
- (or_normalize(lcons(distribute_args(lfirst(new_orlist),
- ((Expr*)distributable)->args),
- lnext(new_orlist))));
- }else {
- return (orlist);
- }
+ List *distributable = NIL;
+ List *new_orlist = NIL;
+ List *temp = NIL;
+
+ if (orlist == NIL)
+ return NIL;
+
+ foreach(temp, orlist)
+ {
+ if (and_clause(lfirst(temp)))
+ distributable = lfirst(temp);
+ }
+ if (distributable)
+ new_orlist = LispRemove(distributable, orlist);
+
+ if (new_orlist)
+ {
+ return
+ (or_normalize(lcons(distribute_args(lfirst(new_orlist),
+ ((Expr *) distributable)->args),
+ lnext(new_orlist))));
+ }
+ else
+ {
+ return (orlist);
+ }
}
-/*
+/*
* distribute-args--
- * Create new 'or' clauses by or'ing 'item' with each element of 'args'.
- * E.g.: (distribute-args A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
- *
+ * Create new 'or' clauses by or'ing 'item' with each element of 'args'.
+ * E.g.: (distribute-args A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
+ *
* Returns an 'and' clause.
- *
+ *
*/
-static List *
-distribute_args(List *item, List *args)
+static List *
+distribute_args(List * item, List * args)
{
- List *or_list = NIL;
- List *n_list = NIL;
- List *temp = NIL;
- List *t_list = NIL;
-
- if (args==NULL)
- return (item);
-
- foreach (temp,args) {
- n_list = or_normalize(pull_ors(lcons(item,
- lcons(lfirst(temp),NIL))));
- or_list = (List*)make_orclause(n_list);
- t_list = lappend(t_list,or_list);
- }
- return ((List*)make_andclause(t_list));
+ List *or_list = NIL;
+ List *n_list = NIL;
+ List *temp = NIL;
+ List *t_list = NIL;
+
+ if (args == NULL)
+ return (item);
+
+ foreach(temp, args)
+ {
+ n_list = or_normalize(pull_ors(lcons(item,
+ lcons(lfirst(temp), NIL))));
+ or_list = (List *) make_orclause(n_list);
+ t_list = lappend(t_list, or_list);
+ }
+ return ((List *) make_andclause(t_list));
}
-/*
+/*
* qualcleanup--
- * Fix up a qualification by removing duplicate entries (left over from
- * normalization), and by removing 'and' and 'or' clauses which have only
- * one valid expr (e.g., ("AND" A) => A).
- *
+ * Fix up a qualification by removing duplicate entries (left over from
+ * normalization), and by removing 'and' and 'or' clauses which have only
+ * one valid expr (e.g., ("AND" A) => A).
+ *
* Returns the modified qualfication.
- *
+ *
*/
-static List *
-qualcleanup(Expr *qual)
+static List *
+qualcleanup(Expr * qual)
{
- if (qual==NULL)
- return (NIL);
-
- if (is_opclause((Node*)qual)) {
- return ((List*)make_clause(qual->opType, qual->oper,
- lcons(qualcleanup((Expr*)get_leftop(qual)),
- lcons(qualcleanup((Expr*)get_rightop(qual)),
- NIL))));
- } else if (and_clause((Node*)qual)) {
- List *temp = NIL;
- List *t_list = NIL;
- List *new_and_args = NIL;
-
- foreach(temp, qual->args)
- t_list = lappend(t_list,qualcleanup(lfirst(temp)));
-
- new_and_args = remove_duplicates(t_list);
-
- if(length (new_and_args) > 1)
- return ((List*)make_andclause(new_and_args));
- else
- return (lfirst(new_and_args));
- }
- else if (or_clause((Node*)qual)) {
- List *temp = NIL;
- List *t_list = NIL;
- List *new_or_args = NIL;
-
- foreach (temp, qual->args)
- t_list = lappend(t_list,qualcleanup(lfirst(temp)));
-
- new_or_args = remove_duplicates(t_list);
-
-
- if(length (new_or_args) > 1)
- return ((List*)make_orclause (new_or_args));
- else
- return (lfirst (new_or_args));
- } else if (not_clause((Node*)qual))
- return ((List*)make_notclause((Expr*)qualcleanup((Expr*)get_notclausearg(qual))));
-
- else
- return ((List*)qual);
+ if (qual == NULL)
+ return (NIL);
+
+ if (is_opclause((Node *) qual))
+ {
+ return ((List *) make_clause(qual->opType, qual->oper,
+ lcons(qualcleanup((Expr *) get_leftop(qual)),
+ lcons(qualcleanup((Expr *) get_rightop(qual)),
+ NIL))));
+ }
+ else if (and_clause((Node *) qual))
+ {
+ List *temp = NIL;
+ List *t_list = NIL;
+ List *new_and_args = NIL;
+
+ foreach(temp, qual->args)
+ t_list = lappend(t_list, qualcleanup(lfirst(temp)));
+
+ new_and_args = remove_duplicates(t_list);
+
+ if (length(new_and_args) > 1)
+ return ((List *) make_andclause(new_and_args));
+ else
+ return (lfirst(new_and_args));
+ }
+ else if (or_clause((Node *) qual))
+ {
+ List *temp = NIL;
+ List *t_list = NIL;
+ List *new_or_args = NIL;
+
+ foreach(temp, qual->args)
+ t_list = lappend(t_list, qualcleanup(lfirst(temp)));
+
+ new_or_args = remove_duplicates(t_list);
+
+
+ if (length(new_or_args) > 1)
+ return ((List *) make_orclause(new_or_args));
+ else
+ return (lfirst(new_or_args));
+ }
+ else if (not_clause((Node *) qual))
+ return ((List *) make_notclause((Expr *) qualcleanup((Expr *) get_notclausearg(qual))));
+
+ else
+ return ((List *) qual);
}
-/*
+/*
* remove-ands--
- * Remove the explicit "AND"s from the qualification:
- * ("AND" A B) => (A B)
- *
+ * Remove the explicit "AND"s from the qualification:
+ * ("AND" A B) => (A B)
+ *
* RETURNS : qual
* MODIFIES: qual
*/
-static List *
-remove_ands(Expr *qual)
+static List *
+remove_ands(Expr * qual)
{
- List *t_list = NIL;
-
- if (qual==NULL)
- return (NIL);
- if (is_opclause((Node*)qual)) {
- return ((List*)make_clause(qual->opType, qual->oper,
- lcons(remove_ands((Expr*)get_leftop(qual)),
- lcons(remove_ands((Expr*)get_rightop(qual)),
- NIL))));
- } else if (and_clause((Node*)qual)) {
- List *temp = NIL;
- foreach (temp, qual->args)
- t_list = lappend(t_list,remove_ands(lfirst(temp)));
- return(t_list);
- } else if (or_clause((Node*)qual)) {
- List *temp = NIL;
- foreach (temp, qual->args)
- t_list = lappend(t_list,remove_ands(lfirst(temp)));
- return ((List*)make_orclause((List*)t_list));
- } else if (not_clause((Node*)qual)) {
- return ((List*)make_notclause((Expr*)remove_ands((Expr*)get_notclausearg (qual))));
- } else {
- return ((List*)qual);
- }
+ List *t_list = NIL;
+
+ if (qual == NULL)
+ return (NIL);
+ if (is_opclause((Node *) qual))
+ {
+ return ((List *) make_clause(qual->opType, qual->oper,
+ lcons(remove_ands((Expr *) get_leftop(qual)),
+ lcons(remove_ands((Expr *) get_rightop(qual)),
+ NIL))));
+ }
+ else if (and_clause((Node *) qual))
+ {
+ List *temp = NIL;
+
+ foreach(temp, qual->args)
+ t_list = lappend(t_list, remove_ands(lfirst(temp)));
+ return (t_list);
+ }
+ else if (or_clause((Node *) qual))
+ {
+ List *temp = NIL;
+
+ foreach(temp, qual->args)
+ t_list = lappend(t_list, remove_ands(lfirst(temp)));
+ return ((List *) make_orclause((List *) t_list));
+ }
+ else if (not_clause((Node *) qual))
+ {
+ return ((List *) make_notclause((Expr *) remove_ands((Expr *) get_notclausearg(qual))));
+ }
+ else
+ {
+ return ((List *) qual);
+ }
}
/*****************************************************************************
*
- * EXISTENTIAL QUALIFICATIONS
+ * EXISTENTIAL QUALIFICATIONS
*
*****************************************************************************/
-/*
+/*
* update-relations--
- * Returns the range table indices (i.e., varnos) for all relations which
- * are referenced in the target list.
- *
+ * Returns the range table indices (i.e., varnos) for all relations which
+ * are referenced in the target list.
+ *
*/
-#ifdef NOT_USED
-static List *
-update_relations(List *tlist)
+#ifdef NOT_USED
+static List *
+update_relations(List * tlist)
{
- return(NIL);
+ return (NIL);
}
+
#endif
/*****************************************************************************
@@ -557,28 +634,31 @@ update_relations(List *tlist)
*
*****************************************************************************/
-static List *
-remove_duplicates(List *list)
+static List *
+remove_duplicates(List * list)
{
- List *i;
- List *j;
- List *result = NIL;
- bool there_exists_duplicate = false;
-
- if (length(list) == 1)
- return(list);
-
- foreach (i, list) {
- if (i != NIL) {
- foreach (j, lnext(i)) {
- if (equal(lfirst(i), lfirst(j)))
- there_exists_duplicate = true;
- }
- if (!there_exists_duplicate)
- result = lappend(result, lfirst(i));
-
- there_exists_duplicate = false;
- }
- }
- return(result);
+ List *i;
+ List *j;
+ List *result = NIL;
+ bool there_exists_duplicate = false;
+
+ if (length(list) == 1)
+ return (list);
+
+ foreach(i, list)
+ {
+ if (i != NIL)
+ {
+ foreach(j, lnext(i))
+ {
+ if (equal(lfirst(i), lfirst(j)))
+ there_exists_duplicate = true;
+ }
+ if (!there_exists_duplicate)
+ result = lappend(result, lfirst(i));
+
+ there_exists_duplicate = false;
+ }
+ }
+ return (result);
}
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index d57755ac064..8b94fb4cbba 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* preptlist.c--
- * Routines to preprocess the parse tree target list
+ * Routines to preprocess the parse tree target list
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.2 1997/01/22 01:42:38 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.3 1997/09/07 04:44:13 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,7 +25,7 @@
#include "utils/lsyscache.h"
#include "utils/palloc.h"
-#include "parser/parsetree.h" /* for getrelid() */
+#include "parser/parsetree.h" /* for getrelid() */
#include "parser/catalog_utils.h"
#include "optimizer/internal.h"
@@ -33,291 +33,315 @@
#include "optimizer/clauses.h"
#include "optimizer/tlist.h"
-static List *expand_targetlist(List *tlist, Oid relid, int command_type,
- Index result_relation);
-static List *replace_matching_resname(List *new_tlist,
- List *old_tlist);
-static List *new_relation_targetlist(Oid relid, Index rt_index,
- NodeTag node_type);
-
+static List *
+expand_targetlist(List * tlist, Oid relid, int command_type,
+ Index result_relation);
+static List *
+replace_matching_resname(List * new_tlist,
+ List * old_tlist);
+static List *
+new_relation_targetlist(Oid relid, Index rt_index,
+ NodeTag node_type);
-/*
+
+/*
* preprocess-targetlist--
- * Driver for preprocessing the parse tree targetlist.
- *
- * 1. Deal with appends and replaces by filling missing attributes
- * in the target list.
- * 2. Reset operator OIDs to the appropriate regproc ids.
- *
- * Returns the new targetlist.
+ * Driver for preprocessing the parse tree targetlist.
+ *
+ * 1. Deal with appends and replaces by filling missing attributes
+ * in the target list.
+ * 2. Reset operator OIDs to the appropriate regproc ids.
+ *
+ * Returns the new targetlist.
*/
-List *
-preprocess_targetlist(List *tlist,
- int command_type,
- Index result_relation,
- List *range_table)
+List *
+preprocess_targetlist(List * tlist,
+ int command_type,
+ Index result_relation,
+ List * range_table)
{
- List *expanded_tlist = NIL;
- Oid relid = InvalidOid;
- List *t_list = NIL;
- List *temp = NIL;
-
- if (result_relation>=1 && command_type != CMD_SELECT) {
- relid = getrelid(result_relation, range_table);
- }
-
- /*
- * for heap_formtuple to work, the targetlist must match the exact
- * order of the attributes. We also need to fill in the missing
- * attributes here. -ay 10/94
- */
- expanded_tlist =
- expand_targetlist(tlist, relid, command_type, result_relation);
-
- /* XXX should the fix-opids be this early?? */
- /* was mapCAR */
- foreach (temp,expanded_tlist) {
- TargetEntry *tle = lfirst(temp);
- if (tle->expr)
- fix_opid(tle->expr);
- }
- t_list = copyObject(expanded_tlist);
-
- /* ------------------
- * for "replace" or "delete" queries, add ctid of the result
- * relation into the target list so that the ctid can get
- * propogate through the execution and in the end ExecReplace()
- * will find the right tuple to replace or delete. This
- * extra field will be removed in ExecReplace().
- * For convinient, we append this extra field to the end of
- * the target list.
- * ------------------
- */
- if (command_type == CMD_UPDATE || command_type == CMD_DELETE) {
- TargetEntry *ctid;
- Resdom *resdom;
- Var *var;
-
- resdom = makeResdom(length(t_list) + 1,
- 27,
- 6,
- "ctid",
- 0,
- 0,
- 1);
-
- var = makeVar(result_relation, -1, 27, result_relation, -1);
-
- ctid = makeNode(TargetEntry);
- ctid->resdom = resdom;
- ctid->expr = (Node *)var;
- t_list = lappend(t_list, ctid);
- }
-
- return(t_list);
+ List *expanded_tlist = NIL;
+ Oid relid = InvalidOid;
+ List *t_list = NIL;
+ List *temp = NIL;
+
+ if (result_relation >= 1 && command_type != CMD_SELECT)
+ {
+ relid = getrelid(result_relation, range_table);
+ }
+
+ /*
+ * for heap_formtuple to work, the targetlist must match the exact
+ * order of the attributes. We also need to fill in the missing
+ * attributes here. -ay 10/94
+ */
+ expanded_tlist =
+ expand_targetlist(tlist, relid, command_type, result_relation);
+
+ /* XXX should the fix-opids be this early?? */
+ /* was mapCAR */
+ foreach(temp, expanded_tlist)
+ {
+ TargetEntry *tle = lfirst(temp);
+
+ if (tle->expr)
+ fix_opid(tle->expr);
+ }
+ t_list = copyObject(expanded_tlist);
+
+ /* ------------------
+ * for "replace" or "delete" queries, add ctid of the result
+ * relation into the target list so that the ctid can get
+ * propogate through the execution and in the end ExecReplace()
+ * will find the right tuple to replace or delete. This
+ * extra field will be removed in ExecReplace().
+ * For convinient, we append this extra field to the end of
+ * the target list.
+ * ------------------
+ */
+ if (command_type == CMD_UPDATE || command_type == CMD_DELETE)
+ {
+ TargetEntry *ctid;
+ Resdom *resdom;
+ Var *var;
+
+ resdom = makeResdom(length(t_list) + 1,
+ 27,
+ 6,
+ "ctid",
+ 0,
+ 0,
+ 1);
+
+ var = makeVar(result_relation, -1, 27, result_relation, -1);
+
+ ctid = makeNode(TargetEntry);
+ ctid->resdom = resdom;
+ ctid->expr = (Node *) var;
+ t_list = lappend(t_list, ctid);
+ }
+
+ return (t_list);
}
/*****************************************************************************
*
- * TARGETLIST EXPANSION
+ * TARGETLIST EXPANSION
*
*****************************************************************************/
-/*
+/*
* expand-targetlist--
- * Given a target list as generated by the parser and a result relation,
- * add targetlist entries for the attributes which have not been used.
- *
- * XXX This code is only supposed to work with unnested relations.
- *
- * 'tlist' is the original target list
- * 'relid' is the relid of the result relation
- * 'command' is the update command
- *
+ * Given a target list as generated by the parser and a result relation,
+ * add targetlist entries for the attributes which have not been used.
+ *
+ * XXX This code is only supposed to work with unnested relations.
+ *
+ * 'tlist' is the original target list
+ * 'relid' is the relid of the result relation
+ * 'command' is the update command
+ *
* Returns the expanded target list, sorted in resno order.
*/
-static List *
-expand_targetlist(List *tlist,
- Oid relid,
- int command_type,
- Index result_relation)
+static List *
+expand_targetlist(List * tlist,
+ Oid relid,
+ int command_type,
+ Index result_relation)
{
- NodeTag node_type = T_Invalid;
-
- switch (command_type) {
- case CMD_INSERT:
- node_type = (NodeTag)T_Const;
- break;
- case CMD_UPDATE:
- node_type = (NodeTag)T_Var;
- break;
- }
-
- if(node_type != T_Invalid) {
- List *ntlist = new_relation_targetlist(relid,
- result_relation,
- node_type);
-
- return (replace_matching_resname(ntlist, tlist));
- } else {
- return (tlist);
- }
-
+ NodeTag node_type = T_Invalid;
+
+ switch (command_type)
+ {
+ case CMD_INSERT:
+ node_type = (NodeTag) T_Const;
+ break;
+ case CMD_UPDATE:
+ node_type = (NodeTag) T_Var;
+ break;
+ }
+
+ if (node_type != T_Invalid)
+ {
+ List *ntlist = new_relation_targetlist(relid,
+ result_relation,
+ node_type);
+
+ return (replace_matching_resname(ntlist, tlist));
+ }
+ else
+ {
+ return (tlist);
+ }
+
}
-static List *
-replace_matching_resname(List *new_tlist, List *old_tlist)
+static List *
+replace_matching_resname(List * new_tlist, List * old_tlist)
{
- List *temp, *i;
- List *t_list = NIL;
-
- foreach (i,new_tlist) {
- TargetEntry *new_tle = (TargetEntry *)lfirst(i);
- TargetEntry *matching_old_tl = NULL;
-
- foreach (temp, old_tlist) {
- TargetEntry *old_tle = (TargetEntry *)lfirst(temp);
-
- old_tle = lfirst(temp);
- if (!strcmp(old_tle->resdom->resname,
- new_tle->resdom->resname)) {
- matching_old_tl = old_tle;
- break;
- }
+ List *temp,
+ *i;
+ List *t_list = NIL;
+
+ foreach(i, new_tlist)
+ {
+ TargetEntry *new_tle = (TargetEntry *) lfirst(i);
+ TargetEntry *matching_old_tl = NULL;
+
+ foreach(temp, old_tlist)
+ {
+ TargetEntry *old_tle = (TargetEntry *) lfirst(temp);
+
+ old_tle = lfirst(temp);
+ if (!strcmp(old_tle->resdom->resname,
+ new_tle->resdom->resname))
+ {
+ matching_old_tl = old_tle;
+ break;
+ }
+ }
+
+ if (matching_old_tl)
+ {
+ matching_old_tl->resdom->resno =
+ new_tle->resdom->resno;
+ t_list = lappend(t_list, matching_old_tl);
+ }
+ else
+ {
+ t_list = lappend(t_list, new_tle);
+ }
}
-
- if(matching_old_tl) {
- matching_old_tl->resdom->resno =
- new_tle->resdom->resno;
- t_list = lappend(t_list, matching_old_tl);
- }
- else {
- t_list = lappend(t_list, new_tle);
- }
- }
-
- /*
- * It is possible that 'old_tlist' has some negative
- * attributes (i.e. negative resnos). This only happens
- * if this is a replace/append command and we explicitly
- * specify a system attribute. Of course this is not a very good
- * idea if this is a user query, but on the other hand the rule
- * manager uses this mechanism to replace rule locks.
- *
- * So, copy all these entries to the end of the target list
- * and set their 'resjunk' value to 1 to show that these are
- * special attributes and have to be treated specially by the
- * executor!
- */
- foreach (temp, old_tlist) {
- TargetEntry *old_tle, *new_tl;
- Resdom *newresno;
-
- old_tle = lfirst(temp);
- if (old_tle->resdom->resno < 0) {
- newresno = (Resdom*) copyObject((Node*)old_tle->resdom);
- newresno->resno = length(t_list) +1;
- newresno->resjunk = 1;
- new_tl = MakeTLE(newresno, old_tle->expr);
- t_list = lappend(t_list, new_tl);
+
+ /*
+ * It is possible that 'old_tlist' has some negative attributes (i.e.
+ * negative resnos). This only happens if this is a replace/append
+ * command and we explicitly specify a system attribute. Of course
+ * this is not a very good idea if this is a user query, but on the
+ * other hand the rule manager uses this mechanism to replace rule
+ * locks.
+ *
+ * So, copy all these entries to the end of the target list and set their
+ * 'resjunk' value to 1 to show that these are special attributes and
+ * have to be treated specially by the executor!
+ */
+ foreach(temp, old_tlist)
+ {
+ TargetEntry *old_tle,
+ *new_tl;
+ Resdom *newresno;
+
+ old_tle = lfirst(temp);
+ if (old_tle->resdom->resno < 0)
+ {
+ newresno = (Resdom *) copyObject((Node *) old_tle->resdom);
+ newresno->resno = length(t_list) + 1;
+ newresno->resjunk = 1;
+ new_tl = MakeTLE(newresno, old_tle->expr);
+ t_list = lappend(t_list, new_tl);
+ }
}
- }
- return (t_list);
+ return (t_list);
}
-/*
+/*
* new-relation-targetlist--
- * Generate a targetlist for the relation with relation OID 'relid'
- * and rangetable index 'rt-index'.
- *
- * Returns the new targetlist.
+ * Generate a targetlist for the relation with relation OID 'relid'
+ * and rangetable index 'rt-index'.
+ *
+ * Returns the new targetlist.
*/
-static List *
+static List *
new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type)
{
- AttrNumber attno;
- List *t_list = NIL;
- char *attname;
- Oid atttype = 0;
- int16 typlen = 0;
- bool attisset = false;
-/* Oid type_id; */
-/* type_id = RelationIdGetTypeId(relid); */
-
- for(attno=1; attno <= get_relnatts(relid); attno++) {
- attname = get_attname(/*type_id,*/ relid, attno);
- atttype = get_atttype(/*type_id,*/ relid, attno);
- /*
- * Since this is an append or replace, the size of any set
- * attribute is the size of the OID used to represent it.
- */
- attisset = get_attisset(/* type_id,*/ relid, attname);
- if (attisset) {
- typlen = tlen(type("oid"));
- } else {
- typlen = get_typlen(atttype);
- }
-
- switch (node_type) {
- case T_Const:
- {
- struct varlena *typedefault = get_typdefault(atttype);
- int temp = 0;
- Const *temp2 = (Const*)NULL;
- TargetEntry *temp3 = (TargetEntry *)NULL;
-
- if (typedefault==NULL)
- temp = 0;
- else
- temp = typlen;
-
- temp2 = makeConst (atttype,
- temp,
- (Datum)typedefault,
- (typedefault == (struct varlena *)NULL),
- /* XXX this is bullshit */
- false,
- false, /* not a set */
- false);
-
- temp3 = MakeTLE (makeResdom(attno,
- atttype,
- typlen,
- attname,
- 0,
- (Oid)0,
- 0),
- (Node*)temp2);
- t_list = lappend(t_list,temp3);
- break;
- }
- case T_Var:
- {
- Var *temp_var = (Var*)NULL;
- TargetEntry *temp_list = NULL;
-
- temp_var =
- makeVar(rt_index, attno, atttype, rt_index, attno);
-
- temp_list = MakeTLE(makeResdom(attno,
- atttype,
- typlen,
- attname,
- 0,
- (Oid)0,
- 0),
- (Node*)temp_var);
- t_list = lappend(t_list,temp_list);
- break;
- }
- default: /* do nothing */
- break;
- }
- }
+ AttrNumber attno;
+ List *t_list = NIL;
+ char *attname;
+ Oid atttype = 0;
+ int16 typlen = 0;
+ bool attisset = false;
- return(t_list);
-}
+/* Oid type_id; */
+/* type_id = RelationIdGetTypeId(relid); */
+
+ for (attno = 1; attno <= get_relnatts(relid); attno++)
+ {
+ attname = get_attname( /* type_id, */ relid, attno);
+ atttype = get_atttype( /* type_id, */ relid, attno);
+
+ /*
+ * Since this is an append or replace, the size of any set
+ * attribute is the size of the OID used to represent it.
+ */
+ attisset = get_attisset( /* type_id, */ relid, attname);
+ if (attisset)
+ {
+ typlen = tlen(type("oid"));
+ }
+ else
+ {
+ typlen = get_typlen(atttype);
+ }
+ switch (node_type)
+ {
+ case T_Const:
+ {
+ struct varlena *typedefault = get_typdefault(atttype);
+ int temp = 0;
+ Const *temp2 = (Const *) NULL;
+ TargetEntry *temp3 = (TargetEntry *) NULL;
+ if (typedefault == NULL)
+ temp = 0;
+ else
+ temp = typlen;
+
+ temp2 = makeConst(atttype,
+ temp,
+ (Datum) typedefault,
+ (typedefault == (struct varlena *) NULL),
+ /* XXX this is bullshit */
+ false,
+ false, /* not a set */
+ false);
+
+ temp3 = MakeTLE(makeResdom(attno,
+ atttype,
+ typlen,
+ attname,
+ 0,
+ (Oid) 0,
+ 0),
+ (Node *) temp2);
+ t_list = lappend(t_list, temp3);
+ break;
+ }
+ case T_Var:
+ {
+ Var *temp_var = (Var *) NULL;
+ TargetEntry *temp_list = NULL;
+
+ temp_var =
+ makeVar(rt_index, attno, atttype, rt_index, attno);
+
+ temp_list = MakeTLE(makeResdom(attno,
+ atttype,
+ typlen,
+ attname,
+ 0,
+ (Oid) 0,
+ 0),
+ (Node *) temp_var);
+ t_list = lappend(t_list, temp_list);
+ break;
+ }
+ default: /* do nothing */
+ break;
+ }
+ }
+
+ return (t_list);
+}
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 3142f37c07a..9bf282f8cc3 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* prepunion.c--
- * Routines to plan archive, inheritance, union, and version queries
+ * Routines to plan archive, inheritance, union, and version queries
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.3 1997/01/10 20:18:12 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.4 1997/09/07 04:44:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,370 +34,396 @@
#include "optimizer/planner.h"
#include "optimizer/prep.h"
-static List *plan_union_query(List *relids, Index rt_index,
- RangeTblEntry *rt_entry, Query *parse, UnionFlag flag,
- List **union_rtentriesPtr);
-static RangeTblEntry *new_rangetable_entry(Oid new_relid,
- RangeTblEntry *old_entry);
-static Query *subst_rangetable(Query *root, Index index,
- RangeTblEntry *new_entry);
-static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
- Oid new_relid, Query *parsetree);
-static Append *make_append(List *unionplans, Index rt_index,
- List *union_rt_entries, List *tlist);
+static List *
+plan_union_query(List * relids, Index rt_index,
+ RangeTblEntry * rt_entry, Query * parse, UnionFlag flag,
+ List ** union_rtentriesPtr);
+static RangeTblEntry *
+new_rangetable_entry(Oid new_relid,
+ RangeTblEntry * old_entry);
+static Query *
+subst_rangetable(Query * root, Index index,
+ RangeTblEntry * new_entry);
+static void
+fix_parsetree_attnums(Index rt_index, Oid old_relid,
+ Oid new_relid, Query * parsetree);
+static Append *
+make_append(List * unionplans, Index rt_index,
+ List * union_rt_entries, List * tlist);
-/*
+/*
* find-all-inheritors -
- * Returns a list of relids corresponding to relations that inherit
- * attributes from any relations listed in either of the argument relid
- * lists.
+ * Returns a list of relids corresponding to relations that inherit
+ * attributes from any relations listed in either of the argument relid
+ * lists.
*/
-List *
-find_all_inheritors(List *unexamined_relids,
- List *examined_relids)
+List *
+find_all_inheritors(List * unexamined_relids,
+ List * examined_relids)
{
- List *new_inheritors = NIL;
- List *new_examined_relids = NIL;
- List *new_unexamined_relids = NIL;
-
- /* Find all relations which inherit from members of
- * 'unexamined-relids' and store them in 'new-inheritors'.
- */
- List *rels = NIL;
- List *newrels = NIL;
-
- foreach(rels,unexamined_relids) {
- newrels = (List*)LispUnioni(find_inheritance_children(lfirsti(rels)),
- newrels);
- }
- new_inheritors = newrels;
-
- new_examined_relids = (List*)LispUnioni(examined_relids,unexamined_relids);
- new_unexamined_relids = set_differencei(new_inheritors,
- new_examined_relids);
-
- if (new_unexamined_relids==NULL) {
- return(new_examined_relids);
- } else {
- return (find_all_inheritors (new_unexamined_relids,
- new_examined_relids));
- }
+ List *new_inheritors = NIL;
+ List *new_examined_relids = NIL;
+ List *new_unexamined_relids = NIL;
+
+ /*
+ * Find all relations which inherit from members of
+ * 'unexamined-relids' and store them in 'new-inheritors'.
+ */
+ List *rels = NIL;
+ List *newrels = NIL;
+
+ foreach(rels, unexamined_relids)
+ {
+ newrels = (List *) LispUnioni(find_inheritance_children(lfirsti(rels)),
+ newrels);
+ }
+ new_inheritors = newrels;
+
+ new_examined_relids = (List *) LispUnioni(examined_relids, unexamined_relids);
+ new_unexamined_relids = set_differencei(new_inheritors,
+ new_examined_relids);
+
+ if (new_unexamined_relids == NULL)
+ {
+ return (new_examined_relids);
+ }
+ else
+ {
+ return (find_all_inheritors(new_unexamined_relids,
+ new_examined_relids));
+ }
}
-/*
+/*
* first-matching-rt-entry -
- * Given a rangetable, find the first rangetable entry that represents
- * the appropriate special case.
- *
- * Returns a rangetable index., Returns -1 if no matches
+ * Given a rangetable, find the first rangetable entry that represents
+ * the appropriate special case.
+ *
+ * Returns a rangetable index., Returns -1 if no matches
*/
int
-first_matching_rt_entry (List *rangetable, UnionFlag flag)
+first_matching_rt_entry(List * rangetable, UnionFlag flag)
{
- int count = 0;
- List *temp = NIL;
+ int count = 0;
+ List *temp = NIL;
- foreach(temp, rangetable) {
- RangeTblEntry *rt_entry = lfirst(temp);
-
- switch(flag) {
- case INHERITS_FLAG:
- if (rt_entry->inh)
- return count+1;
- break;
- case ARCHIVE_FLAG:
- if (rt_entry->archive)
- return count+1;
- break;
- default:
- break;
+ foreach(temp, rangetable)
+ {
+ RangeTblEntry *rt_entry = lfirst(temp);
+
+ switch (flag)
+ {
+ case INHERITS_FLAG:
+ if (rt_entry->inh)
+ return count + 1;
+ break;
+ case ARCHIVE_FLAG:
+ if (rt_entry->archive)
+ return count + 1;
+ break;
+ default:
+ break;
+ }
+ count++;
}
- count++;
- }
-
- return(-1);
+
+ return (-1);
}
-/*
+/*
* plan-union-queries--
- *
- * Plans the queries for a given parent relation.
- *
+ *
+ * Plans the queries for a given parent relation.
+ *
* Returns a list containing a list of plans and a list of rangetable
* entries to be inserted into an APPEND node.
* XXX - what exactly does this mean, look for make_append
*/
-Append *
+Append *
plan_union_queries(Index rt_index,
- Query *parse,
- UnionFlag flag)
+ Query * parse,
+ UnionFlag flag)
{
- List *rangetable = parse->rtable;
- RangeTblEntry *rt_entry = rt_fetch(rt_index,rangetable);
- List *union_relids = NIL;
- List *union_plans = NIL;
- List *union_rt_entries = NIL;
-
- switch (flag) {
- case INHERITS_FLAG:
- union_relids =
- find_all_inheritors(lconsi(rt_entry->relid,
- NIL),
- NIL);
- break;
-
-#if 0
- case UNION_FLAG:
+ List *rangetable = parse->rtable;
+ RangeTblEntry *rt_entry = rt_fetch(rt_index, rangetable);
+ List *union_relids = NIL;
+ List *union_plans = NIL;
+ List *union_rt_entries = NIL;
+
+ switch (flag)
{
- Index rt_index = 0;
- union_plans = handleunion(root,rangetable,tlist,qual);
- return (make_append (union_plans,
- rt_index, rangetable,
- ((Plan*)lfirst(union_plans))->targetlist ));
- }
- break;
+ case INHERITS_FLAG:
+ union_relids =
+ find_all_inheritors(lconsi(rt_entry->relid,
+ NIL),
+ NIL);
+ break;
+
+#if 0
+ case UNION_FLAG:
+ {
+ Index rt_index = 0;
+
+ union_plans = handleunion(root, rangetable, tlist, qual);
+ return (make_append(union_plans,
+ rt_index, rangetable,
+ ((Plan *) lfirst(union_plans))->targetlist));
+ }
+ break;
#endif
-
- case VERSION_FLAG:
- union_relids = VersionGetParents(rt_entry->relid);
- break;
-
- case ARCHIVE_FLAG:
- union_relids = find_archive_rels(rt_entry->relid);
- break;
-
- default:
- /* do nothing */
- break;
- }
-
- /*
- * Remove the flag for this relation, since we're about to handle it
- * (do it before recursing!).
- * XXX destructive parse tree change
- */
- switch(flag) {
- case INHERITS_FLAG:
- rt_fetch(rt_index,rangetable)->inh = false;
- break;
- case ARCHIVE_FLAG:
- rt_fetch(rt_index,rangetable)->archive = false;
- break;
- default:
- break;
- }
-
- /* XXX - can't find any reason to sort union-relids
- * as paul did, so we're leaving it out for now
- * (maybe forever) - jeff & lp
- *
- * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul.
- * -- ay 10/94.]
- */
- union_plans = plan_union_query(union_relids, rt_index, rt_entry,
- parse, flag, &union_rt_entries);
-
- return (make_append(union_plans,
- rt_index,
- union_rt_entries,
- ((Plan*)lfirst(union_plans))->targetlist));
+
+ case VERSION_FLAG:
+ union_relids = VersionGetParents(rt_entry->relid);
+ break;
+
+ case ARCHIVE_FLAG:
+ union_relids = find_archive_rels(rt_entry->relid);
+ break;
+
+ default:
+ /* do nothing */
+ break;
+ }
+
+ /*
+ * Remove the flag for this relation, since we're about to handle it
+ * (do it before recursing!). XXX destructive parse tree change
+ */
+ switch (flag)
+ {
+ case INHERITS_FLAG:
+ rt_fetch(rt_index, rangetable)->inh = false;
+ break;
+ case ARCHIVE_FLAG:
+ rt_fetch(rt_index, rangetable)->archive = false;
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * XXX - can't find any reason to sort union-relids as paul did, so
+ * we're leaving it out for now (maybe forever) - jeff & lp
+ *
+ * [maybe so. btw, jeff & lp did the lisp conversion, according to Paul.
+ * -- ay 10/94.]
+ */
+ union_plans = plan_union_query(union_relids, rt_index, rt_entry,
+ parse, flag, &union_rt_entries);
+
+ return (make_append(union_plans,
+ rt_index,
+ union_rt_entries,
+ ((Plan *) lfirst(union_plans))->targetlist));
}
-/*
+/*
* plan-union-query--
- * Returns a list of plans for 'relids' and a list of range table entries
- * in union_rtentries.
+ * Returns a list of plans for 'relids' and a list of range table entries
+ * in union_rtentries.
*/
-static List *
-plan_union_query(List *relids,
- Index rt_index,
- RangeTblEntry *rt_entry,
- Query *root,
- UnionFlag flag,
- List **union_rtentriesPtr)
+static List *
+plan_union_query(List * relids,
+ Index rt_index,
+ RangeTblEntry * rt_entry,
+ Query * root,
+ UnionFlag flag,
+ List ** union_rtentriesPtr)
{
- List *i;
- List *union_plans = NIL;
- List *union_rtentries = NIL;
-
- foreach (i, relids) {
- int relid = lfirsti(i);
- RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
- rt_entry);
- Query *new_root = subst_rangetable(root,
- rt_index,
- new_rt_entry);
-
- /* reset the uniqueflag and sortclause in parse tree root, so that
- * sorting will only be done once after append
- */
-/* new_root->uniqueFlag = false; */
- new_root->uniqueFlag = NULL;
- new_root->sortClause = NULL;
- if (flag == ARCHIVE_FLAG) {
- /*
- * the entire union query uses the same (most recent) schema.
- * to do otherwise would require either ragged tuples or careful
- * archiving and interpretation of pg_attribute...
- */
- } else {
- fix_parsetree_attnums(rt_index,
- rt_entry->relid,
- relid,
- new_root);
- }
+ List *i;
+ List *union_plans = NIL;
+ List *union_rtentries = NIL;
- union_plans = lappend(union_plans, planner(new_root));
- union_rtentries = lappend(union_rtentries, new_rt_entry);
- }
+ foreach(i, relids)
+ {
+ int relid = lfirsti(i);
+ RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
+ rt_entry);
+ Query *new_root = subst_rangetable(root,
+ rt_index,
+ new_rt_entry);
+
+ /*
+ * reset the uniqueflag and sortclause in parse tree root, so that
+ * sorting will only be done once after append
+ */
+/* new_root->uniqueFlag = false; */
+ new_root->uniqueFlag = NULL;
+ new_root->sortClause = NULL;
+ if (flag == ARCHIVE_FLAG)
+ {
+
+ /*
+ * the entire union query uses the same (most recent) schema.
+ * to do otherwise would require either ragged tuples or
+ * careful archiving and interpretation of pg_attribute...
+ */
+ }
+ else
+ {
+ fix_parsetree_attnums(rt_index,
+ rt_entry->relid,
+ relid,
+ new_root);
+ }
+
+ union_plans = lappend(union_plans, planner(new_root));
+ union_rtentries = lappend(union_rtentries, new_rt_entry);
+ }
- *union_rtentriesPtr = union_rtentries;
- return(union_plans);
+ *union_rtentriesPtr = union_rtentries;
+ return (union_plans);
}
-/*
+/*
* new-rangetable-entry -
- * Replaces the name and relid of 'old-entry' with the values for
- * 'new-relid'.
- *
- * Returns a copy of 'old-entry' with the parameters substituted.
+ * Replaces the name and relid of 'old-entry' with the values for
+ * 'new-relid'.
+ *
+ * Returns a copy of 'old-entry' with the parameters substituted.
*/
static RangeTblEntry *
-new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
+new_rangetable_entry(Oid new_relid, RangeTblEntry * old_entry)
{
- RangeTblEntry *new_entry = copyObject(old_entry);
+ RangeTblEntry *new_entry = copyObject(old_entry);
- /* ??? someone tell me what the following is doing! - ay 11/94 */
- if (!strcmp(new_entry->refname, "*CURRENT*") ||
- !strcmp(new_entry->refname, "*NEW*"))
- new_entry->refname = get_rel_name(new_relid);
- else
- new_entry->relname = get_rel_name(new_relid);
+ /* ??? someone tell me what the following is doing! - ay 11/94 */
+ if (!strcmp(new_entry->refname, "*CURRENT*") ||
+ !strcmp(new_entry->refname, "*NEW*"))
+ new_entry->refname = get_rel_name(new_relid);
+ else
+ new_entry->relname = get_rel_name(new_relid);
- new_entry->relid = new_relid;
- return(new_entry);
+ new_entry->relid = new_relid;
+ return (new_entry);
}
-/*
+/*
* subst-rangetable--
- * Replaces the 'index'th rangetable entry in 'root' with 'new-entry'.
- *
+ * Replaces the 'index'th rangetable entry in 'root' with 'new-entry'.
+ *
* Returns a new copy of 'root'.
*/
-static Query *
-subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry)
+static Query *
+subst_rangetable(Query * root, Index index, RangeTblEntry * new_entry)
{
- Query *new_root = copyObject(root);
- List *temp = NIL;
- int i = 0;
+ Query *new_root = copyObject(root);
+ List *temp = NIL;
+ int i = 0;
- for(temp = new_root->rtable,i =1; i < index; temp =lnext(temp),i++)
- ;
- lfirst(temp) = new_entry;
+ for (temp = new_root->rtable, i = 1; i < index; temp = lnext(temp), i++)
+ ;
+ lfirst(temp) = new_entry;
- return (new_root);
+ return (new_root);
}
static void
fix_parsetree_attnums_nodes(Index rt_index,
- Oid old_relid,
- Oid new_relid,
- Node *node)
+ Oid old_relid,
+ Oid new_relid,
+ Node * node)
{
- if (node==NULL)
- return;
-
- switch(nodeTag(node)) {
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *)node;
-
- fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
- tle->expr);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr *)node;
- fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
- (Node*)expr->args);
- }
- break;
- case T_Var:
- {
- Var *var = (Var *)node;
- Oid old_typeid, new_typeid;
-
-/* old_typeid = RelationIdGetTypeId(old_relid);*/
-/* new_typeid = RelationIdGetTypeId(new_relid);*/
- old_typeid = old_relid;
- new_typeid = new_relid;
-
- if (var->varno == rt_index && var->varattno != 0) {
- var->varattno =
- get_attnum(new_typeid,
- get_attname(old_typeid, var->varattno));
- }
- }
- break;
- case T_List:
+ if (node == NULL)
+ return;
+
+ switch (nodeTag(node))
{
- List *l;
- foreach(l, (List*)node) {
- fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
- (Node*)lfirst(l));
- }
+ case T_TargetEntry:
+ {
+ TargetEntry *tle = (TargetEntry *) node;
+
+ fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
+ tle->expr);
+ }
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) node;
+
+ fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
+ (Node *) expr->args);
+ }
+ break;
+ case T_Var:
+ {
+ Var *var = (Var *) node;
+ Oid old_typeid,
+ new_typeid;
+
+/* old_typeid = RelationIdGetTypeId(old_relid);*/
+/* new_typeid = RelationIdGetTypeId(new_relid);*/
+ old_typeid = old_relid;
+ new_typeid = new_relid;
+
+ if (var->varno == rt_index && var->varattno != 0)
+ {
+ var->varattno =
+ get_attnum(new_typeid,
+ get_attname(old_typeid, var->varattno));
+ }
+ }
+ break;
+ case T_List:
+ {
+ List *l;
+
+ foreach(l, (List *) node)
+ {
+ fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
+ (Node *) lfirst(l));
+ }
+ }
+ break;
+ default:
+ break;
}
- break;
- default:
- break;
- }
}
-
-/*
+
+/*
* fix-parsetree-attnums--
- * Replaces attribute numbers from the relation represented by
- * 'old-relid' in 'parsetree' with the attribute numbers from
- * 'new-relid'.
- *
+ * Replaces attribute numbers from the relation represented by
+ * 'old-relid' in 'parsetree' with the attribute numbers from
+ * 'new-relid'.
+ *
* Returns the destructively-modified parsetree.
- *
+ *
*/
static void
fix_parsetree_attnums(Index rt_index,
- Oid old_relid,
- Oid new_relid,
- Query *parsetree)
+ Oid old_relid,
+ Oid new_relid,
+ Query * parsetree)
{
- if (old_relid == new_relid)
- return;
+ if (old_relid == new_relid)
+ return;
- fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
- (Node*)parsetree->targetList);
- fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
- parsetree->qual);
+ fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
+ (Node *) parsetree->targetList);
+ fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
+ parsetree->qual);
}
-static Append *
-make_append(List *unionplans,
- Index rt_index,
- List *union_rt_entries,
- List *tlist)
+static Append *
+make_append(List * unionplans,
+ Index rt_index,
+ List * union_rt_entries,
+ List * tlist)
{
- Append *node = makeNode(Append);
-
- node->unionplans = unionplans;
- node->unionrelid = rt_index;
- node->unionrtentries = union_rt_entries;
- node->plan.cost = 0.0;
- node->plan.state = (EState*)NULL;
- node->plan.targetlist = tlist;
- node->plan.qual = NIL;
- node->plan.lefttree = (Plan*)NULL;
- node->plan.righttree = (Plan*)NULL;
-
- return(node);
+ Append *node = makeNode(Append);
+
+ node->unionplans = unionplans;
+ node->unionrelid = rt_index;
+ node->unionrtentries = union_rt_entries;
+ node->plan.cost = 0.0;
+ node->plan.state = (EState *) NULL;
+ node->plan.targetlist = tlist;
+ node->plan.qual = NIL;
+ node->plan.lefttree = (Plan *) NULL;
+ node->plan.righttree = (Plan *) NULL;
+
+ return (node);
}
diff --git a/src/backend/optimizer/util/clauseinfo.c b/src/backend/optimizer/util/clauseinfo.c
index 2d648eb3605..e5fd2b7e5bb 100644
--- a/src/backend/optimizer/util/clauseinfo.c
+++ b/src/backend/optimizer/util/clauseinfo.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* clauseinfo.c--
- * ClauseInfo node manipulation routines.
+ * ClauseInfo node manipulation routines.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/clauseinfo.c,v 1.3 1996/07/31 18:47:06 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/clauseinfo.c,v 1.4 1997/09/07 04:44:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,167 +20,172 @@
#include "optimizer/clauses.h"
#include "optimizer/clauseinfo.h"
-/*
+/*
* valid-or-clause--
- *
+ *
* Returns t iff the clauseinfo node contains a 'normal' 'or' clause.
- *
+ *
*/
bool
-valid_or_clause(CInfo *clauseinfo)
+valid_or_clause(CInfo * clauseinfo)
{
- if (clauseinfo != NULL &&
- !single_node((Node*)clauseinfo->clause) &&
- !clauseinfo->notclause &&
- or_clause((Node*)clauseinfo->clause))
- return(true);
- else
- return(false);
+ if (clauseinfo != NULL &&
+ !single_node((Node *) clauseinfo->clause) &&
+ !clauseinfo->notclause &&
+ or_clause((Node *) clauseinfo->clause))
+ return (true);
+ else
+ return (false);
}
-/*
+/*
* get-actual-clauses--
- *
+ *
* Returns a list containing the clauses from 'clauseinfo-list'.
- *
+ *
*/
-List *
-get_actual_clauses(List *clauseinfo_list)
+List *
+get_actual_clauses(List * clauseinfo_list)
{
- List *temp = NIL;
- List *result = NIL;
- CInfo *clause = (CInfo *)NULL;
-
- foreach(temp,clauseinfo_list) {
- clause = (CInfo *)lfirst(temp);
- result = lappend(result,clause->clause);
- }
- return(result);
+ List *temp = NIL;
+ List *result = NIL;
+ CInfo *clause = (CInfo *) NULL;
+
+ foreach(temp, clauseinfo_list)
+ {
+ clause = (CInfo *) lfirst(temp);
+ result = lappend(result, clause->clause);
+ }
+ return (result);
}
-/*
+/*
* XXX NOTE:
- * The following routines must return their contents in the same order
- * (e.g., the first clause's info should be first, and so on) or else
- * get_index_sel() won't work.
- *
+ * The following routines must return their contents in the same order
+ * (e.g., the first clause's info should be first, and so on) or else
+ * get_index_sel() won't work.
+ *
*/
-/*
+/*
* get_relattvals--
- * For each member of a list of clauseinfo nodes to be used with an
- * index, create a vectori-long specifying:
- * the attnos,
- * the values of the clause constants, and
- * flags indicating the type and location of the constant within
- * each clause.
- * Each clause is of the form (op var some_type_of_constant), thus the
- * flag indicating whether the constant is on the left or right should
- * always be *SELEC-CONSTANT-RIGHT*.
- *
+ * For each member of a list of clauseinfo nodes to be used with an
+ * index, create a vectori-long specifying:
+ * the attnos,
+ * the values of the clause constants, and
+ * flags indicating the type and location of the constant within
+ * each clause.
+ * Each clause is of the form (op var some_type_of_constant), thus the
+ * flag indicating whether the constant is on the left or right should
+ * always be *SELEC-CONSTANT-RIGHT*.
+ *
* 'clauseinfo-list' is a list of clauseinfo nodes
- *
+ *
* Returns a list of vectori-longs.
- *
+ *
*/
void
-get_relattvals(List *clauseinfo_list,
- List **attnos,
- List **values,
- List **flags)
+get_relattvals(List * clauseinfo_list,
+ List ** attnos,
+ List ** values,
+ List ** flags)
{
- List *result1 = NIL;
- List *result2 = NIL;
- List *result3 = NIL;
- CInfo *temp = (CInfo *)NULL;
- List *i = NIL;
-
- foreach (i,clauseinfo_list) {
- int dummy;
- AttrNumber attno;
- Datum constval;
- int flag;
-
- temp = (CInfo *)lfirst(i);
- get_relattval((Node*)temp->clause, &dummy, &attno, &constval, &flag);
- result1 = lappendi(result1, (int)attno);
- result2 = lappendi(result2, constval);
- result3 = lappendi(result3, flag);
- }
+ List *result1 = NIL;
+ List *result2 = NIL;
+ List *result3 = NIL;
+ CInfo *temp = (CInfo *) NULL;
+ List *i = NIL;
+
+ foreach(i, clauseinfo_list)
+ {
+ int dummy;
+ AttrNumber attno;
+ Datum constval;
+ int flag;
+
+ temp = (CInfo *) lfirst(i);
+ get_relattval((Node *) temp->clause, &dummy, &attno, &constval, &flag);
+ result1 = lappendi(result1, (int) attno);
+ result2 = lappendi(result2, constval);
+ result3 = lappendi(result3, flag);
+ }
- *attnos = result1;
- *values = result2;
- *flags = result3;
- return;
+ *attnos = result1;
+ *values = result2;
+ *flags = result3;
+ return;
}
-/*
+/*
* get_joinvars --
- * Given a list of join clauseinfo nodes to be used with the index
- * of an inner join relation, return three lists consisting of:
- * the attributes corresponding to the inner join relation
- * the value of the inner var clause (always "")
- * whether the attribute appears on the left or right side of
- * the operator.
- *
+ * Given a list of join clauseinfo nodes to be used with the index
+ * of an inner join relation, return three lists consisting of:
+ * the attributes corresponding to the inner join relation
+ * the value of the inner var clause (always "")
+ * whether the attribute appears on the left or right side of
+ * the operator.
+ *
* 'relid' is the inner join relation
* 'clauseinfo-list' is a list of qualification clauses to be used with
- * 'rel'
- *
+ * 'rel'
+ *
*/
void
get_joinvars(Oid relid,
- List *clauseinfo_list,
- List **attnos,
- List **values,
- List **flags)
+ List * clauseinfo_list,
+ List ** attnos,
+ List ** values,
+ List ** flags)
{
- List *result1 = NIL;
- List *result2 = NIL;
- List *result3 = NIL;
- List *temp;
-
- foreach(temp, clauseinfo_list) {
- CInfo *clauseinfo = lfirst(temp);
- Expr *clause = clauseinfo->clause;
-
- if( IsA (get_leftop(clause),Var) &&
- (relid == (get_leftop(clause))->varno)) {
- result1 = lappendi(result1, (int4)(get_leftop(clause))->varattno);
- result2 = lappend(result2, "");
- result3 = lappendi(result3, _SELEC_CONSTANT_RIGHT_);
- } else {
- result1 = lappendi(result1, (int4)(get_rightop(clause))->varattno);
- result2 = lappend(result2, "");
- result3 = lappendi(result3, _SELEC_CONSTANT_LEFT_);
+ List *result1 = NIL;
+ List *result2 = NIL;
+ List *result3 = NIL;
+ List *temp;
+
+ foreach(temp, clauseinfo_list)
+ {
+ CInfo *clauseinfo = lfirst(temp);
+ Expr *clause = clauseinfo->clause;
+
+ if (IsA(get_leftop(clause), Var) &&
+ (relid == (get_leftop(clause))->varno))
+ {
+ result1 = lappendi(result1, (int4) (get_leftop(clause))->varattno);
+ result2 = lappend(result2, "");
+ result3 = lappendi(result3, _SELEC_CONSTANT_RIGHT_);
+ }
+ else
+ {
+ result1 = lappendi(result1, (int4) (get_rightop(clause))->varattno);
+ result2 = lappend(result2, "");
+ result3 = lappendi(result3, _SELEC_CONSTANT_LEFT_);
+ }
}
- }
- *attnos = result1;
- *values = result2;
- *flags = result3;
- return;
+ *attnos = result1;
+ *values = result2;
+ *flags = result3;
+ return;
}
-/*
+/*
* get_opnos--
- * Create and return a list containing the clause operators of each member
- * of a list of clauseinfo nodes to be used with an index.
- *
+ * Create and return a list containing the clause operators of each member
+ * of a list of clauseinfo nodes to be used with an index.
+ *
*/
-List *
-get_opnos(List *clauseinfo_list)
+List *
+get_opnos(List * clauseinfo_list)
{
- CInfo *temp = (CInfo *)NULL;
- List *result = NIL;
- List *i = NIL;
-
- foreach(i,clauseinfo_list) {
- temp = (CInfo *)lfirst(i);
- result =
- lappendi(result,
- (((Oper*)temp->clause->oper)->opno));
- }
- return(result);
+ CInfo *temp = (CInfo *) NULL;
+ List *result = NIL;
+ List *i = NIL;
+
+ foreach(i, clauseinfo_list)
+ {
+ temp = (CInfo *) lfirst(i);
+ result =
+ lappendi(result,
+ (((Oper *) temp->clause->oper)->opno));
+ }
+ return (result);
}
-
-
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 153c11f9f42..03e0856ef09 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* clauses.c--
- * routines to manipulate qualification clauses
+ * routines to manipulate qualification clauses
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.7 1997/08/19 21:31:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.8 1997/09/07 04:44:20 momjian Exp $
*
* HISTORY
- * AUTHOR DATE MAJOR EVENT
- * Andrew Yu Nov 3, 1994 clause.c and clauses.c combined
+ * AUTHOR DATE MAJOR EVENT
+ * Andrew Yu Nov 3, 1994 clause.c and clauses.c combined
*
*-------------------------------------------------------------------------
*/
@@ -34,533 +34,556 @@
#include "optimizer/internal.h"
#include "optimizer/var.h"
-static bool agg_clause(Node *clause);
+static bool agg_clause(Node * clause);
-Expr *
-make_clause(int type, Node *oper, List *args)
+Expr *
+make_clause(int type, Node * oper, List * args)
{
- if (type == AND_EXPR || type == OR_EXPR || type == NOT_EXPR ||
- type == OP_EXPR || type == FUNC_EXPR) {
- Expr *expr = makeNode(Expr);
-
- /*
- * assume type checking already done and we don't need the type of
- * the expr any more.
- */
- expr->typeOid = InvalidOid;
- expr->opType = type;
- expr->oper = oper; /* ignored for AND, OR, NOT */
- expr->args = args;
- return expr;
- }else {
- /* will this ever happen? translated from lispy C code - ay 10/94 */
- return((Expr*)args);
- }
+ if (type == AND_EXPR || type == OR_EXPR || type == NOT_EXPR ||
+ type == OP_EXPR || type == FUNC_EXPR)
+ {
+ Expr *expr = makeNode(Expr);
+
+ /*
+ * assume type checking already done and we don't need the type of
+ * the expr any more.
+ */
+ expr->typeOid = InvalidOid;
+ expr->opType = type;
+ expr->oper = oper; /* ignored for AND, OR, NOT */
+ expr->args = args;
+ return expr;
+ }
+ else
+ {
+ /* will this ever happen? translated from lispy C code - ay 10/94 */
+ return ((Expr *) args);
+ }
}
/*****************************************************************************
- * OPERATOR clause functions
+ * OPERATOR clause functions
*****************************************************************************/
-/*
+/*
* is_opclause--
- *
+ *
* Returns t iff the clause is an operator clause:
- * (op expr expr) or (op expr).
+ * (op expr expr) or (op expr).
*
* [historical note: is_clause has the exact functionality and is used
- * throughout the code. They're renamed to is_opclause for clarity.
- * - ay 10/94.]
+ * throughout the code. They're renamed to is_opclause for clarity.
+ * - ay 10/94.]
*/
bool
-is_opclause(Node *clause)
+is_opclause(Node * clause)
{
- return
- (clause!=NULL &&
- nodeTag(clause)==T_Expr && ((Expr*)clause)->opType==OP_EXPR);
+ return
+ (clause != NULL &&
+ nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == OP_EXPR);
}
-/*
+/*
* make_opclause--
- * Creates a clause given its operator left operand and right
- * operand (if it is non-null).
- *
+ * Creates a clause given its operator left operand and right
+ * operand (if it is non-null).
+ *
*/
-Expr *
-make_opclause(Oper *op, Var *leftop, Var *rightop)
+Expr *
+make_opclause(Oper * op, Var * leftop, Var * rightop)
{
- Expr *expr = makeNode(Expr);
+ Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = OP_EXPR;
- expr->oper = (Node*)op;
- expr->args = makeList(leftop, rightop, -1);
- return expr;
+ expr->typeOid = InvalidOid; /* assume type checking done */
+ expr->opType = OP_EXPR;
+ expr->oper = (Node *) op;
+ expr->args = makeList(leftop, rightop, -1);
+ return expr;
}
-/*
+/*
* get_leftop--
- *
+ *
* Returns the left operand of a clause of the form (op expr expr)
- * or (op expr)
- * NB: it is assumed (for now) that all expr must be Var nodes
+ * or (op expr)
+ * NB: it is assumed (for now) that all expr must be Var nodes
*/
-Var *
-get_leftop(Expr *clause)
+Var *
+get_leftop(Expr * clause)
{
- if (clause->args!=NULL)
- return(lfirst(clause->args));
- else
- return NULL;
+ if (clause->args != NULL)
+ return (lfirst(clause->args));
+ else
+ return NULL;
}
-/*
+/*
* get_rightop
- *
+ *
* Returns the right operand in a clause of the form (op expr expr).
- *
+ *
*/
-Var *
-get_rightop(Expr *clause)
+Var *
+get_rightop(Expr * clause)
{
- if (clause->args!=NULL && lnext(clause->args)!=NULL)
- return (lfirst(lnext(clause->args)));
- else
- return NULL;
+ if (clause->args != NULL && lnext(clause->args) != NULL)
+ return (lfirst(lnext(clause->args)));
+ else
+ return NULL;
}
/*****************************************************************************
- * AGG clause functions
+ * AGG clause functions
*****************************************************************************/
-static bool
-agg_clause(Node *clause)
+static bool
+agg_clause(Node * clause)
{
- return
- (clause!=NULL && nodeTag(clause)==T_Aggreg);
+ return
+ (clause != NULL && nodeTag(clause) == T_Aggreg);
}
/*****************************************************************************
- * FUNC clause functions
+ * FUNC clause functions
*****************************************************************************/
-/*
+/*
* is_funcclause--
- *
+ *
* Returns t iff the clause is a function clause: (func { expr }).
- *
+ *
*/
bool
-is_funcclause(Node *clause)
+is_funcclause(Node * clause)
{
- return
- (clause!=NULL &&
- nodeTag(clause)==T_Expr && ((Expr*)clause)->opType==FUNC_EXPR);
+ return
+ (clause != NULL &&
+ nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == FUNC_EXPR);
}
-/*
+/*
* make_funcclause--
- *
+ *
* Creates a function clause given the FUNC node and the functional
* arguments.
- *
+ *
*/
-Expr *
-make_funcclause(Func *func, List *funcargs)
+Expr *
+make_funcclause(Func * func, List * funcargs)
{
- Expr *expr = makeNode(Expr);
+ Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = FUNC_EXPR;
- expr->oper = (Node*)func;
- expr->args = funcargs;
- return expr;
+ expr->typeOid = InvalidOid; /* assume type checking done */
+ expr->opType = FUNC_EXPR;
+ expr->oper = (Node *) func;
+ expr->args = funcargs;
+ return expr;
}
/*****************************************************************************
- * OR clause functions
+ * OR clause functions
*****************************************************************************/
-/*
+/*
* or_clause--
- *
+ *
* Returns t iff the clause is an 'or' clause: (OR { expr }).
- *
+ *
*/
bool
-or_clause(Node *clause)
+or_clause(Node * clause)
{
- return
- (clause!=NULL &&
- nodeTag(clause)==T_Expr && ((Expr*)clause)->opType==OR_EXPR);
+ return
+ (clause != NULL &&
+ nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == OR_EXPR);
}
-/*
+/*
* make_orclause--
- *
+ *
* Creates an 'or' clause given a list of its subclauses.
- *
+ *
*/
-Expr *
-make_orclause(List *orclauses)
+Expr *
+make_orclause(List * orclauses)
{
- Expr *expr = makeNode(Expr);
+ Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = OR_EXPR;
- expr->oper = NULL;
- expr->args = orclauses;
- return expr;
+ expr->typeOid = InvalidOid; /* assume type checking done */
+ expr->opType = OR_EXPR;
+ expr->oper = NULL;
+ expr->args = orclauses;
+ return expr;
}
/*****************************************************************************
- * NOT clause functions
+ * NOT clause functions
*****************************************************************************/
-/*
+/*
* not_clause--
- *
+ *
* Returns t iff this is a 'not' clause: (NOT expr).
- *
+ *
*/
bool
-not_clause(Node *clause)
+not_clause(Node * clause)
{
- return
- (clause!=NULL &&
- nodeTag(clause)==T_Expr && ((Expr*)clause)->opType == NOT_EXPR);
+ return
+ (clause != NULL &&
+ nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == NOT_EXPR);
}
-/*
+/*
* make_notclause--
- *
+ *
* Create a 'not' clause given the expression to be negated.
- *
+ *
*/
-Expr *
-make_notclause(Expr *notclause)
+Expr *
+make_notclause(Expr * notclause)
{
- Expr *expr = makeNode(Expr);
+ Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = NOT_EXPR;
- expr->oper = NULL;
- expr->args = lcons(notclause, NIL);
- return expr;
+ expr->typeOid = InvalidOid; /* assume type checking done */
+ expr->opType = NOT_EXPR;
+ expr->oper = NULL;
+ expr->args = lcons(notclause, NIL);
+ return expr;
}
-/*
+/*
* get_notclausearg--
- *
+ *
* Retrieve the clause within a 'not' clause
- *
+ *
*/
-Expr *
-get_notclausearg(Expr *notclause)
+Expr *
+get_notclausearg(Expr * notclause)
{
- return(lfirst(notclause->args));
+ return (lfirst(notclause->args));
}
/*****************************************************************************
- * AND clause functions
+ * AND clause functions
*****************************************************************************/
-/*
+/*
* and_clause--
- *
+ *
* Returns t iff its argument is an 'and' clause: (AND { expr }).
- *
+ *
*/
bool
-and_clause(Node *clause)
+and_clause(Node * clause)
{
- return
- (clause!=NULL &&
- nodeTag(clause)==T_Expr && ((Expr*)clause)->opType == AND_EXPR);
+ return
+ (clause != NULL &&
+ nodeTag(clause) == T_Expr && ((Expr *) clause)->opType == AND_EXPR);
}
-/*
+
+/*
* make_andclause--
- *
+ *
* Create an 'and' clause given its arguments in a list.
- *
+ *
*/
-Expr *
-make_andclause(List *andclauses)
+Expr *
+make_andclause(List * andclauses)
{
- Expr *expr = makeNode(Expr);
+ Expr *expr = makeNode(Expr);
- expr->typeOid = InvalidOid; /* assume type checking done */
- expr->opType = AND_EXPR;
- expr->oper = NULL;
- expr->args = andclauses;
- return expr;
+ expr->typeOid = InvalidOid; /* assume type checking done */
+ expr->opType = AND_EXPR;
+ expr->oper = NULL;
+ expr->args = andclauses;
+ return expr;
}
/*****************************************************************************
- * *
- * *
- * *
+ * *
+ * *
+ * *
*****************************************************************************/
-/*
+/*
* pull-constant-clauses--
- * Scans through a list of qualifications and find those that
- * contain no variables.
- *
+ * Scans through a list of qualifications and find those that
+ * contain no variables.
+ *
* Returns a list of the constant clauses in constantQual and the remaining
* quals as the return value.
- *
+ *
*/
-List *
-pull_constant_clauses(List *quals, List **constantQual)
+List *
+pull_constant_clauses(List * quals, List ** constantQual)
{
- List *q;
- List *constqual=NIL;
- List *restqual=NIL;
-
- foreach(q, quals) {
- if (!contain_var_clause(lfirst(q))) {
- constqual = lcons(lfirst(q), constqual);
- }else {
- restqual = lcons(lfirst(q), restqual);
+ List *q;
+ List *constqual = NIL;
+ List *restqual = NIL;
+
+ foreach(q, quals)
+ {
+ if (!contain_var_clause(lfirst(q)))
+ {
+ constqual = lcons(lfirst(q), constqual);
+ }
+ else
+ {
+ restqual = lcons(lfirst(q), restqual);
+ }
}
- }
- freeList(quals);
- *constantQual = constqual;
- return restqual;
+ freeList(quals);
+ *constantQual = constqual;
+ return restqual;
}
-/*
+/*
* clause-relids-vars--
- * Retrieves relids and vars appearing within a clause.
- * Returns ((relid1 relid2 ... relidn) (var1 var2 ... varm)) where
- * vars appear in the clause this is done by recursively searching
- * through the left and right operands of a clause.
- *
+ * Retrieves relids and vars appearing within a clause.
+ * Returns ((relid1 relid2 ... relidn) (var1 var2 ... varm)) where
+ * vars appear in the clause this is done by recursively searching
+ * through the left and right operands of a clause.
+ *
* Returns the list of relids and vars.
- *
+ *
* XXX take the nreverse's out later
- *
+ *
*/
void
-clause_relids_vars(Node *clause, List **relids, List **vars)
+clause_relids_vars(Node * clause, List ** relids, List ** vars)
{
- List *clvars = pull_var_clause(clause);
- List *var_list = NIL;
- List *varno_list = NIL;
- List *i = NIL;
+ List *clvars = pull_var_clause(clause);
+ List *var_list = NIL;
+ List *varno_list = NIL;
+ List *i = NIL;
- foreach (i, clvars) {
- Var *var = (Var *)lfirst(i);
- List *vi;
-
- if (!intMember(var->varno, varno_list)) {
- varno_list = lappendi(varno_list, var->varno);
- }
- foreach (vi, var_list)
+ foreach(i, clvars)
{
- Var *in_list = (Var *)lfirst(vi);
-
- if ( in_list->varno == var->varno &&
- in_list->varattno == var->varattno )
- break;
+ Var *var = (Var *) lfirst(i);
+ List *vi;
+
+ if (!intMember(var->varno, varno_list))
+ {
+ varno_list = lappendi(varno_list, var->varno);
+ }
+ foreach(vi, var_list)
+ {
+ Var *in_list = (Var *) lfirst(vi);
+
+ if (in_list->varno == var->varno &&
+ in_list->varattno == var->varattno)
+ break;
+ }
+ if (vi == NIL)
+ var_list = lappend(var_list, var);
}
- if ( vi == NIL )
- var_list = lappend(var_list, var);
- }
- *relids = varno_list;
- *vars = var_list;
- return;
+ *relids = varno_list;
+ *vars = var_list;
+ return;
}
-/*
+/*
* NumRelids--
- * (formerly clause-relids)
- *
+ * (formerly clause-relids)
+ *
* Returns the number of different relations referenced in 'clause'.
*/
int
-NumRelids(Node *clause)
+NumRelids(Node * clause)
{
- List *vars = pull_var_clause(clause);
- List *i = NIL;
- List *var_list = NIL;
+ List *vars = pull_var_clause(clause);
+ List *i = NIL;
+ List *var_list = NIL;
- foreach (i, vars) {
- Var *var = (Var *)lfirst(i);
+ foreach(i, vars)
+ {
+ Var *var = (Var *) lfirst(i);
- if (!intMember(var->varno, var_list)) {
- var_list = lconsi(var->varno, var_list);
+ if (!intMember(var->varno, var_list))
+ {
+ var_list = lconsi(var->varno, var_list);
+ }
}
- }
- return(length(var_list));
+ return (length(var_list));
}
-/*
+/*
* contains-not--
*
* Returns t iff the clause is a 'not' clause or if any of the
* subclauses within an 'or' clause contain 'not's.
- *
+ *
*/
bool
-contains_not(Node *clause)
+contains_not(Node * clause)
{
- if (single_node(clause))
- return (false);
-
- if (not_clause(clause))
- return (true);
+ if (single_node(clause))
+ return (false);
- if (or_clause(clause)) {
- List *a;
- foreach(a, ((Expr*)clause)->args) {
- if (contains_not(lfirst(a)))
+ if (not_clause(clause))
return (true);
+
+ if (or_clause(clause))
+ {
+ List *a;
+
+ foreach(a, ((Expr *) clause)->args)
+ {
+ if (contains_not(lfirst(a)))
+ return (true);
+ }
}
- }
-
- return(false);
+
+ return (false);
}
-/*
+/*
* join-clause-p--
- *
+ *
* Returns t iff 'clause' is a valid join clause.
- *
+ *
*/
bool
-join_clause_p(Node *clause)
+join_clause_p(Node * clause)
{
- Node *leftop, *rightop;
+ Node *leftop,
+ *rightop;
- if (!is_opclause(clause))
- return false;
+ if (!is_opclause(clause))
+ return false;
- leftop = (Node*)get_leftop((Expr*)clause);
- rightop = (Node*)get_rightop((Expr*)clause);
+ leftop = (Node *) get_leftop((Expr *) clause);
+ rightop = (Node *) get_rightop((Expr *) clause);
- /*
- * One side of the clause (i.e. left or right operands)
- * must either be a var node ...
- */
- if (IsA(leftop,Var) || IsA(rightop,Var))
- return true;
+ /*
+ * One side of the clause (i.e. left or right operands) must either be
+ * a var node ...
+ */
+ if (IsA(leftop, Var) || IsA(rightop, Var))
+ return true;
- /*
- * ... or a func node.
- */
- if (is_funcclause(leftop) || is_funcclause(rightop))
- return(true);
+ /*
+ * ... or a func node.
+ */
+ if (is_funcclause(leftop) || is_funcclause(rightop))
+ return (true);
- return(false);
+ return (false);
}
-/*
+/*
* qual-clause-p--
- *
+ *
* Returns t iff 'clause' is a valid qualification clause.
- *
+ *
*/
bool
-qual_clause_p(Node *clause)
+qual_clause_p(Node * clause)
{
- if (!is_opclause(clause))
- return false;
+ if (!is_opclause(clause))
+ return false;
- if (IsA (get_leftop((Expr*)clause),Var) &&
- IsA (get_rightop((Expr*)clause),Const))
+ if (IsA(get_leftop((Expr *) clause), Var) &&
+ IsA(get_rightop((Expr *) clause), Const))
{
- return(true);
+ return (true);
}
- else if (IsA (get_rightop((Expr*)clause),Var) &&
- IsA (get_leftop((Expr*)clause),Const))
+ else if (IsA(get_rightop((Expr *) clause), Var) &&
+ IsA(get_leftop((Expr *) clause), Const))
{
- return(true);
+ return (true);
}
- return(false);
+ return (false);
}
-/*
+/*
* fix-opid--
- * Calculate the opfid from the opno...
- *
+ * Calculate the opfid from the opno...
+ *
* Returns nothing.
- *
+ *
*/
void
-fix_opid(Node *clause)
+fix_opid(Node * clause)
{
- if (clause==NULL || single_node(clause)) {
- ;
- }
- else if (or_clause (clause)) {
- fix_opids(((Expr*)clause)->args);
- }
- else if (is_funcclause (clause)) {
- fix_opids(((Expr*)clause)->args);
- }
- else if (IsA(clause,ArrayRef)) {
- ArrayRef *aref = (ArrayRef *)clause;
-
- fix_opids(aref->refupperindexpr);
- fix_opids(aref->reflowerindexpr);
- fix_opid(aref->refexpr);
- fix_opid(aref->refassgnexpr);
- }
- else if (not_clause(clause)) {
- fix_opid((Node*)get_notclausearg((Expr*)clause));
- }
- else if (is_opclause (clause)) {
- replace_opid((Oper*)((Expr*)clause)->oper);
- fix_opid((Node*)get_leftop((Expr*)clause));
- fix_opid((Node*)get_rightop((Expr*)clause));
- }
- else if (agg_clause (clause)) {
- fix_opid (((Aggreg*)clause)->target);
- }
+ if (clause == NULL || single_node(clause))
+ {
+ ;
+ }
+ else if (or_clause(clause))
+ {
+ fix_opids(((Expr *) clause)->args);
+ }
+ else if (is_funcclause(clause))
+ {
+ fix_opids(((Expr *) clause)->args);
+ }
+ else if (IsA(clause, ArrayRef))
+ {
+ ArrayRef *aref = (ArrayRef *) clause;
+
+ fix_opids(aref->refupperindexpr);
+ fix_opids(aref->reflowerindexpr);
+ fix_opid(aref->refexpr);
+ fix_opid(aref->refassgnexpr);
+ }
+ else if (not_clause(clause))
+ {
+ fix_opid((Node *) get_notclausearg((Expr *) clause));
+ }
+ else if (is_opclause(clause))
+ {
+ replace_opid((Oper *) ((Expr *) clause)->oper);
+ fix_opid((Node *) get_leftop((Expr *) clause));
+ fix_opid((Node *) get_rightop((Expr *) clause));
+ }
+ else if (agg_clause(clause))
+ {
+ fix_opid(((Aggreg *) clause)->target);
+ }
}
-/*
+/*
* fix-opids--
- * Calculate the opfid from the opno for all the clauses...
- *
+ * Calculate the opfid from the opno for all the clauses...
+ *
* Returns its argument.
- *
+ *
*/
-List *
-fix_opids(List *clauses)
+List *
+fix_opids(List * clauses)
{
- List *clause;
+ List *clause;
- foreach(clause, clauses)
- fix_opid(lfirst(clause));
+ foreach(clause, clauses)
+ fix_opid(lfirst(clause));
- return(clauses);
+ return (clauses);
}
-/*
+/*
* get_relattval--
- * For a non-join clause, returns a list consisting of the
- * relid,
- * attno,
- * value of the CONST node (if any), and a
- * flag indicating whether the value appears on the left or right
- * of the operator and whether the value varied.
+ * For a non-join clause, returns a list consisting of the
+ * relid,
+ * attno,
+ * value of the CONST node (if any), and a
+ * flag indicating whether the value appears on the left or right
+ * of the operator and whether the value varied.
*
* OLD OBSOLETE COMMENT FOLLOWS:
- * If 'clause' is not of the format (op var node) or (op node var),
- * or if the var refers to a nested attribute, then -1's are returned for
- * everything but the value a blank string "" (pointer to \0) is
- * returned for the value if it is unknown or null.
+ * If 'clause' is not of the format (op var node) or (op node var),
+ * or if the var refers to a nested attribute, then -1's are returned for
+ * everything but the value a blank string "" (pointer to \0) is
+ * returned for the value if it is unknown or null.
* END OF OLD OBSOLETE COMMENT.
* NEW COMMENT:
* when defining rules one of the attibutes of the operator can
@@ -569,198 +592,223 @@ fix_opids(List *clauses)
* this routine used to return "" as value, which made 'compute_selec'
* to bomb (because it was expecting a lisp integer and got back a lisp
* string). Now the code returns a plain old good "lispInteger(0)".
- *
+ *
*/
void
-get_relattval(Node *clause,
- int *relid,
- AttrNumber *attno,
- Datum *constval,
- int *flag)
+get_relattval(Node * clause,
+ int *relid,
+ AttrNumber * attno,
+ Datum * constval,
+ int *flag)
{
- Var *left = get_leftop((Expr*)clause);
- Var *right = get_rightop((Expr*)clause);
-
- if(is_opclause(clause) && IsA(left,Var) &&
- IsA(right,Const)) {
-
- if(right!=NULL) {
-
- *relid = left->varno;
- *attno = left->varattno;
- *constval = ((Const *)right)->constvalue;
- *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
-
- } else {
-
- *relid = left->varno;
- *attno = left->varattno;
- *constval = 0;
- *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_NOT_CONSTANT_);
-
- }
+ Var *left = get_leftop((Expr *) clause);
+ Var *right = get_rightop((Expr *) clause);
+
+ if (is_opclause(clause) && IsA(left, Var) &&
+ IsA(right, Const))
+ {
+
+ if (right != NULL)
+ {
+
+ *relid = left->varno;
+ *attno = left->varattno;
+ *constval = ((Const *) right)->constvalue;
+ *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
+
+ }
+ else
+ {
+
+ *relid = left->varno;
+ *attno = left->varattno;
+ *constval = 0;
+ *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_NOT_CONSTANT_);
+
+ }
#ifdef INDEXSCAN_PATCH
- } else if (is_opclause(clause) && IsA(left,Var) && IsA(right,Param)) {
- /* Function parameter used as index scan arg. DZ - 27-8-1996 */
- *relid = left->varno;
- *attno = left->varattno;
- *constval = 0;
- *flag = (_SELEC_NOT_CONSTANT_);
+ }
+ else if (is_opclause(clause) && IsA(left, Var) && IsA(right, Param))
+ {
+ /* Function parameter used as index scan arg. DZ - 27-8-1996 */
+ *relid = left->varno;
+ *attno = left->varattno;
+ *constval = 0;
+ *flag = (_SELEC_NOT_CONSTANT_);
#endif
- }else if (is_opclause(clause) &&
- is_funcclause((Node*)left) &&
- IsA(right,Const)) {
- List *args = ((Expr*)left)->args;
+ }
+ else if (is_opclause(clause) &&
+ is_funcclause((Node *) left) &&
+ IsA(right, Const))
+ {
+ List *args = ((Expr *) left)->args;
+
+
+ *relid = ((Var *) lfirst(args))->varno;
+ *attno = InvalidAttrNumber;
+ *constval = ((Const *) right)->constvalue;
+ *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
+
+ /*
+ * XXX both of these func clause handling if's seem wrong to me.
+ * they assume that the first argument is the Var. It could not
+ * handle (for example) f(1, emp.name). I think I may have been
+ * assuming no constants in functional index scans when I
+ * implemented this originally (still currently true). -mer 10 Aug
+ * 1992
+ */
+ }
+ else if (is_opclause(clause) &&
+ is_funcclause((Node *) right) &&
+ IsA(left, Const))
+ {
+ List *args = ((Expr *) right)->args;
+ *relid = ((Var *) lfirst(args))->varno;
+ *attno = InvalidAttrNumber;
+ *constval = ((Const *) left)->constvalue;
+ *flag = (_SELEC_IS_CONSTANT_);
- *relid = ((Var*)lfirst(args))->varno;
- *attno = InvalidAttrNumber;
- *constval = ((Const*)right)->constvalue;
- *flag = (_SELEC_CONSTANT_RIGHT_ | _SELEC_IS_CONSTANT_);
-
- /*
- * XXX both of these func clause handling if's seem wrong to me.
- * they assume that the first argument is the Var. It could
- * not handle (for example) f(1, emp.name). I think I may have
- * been assuming no constants in functional index scans when I
- * implemented this originally (still currently true).
- * -mer 10 Aug 1992
- */
- } else if (is_opclause(clause) &&
- is_funcclause((Node*)right) &&
- IsA(left,Const)) {
- List *args = ((Expr*)right)->args;
-
- *relid = ((Var*)lfirst(args))->varno;
- *attno = InvalidAttrNumber;
- *constval = ((Const*)left)->constvalue;
- *flag = ( _SELEC_IS_CONSTANT_);
-
- } else if (is_opclause (clause) && IsA (right,Var) &&
- IsA (left,Const)) {
- if (left!=NULL) {
-
- *relid = right->varno;
- *attno = right->varattno;
- *constval = ((Const*)left)->constvalue;
- *flag = (_SELEC_IS_CONSTANT_);
- } else {
-
- *relid = right->varno;
- *attno = right->varattno;
- *constval = 0;
- *flag = (_SELEC_NOT_CONSTANT_);
- }
+ }
+ else if (is_opclause(clause) && IsA(right, Var) &&
+ IsA(left, Const))
+ {
+ if (left != NULL)
+ {
+
+ *relid = right->varno;
+ *attno = right->varattno;
+ *constval = ((Const *) left)->constvalue;
+ *flag = (_SELEC_IS_CONSTANT_);
+ }
+ else
+ {
+
+ *relid = right->varno;
+ *attno = right->varattno;
+ *constval = 0;
+ *flag = (_SELEC_NOT_CONSTANT_);
+ }
#ifdef INDEXSCAN_PATCH
- } else if (is_opclause(clause) && IsA(right,Var) && IsA(left,Param)) {
- /* ...And here... - vadim 01/22/97 */
- *relid = right->varno;
- *attno = right->varattno;
- *constval = 0;
- *flag = (_SELEC_NOT_CONSTANT_);
+ }
+ else if (is_opclause(clause) && IsA(right, Var) && IsA(left, Param))
+ {
+ /* ...And here... - vadim 01/22/97 */
+ *relid = right->varno;
+ *attno = right->varattno;
+ *constval = 0;
+ *flag = (_SELEC_NOT_CONSTANT_);
#endif
- } else {
- /* One or more of the operands are expressions
- * (e.g., oper clauses)
- */
- *relid = _SELEC_VALUE_UNKNOWN_;
- *attno = _SELEC_VALUE_UNKNOWN_;
- *constval = 0;
- *flag = (_SELEC_NOT_CONSTANT_);
- }
+ }
+ else
+ {
+
+ /*
+ * One or more of the operands are expressions (e.g., oper
+ * clauses)
+ */
+ *relid = _SELEC_VALUE_UNKNOWN_;
+ *attno = _SELEC_VALUE_UNKNOWN_;
+ *constval = 0;
+ *flag = (_SELEC_NOT_CONSTANT_);
+ }
}
-/*
+/*
* get_relsatts--
- *
- * Returns a list
- * ( relid1 attno1 relid2 attno2 )
- * for a joinclause.
- *
+ *
+ * Returns a list
+ * ( relid1 attno1 relid2 attno2 )
+ * for a joinclause.
+ *
* If the clause is not of the form (op var var) or if any of the vars
* refer to nested attributes, then -1's are returned.
- *
+ *
*/
void
-get_rels_atts(Node *clause,
- int *relid1,
- AttrNumber *attno1,
- int *relid2,
- AttrNumber *attno2)
+get_rels_atts(Node * clause,
+ int *relid1,
+ AttrNumber * attno1,
+ int *relid2,
+ AttrNumber * attno2)
{
- Var *left = get_leftop((Expr*)clause);
- Var *right = get_rightop((Expr*)clause);
- bool var_left = (IsA(left,Var));
- bool var_right = (IsA(right,Var));
- bool varexpr_left = (bool)((IsA(left,Func) || IsA (left,Oper)) &&
- contain_var_clause((Node*)left));
- bool varexpr_right = (bool)(( IsA(right,Func) || IsA (right,Oper)) &&
- contain_var_clause((Node*)right));
-
- if (is_opclause(clause)) {
- if(var_left && var_right) {
-
- *relid1 = left->varno;
- *attno1 = left->varoattno;
- *relid2 = right->varno;
- *attno2 = right->varoattno;
- return;
- } else if (var_left && varexpr_right ) {
-
- *relid1 = left->varno;
- *attno1 = left->varoattno;
- *relid2 = _SELEC_VALUE_UNKNOWN_;
- *attno2 = _SELEC_VALUE_UNKNOWN_;
- return;
- } else if (varexpr_left && var_right) {
-
- *relid1 = _SELEC_VALUE_UNKNOWN_;
- *attno1 = _SELEC_VALUE_UNKNOWN_;
- *relid2 = right->varno;
- *attno2 = right->varoattno;
- return;
+ Var *left = get_leftop((Expr *) clause);
+ Var *right = get_rightop((Expr *) clause);
+ bool var_left = (IsA(left, Var));
+ bool var_right = (IsA(right, Var));
+ bool varexpr_left = (bool) ((IsA(left, Func) || IsA(left, Oper)) &&
+ contain_var_clause((Node *) left));
+ bool varexpr_right = (bool) ((IsA(right, Func) || IsA(right, Oper)) &&
+ contain_var_clause((Node *) right));
+
+ if (is_opclause(clause))
+ {
+ if (var_left && var_right)
+ {
+
+ *relid1 = left->varno;
+ *attno1 = left->varoattno;
+ *relid2 = right->varno;
+ *attno2 = right->varoattno;
+ return;
+ }
+ else if (var_left && varexpr_right)
+ {
+
+ *relid1 = left->varno;
+ *attno1 = left->varoattno;
+ *relid2 = _SELEC_VALUE_UNKNOWN_;
+ *attno2 = _SELEC_VALUE_UNKNOWN_;
+ return;
+ }
+ else if (varexpr_left && var_right)
+ {
+
+ *relid1 = _SELEC_VALUE_UNKNOWN_;
+ *attno1 = _SELEC_VALUE_UNKNOWN_;
+ *relid2 = right->varno;
+ *attno2 = right->varoattno;
+ return;
+ }
}
- }
- *relid1 = _SELEC_VALUE_UNKNOWN_;
- *attno1 = _SELEC_VALUE_UNKNOWN_;
- *relid2 = _SELEC_VALUE_UNKNOWN_;
- *attno2 = _SELEC_VALUE_UNKNOWN_;
- return;
+ *relid1 = _SELEC_VALUE_UNKNOWN_;
+ *attno1 = _SELEC_VALUE_UNKNOWN_;
+ *relid2 = _SELEC_VALUE_UNKNOWN_;
+ *attno2 = _SELEC_VALUE_UNKNOWN_;
+ return;
}
void
-CommuteClause(Node *clause)
+CommuteClause(Node * clause)
{
- Node *temp;
- Oper *commu;
- OperatorTupleForm commuTup;
- HeapTuple heapTup;
+ Node *temp;
+ Oper *commu;
+ OperatorTupleForm commuTup;
+ HeapTuple heapTup;
- if (!is_opclause(clause))
- return;
+ if (!is_opclause(clause))
+ return;
- heapTup = (HeapTuple)
- get_operator_tuple(get_commutator(((Oper*)((Expr*)clause)->oper)->opno));
+ heapTup = (HeapTuple)
+ get_operator_tuple(get_commutator(((Oper *) ((Expr *) clause)->oper)->opno));
- if (heapTup == (HeapTuple)NULL)
- return;
+ if (heapTup == (HeapTuple) NULL)
+ return;
- commuTup = (OperatorTupleForm)GETSTRUCT(heapTup);
-
- commu = makeOper(heapTup->t_oid,
- InvalidOid,
- commuTup->oprresult,
- ((Oper*)((Expr*)clause)->oper)->opsize,
- NULL);
-
- /*
- * reform the clause -> (operator func/var constant)
- */
- ((Expr*)clause)->oper = (Node*)commu;
- temp = lfirst(((Expr*)clause)->args);
- lfirst(((Expr*)clause)->args) = lsecond(((Expr*)clause)->args);
- lsecond(((Expr*)clause)->args) = temp;
-}
+ commuTup = (OperatorTupleForm) GETSTRUCT(heapTup);
+ commu = makeOper(heapTup->t_oid,
+ InvalidOid,
+ commuTup->oprresult,
+ ((Oper *) ((Expr *) clause)->oper)->opsize,
+ NULL);
+ /*
+ * reform the clause -> (operator func/var constant)
+ */
+ ((Expr *) clause)->oper = (Node *) commu;
+ temp = lfirst(((Expr *) clause)->args);
+ lfirst(((Expr *) clause)->args) = lsecond(((Expr *) clause)->args);
+ lsecond(((Expr *) clause)->args) = temp;
+}
diff --git a/src/backend/optimizer/util/indexnode.c b/src/backend/optimizer/util/indexnode.c
index 8e9237e6845..e6a1902f8b9 100644
--- a/src/backend/optimizer/util/indexnode.c
+++ b/src/backend/optimizer/util/indexnode.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* indexnode.c--
- * Routines to find all indices on a relation
+ * Routines to find all indices on a relation
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.2 1996/10/31 10:59:37 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.3 1997/09/07 04:44:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,74 +21,77 @@
#include "optimizer/internal.h"
#include "optimizer/plancat.h"
-#include "optimizer/pathnode.h" /* where the decls go */
+#include "optimizer/pathnode.h" /* where the decls go */
-static List *find_secondary_index(Query *root, Oid relid);
+static List *find_secondary_index(Query * root, Oid relid);
-/*
+/*
* find-relation-indices--
- * Returns a list of index nodes containing appropriate information for
- * each (secondary) index defined on a relation.
- *
+ * Returns a list of index nodes containing appropriate information for
+ * each (secondary) index defined on a relation.
+ *
*/
-List *
-find_relation_indices(Query *root, Rel *rel)
+List *
+find_relation_indices(Query * root, Rel * rel)
{
- if (rel->indexed) {
- return (find_secondary_index(root, lfirsti(rel->relids)));
- } else {
- return (NIL);
- }
+ if (rel->indexed)
+ {
+ return (find_secondary_index(root, lfirsti(rel->relids)));
+ }
+ else
+ {
+ return (NIL);
+ }
}
-/*
+/*
* find-secondary-index--
- * Creates a list of index path nodes containing information for each
- * secondary index defined on a relation by searching through the index
- * catalog.
- *
+ * Creates a list of index path nodes containing information for each
+ * secondary index defined on a relation by searching through the index
+ * catalog.
+ *
* 'relid' is the OID of the relation for which indices are being located
- *
+ *
* Returns a list of new index nodes.
- *
+ *
*/
-static List *
-find_secondary_index(Query *root, Oid relid)
+static List *
+find_secondary_index(Query * root, Oid relid)
{
- IdxInfoRetval indexinfo;
- List *indexes = NIL;
- bool first = TRUE;
+ IdxInfoRetval indexinfo;
+ List *indexes = NIL;
+ bool first = TRUE;
- while (index_info(root, first, relid,&indexinfo)) {
- Rel *indexnode = makeNode(Rel);
+ while (index_info(root, first, relid, &indexinfo))
+ {
+ Rel *indexnode = makeNode(Rel);
- indexnode->relids = lconsi(indexinfo.relid,NIL);
- indexnode->relam = indexinfo.relam;
- indexnode->pages = indexinfo.pages;
- indexnode->tuples = indexinfo.tuples;
- indexnode->indexkeys = indexinfo.indexkeys;
- indexnode->ordering = indexinfo.orderOprs;
- indexnode->classlist = indexinfo.classlist;
- indexnode->indproc= indexinfo.indproc;
- indexnode->indpred = (List*)indexinfo.indpred;
-
- indexnode->indexed= false; /* not indexed itself */
- indexnode->size = 0;
- indexnode->width= 0;
- indexnode->targetlist= NIL;
- indexnode->pathlist= NIL;
- indexnode->unorderedpath= NULL;
- indexnode->cheapestpath= NULL;
- indexnode->pruneable= true;
- indexnode->clauseinfo= NIL;
- indexnode->joininfo= NIL;
- indexnode->innerjoin= NIL;
+ indexnode->relids = lconsi(indexinfo.relid, NIL);
+ indexnode->relam = indexinfo.relam;
+ indexnode->pages = indexinfo.pages;
+ indexnode->tuples = indexinfo.tuples;
+ indexnode->indexkeys = indexinfo.indexkeys;
+ indexnode->ordering = indexinfo.orderOprs;
+ indexnode->classlist = indexinfo.classlist;
+ indexnode->indproc = indexinfo.indproc;
+ indexnode->indpred = (List *) indexinfo.indpred;
- indexes = lcons(indexnode, indexes);
- first = FALSE;
- }
+ indexnode->indexed = false; /* not indexed itself */
+ indexnode->size = 0;
+ indexnode->width = 0;
+ indexnode->targetlist = NIL;
+ indexnode->pathlist = NIL;
+ indexnode->unorderedpath = NULL;
+ indexnode->cheapestpath = NULL;
+ indexnode->pruneable = true;
+ indexnode->clauseinfo = NIL;
+ indexnode->joininfo = NIL;
+ indexnode->innerjoin = NIL;
- return indexes;
-}
+ indexes = lcons(indexnode, indexes);
+ first = FALSE;
+ }
+ return indexes;
+}
diff --git a/src/backend/optimizer/util/internal.c b/src/backend/optimizer/util/internal.c
index 8b2dfd43bcb..d1af2062fce 100644
--- a/src/backend/optimizer/util/internal.c
+++ b/src/backend/optimizer/util/internal.c
@@ -1,24 +1,24 @@
/*-------------------------------------------------------------------------
*
* internal.c--
- * Definitions required throughout the query optimizer.
+ * Definitions required throughout the query optimizer.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/internal.c,v 1.3 1997/08/20 14:53:37 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/internal.c,v 1.4 1997/09/07 04:44:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-/*
- * ---------- SHARED MACROS
- *
- * Macros common to modules for creating, accessing, and modifying
- * query tree and query plan components.
- * Shared with the executor.
- *
+/*
+ * ---------- SHARED MACROS
+ *
+ * Macros common to modules for creating, accessing, and modifying
+ * query tree and query plan components.
+ * Shared with the executor.
+ *
*/
#include <sys/types.h>
@@ -31,32 +31,30 @@
#include "nodes/primnodes.h"
#include "utils/palloc.h"
-#ifdef NOT_USED
+#ifdef NOT_USED
/*****************************************************************************
*
*****************************************************************************/
/* the following should probably be moved elsewhere -ay */
-TargetEntry *
-MakeTLE(Resdom *resdom, Node *expr)
+TargetEntry *
+MakeTLE(Resdom * resdom, Node * expr)
{
- TargetEntry *rt = makeNode(TargetEntry);
- rt->resdom = resdom;
- rt->expr = expr;
- return rt;
+ TargetEntry *rt = makeNode(TargetEntry);
+
+ rt->resdom = resdom;
+ rt->expr = expr;
+ return rt;
}
-Var *
-get_expr(TargetEntry *tle)
+Var *
+get_expr(TargetEntry * tle)
{
- Assert(tle!=NULL);
- Assert(tle->expr!=NULL);
+ Assert(tle != NULL);
+ Assert(tle->expr != NULL);
- return ((Var *)tle->expr);
+ return ((Var *) tle->expr);
}
-#endif /* 0 */
-
-
-
+#endif /* 0 */
diff --git a/src/backend/optimizer/util/joininfo.c b/src/backend/optimizer/util/joininfo.c
index a4fd6913752..cf206d80094 100644
--- a/src/backend/optimizer/util/joininfo.c
+++ b/src/backend/optimizer/util/joininfo.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* joininfo.c--
- * JoinInfo node manipulation routines
+ * JoinInfo node manipulation routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.2 1996/11/10 03:01:00 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/joininfo.c,v 1.3 1997/09/07 04:44:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,88 +21,96 @@
#include "optimizer/clauses.h"
-/*
+/*
* joininfo-member--
- * Determines whether a node has already been created for a join
- * between a set of join relations and the relation described by
- * 'joininfo-list'.
- *
+ * Determines whether a node has already been created for a join
+ * between a set of join relations and the relation described by
+ * 'joininfo-list'.
+ *
* 'join-relids' is a list of relids corresponding to the join relation
- * 'joininfo-list' is the list of joininfo nodes against which this is
- * checked
- *
+ * 'joininfo-list' is the list of joininfo nodes against which this is
+ * checked
+ *
* Returns the corresponding node in 'joininfo-list' if such a node
* exists.
- *
+ *
*/
-JInfo *
-joininfo_member(List *join_relids, List *joininfo_list)
+JInfo *
+joininfo_member(List * join_relids, List * joininfo_list)
{
- List *i = NIL;
- List *other_rels = NIL;
+ List *i = NIL;
+ List *other_rels = NIL;
- foreach(i,joininfo_list) {
- other_rels = lfirst(i);
- if(same(join_relids, ((JInfo*)other_rels)->otherrels))
- return((JInfo*)other_rels);
- }
- return((JInfo*)NULL);
+ foreach(i, joininfo_list)
+ {
+ other_rels = lfirst(i);
+ if (same(join_relids, ((JInfo *) other_rels)->otherrels))
+ return ((JInfo *) other_rels);
+ }
+ return ((JInfo *) NULL);
}
-/*
+/*
* find-joininfo-node--
- * Find the joininfo node within a relation entry corresponding
- * to a join between 'this_rel' and the relations in 'join-relids'. A
- * new node is created and added to the relation entry's joininfo
- * field if the desired one can't be found.
- *
+ * Find the joininfo node within a relation entry corresponding
+ * to a join between 'this_rel' and the relations in 'join-relids'. A
+ * new node is created and added to the relation entry's joininfo
+ * field if the desired one can't be found.
+ *
* Returns a joininfo node.
- *
+ *
*/
-JInfo *
-find_joininfo_node(Rel *this_rel, List *join_relids)
+JInfo *
+find_joininfo_node(Rel * this_rel, List * join_relids)
{
- JInfo *joininfo = joininfo_member(join_relids,
- this_rel->joininfo);
- if( joininfo == NULL ) {
- joininfo = makeNode(JInfo);
- joininfo->otherrels = join_relids;
- joininfo->jinfoclauseinfo = NIL;
- joininfo->mergesortable = false;
- joininfo->hashjoinable = false;
- joininfo->inactive = false;
- this_rel->joininfo = lcons(joininfo, this_rel->joininfo);
- }
- return(joininfo);
+ JInfo *joininfo = joininfo_member(join_relids,
+ this_rel->joininfo);
+
+ if (joininfo == NULL)
+ {
+ joininfo = makeNode(JInfo);
+ joininfo->otherrels = join_relids;
+ joininfo->jinfoclauseinfo = NIL;
+ joininfo->mergesortable = false;
+ joininfo->hashjoinable = false;
+ joininfo->inactive = false;
+ this_rel->joininfo = lcons(joininfo, this_rel->joininfo);
+ }
+ return (joininfo);
}
-/*
+/*
* other-join-clause-var--
- * Determines whether a var node is contained within a joinclause
- * of the form(op var var).
- *
+ * Determines whether a var node is contained within a joinclause
+ * of the form(op var var).
+ *
* Returns the other var node in the joinclause if it is, nil if not.
- *
+ *
*/
-Var *
-other_join_clause_var(Var *var, Expr *clause)
+Var *
+other_join_clause_var(Var * var, Expr * clause)
{
- Var *retval;
- Var *l, *r;
+ Var *retval;
+ Var *l,
+ *r;
- retval = (Var*) NULL;
+ retval = (Var *) NULL;
- if( var != NULL && join_clause_p((Node*)clause)) {
- l = (Var *) get_leftop(clause);
- r = (Var *) get_rightop(clause);
+ if (var != NULL && join_clause_p((Node *) clause))
+ {
+ l = (Var *) get_leftop(clause);
+ r = (Var *) get_rightop(clause);
- if(var_equal(var, l)) {
- retval = r;
- } else if(var_equal(var, r)) {
- retval = l;
- }
- }
+ if (var_equal(var, l))
+ {
+ retval = r;
+ }
+ else if (var_equal(var, r))
+ {
+ retval = l;
+ }
+ }
- return(retval);
+ return (retval);
}
diff --git a/src/backend/optimizer/util/keys.c b/src/backend/optimizer/util/keys.c
index 4296deb7e98..0c3a3569eb5 100644
--- a/src/backend/optimizer/util/keys.c
+++ b/src/backend/optimizer/util/keys.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* keys.c--
- * Key manipulation routines
+ * Key manipulation routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/keys.c,v 1.2 1997/08/19 21:32:03 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/keys.c,v 1.3 1997/09/07 04:44:28 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,173 +22,180 @@
#include "optimizer/tlist.h"
-static Expr *matching2_tlvar(int var, List *tlist, bool (*test)());
-static bool equal_indexkey_var(int index_key, Var *var);
+static Expr *matching2_tlvar(int var, List * tlist, bool(*test) ());
+static bool equal_indexkey_var(int index_key, Var * var);
-/*
+/*
* 1. index key
- * one of:
- * attnum
- * (attnum arrayindex)
+ * one of:
+ * attnum
+ * (attnum arrayindex)
* 2. path key
- * (subkey1 ... subkeyN)
- * where subkeyI is a var node
- * note that the 'Keys field is a list of these
+ * (subkey1 ... subkeyN)
+ * where subkeyI is a var node
+ * note that the 'Keys field is a list of these
* 3. join key
- * (outer-subkey inner-subkey)
- * where each subkey is a var node
+ * (outer-subkey inner-subkey)
+ * where each subkey is a var node
* 4. sort key
- * one of:
- * SortKey node
- * number
- * nil
- * (may also refer to the 'SortKey field of a SortKey node,
- * which looks exactly like an index key)
- *
+ * one of:
+ * SortKey node
+ * number
+ * nil
+ * (may also refer to the 'SortKey field of a SortKey node,
+ * which looks exactly like an index key)
+ *
*/
-/*
+/*
* match-indexkey-operand--
- * Returns t iff an index key 'index-key' matches the given clause
- * operand.
- *
+ * Returns t iff an index key 'index-key' matches the given clause
+ * operand.
+ *
*/
bool
-match_indexkey_operand(int indexkey, Var *operand, Rel *rel)
+match_indexkey_operand(int indexkey, Var * operand, Rel * rel)
{
- if (IsA (operand,Var) &&
- (lfirsti(rel->relids) == operand->varno) &&
- equal_indexkey_var(indexkey,operand))
- return(true);
- else
- return(false);
+ if (IsA(operand, Var) &&
+ (lfirsti(rel->relids) == operand->varno) &&
+ equal_indexkey_var(indexkey, operand))
+ return (true);
+ else
+ return (false);
}
-/*
+/*
* equal_indexkey_var--
- * Returns t iff an index key 'index-key' matches the corresponding
- * fields of var node 'var'.
- *
+ * Returns t iff an index key 'index-key' matches the corresponding
+ * fields of var node 'var'.
+ *
*/
-static bool
-equal_indexkey_var(int index_key, Var *var)
+static bool
+equal_indexkey_var(int index_key, Var * var)
{
- if (index_key == var->varattno)
- return(true);
- else
- return(false);
+ if (index_key == var->varattno)
+ return (true);
+ else
+ return (false);
}
-/*
+/*
* extract-subkey--
- * Returns the subkey in a join key corresponding to the outer or inner
- * lelation.
- *
+ * Returns the subkey in a join key corresponding to the outer or inner
+ * lelation.
+ *
*/
-Var *
-extract_subkey(JoinKey *jk, int which_subkey)
+Var *
+extract_subkey(JoinKey * jk, int which_subkey)
{
- Var *retval;
-
- switch (which_subkey) {
- case OUTER:
- retval = jk->outer;
- break;
- case INNER:
- retval = jk->inner;
- break;
- default: /* do nothing */
- elog(DEBUG,"extract_subkey with neither INNER or OUTER");
- retval = NULL;
- }
- return(retval);
+ Var *retval;
+
+ switch (which_subkey)
+ {
+ case OUTER:
+ retval = jk->outer;
+ break;
+ case INNER:
+ retval = jk->inner;
+ break;
+ default: /* do nothing */
+ elog(DEBUG, "extract_subkey with neither INNER or OUTER");
+ retval = NULL;
+ }
+ return (retval);
}
-/*
+/*
* samekeys--
- * Returns t iff two sets of path keys are equivalent. They are
- * equivalent if the first subkey (var node) within each sublist of
- * list 'keys1' is contained within the corresponding sublist of 'keys2'.
- *
- * XXX It isn't necessary to check that each sublist exactly contain
- * the same elements because if the routine that built these
- * sublists together is correct, having one element in common
- * implies having all elements in common.
- *
+ * Returns t iff two sets of path keys are equivalent. They are
+ * equivalent if the first subkey (var node) within each sublist of
+ * list 'keys1' is contained within the corresponding sublist of 'keys2'.
+ *
+ * XXX It isn't necessary to check that each sublist exactly contain
+ * the same elements because if the routine that built these
+ * sublists together is correct, having one element in common
+ * implies having all elements in common.
+ *
*/
bool
-samekeys(List *keys1, List *keys2)
+samekeys(List * keys1, List * keys2)
{
- bool allmember = true;
- List *key1, *key2;
-
- for(key1=keys1,key2=keys2 ; key1 != NIL && key2 !=NIL ;
- key1=lnext(key1), key2=lnext(key2))
- if (!member(lfirst(key1), lfirst(key2)))
- allmember = false;
-
- if ( (length (keys2) >= length (keys1)) && allmember)
- return(true);
- else
- return(false);
+ bool allmember = true;
+ List *key1,
+ *key2;
+
+ for (key1 = keys1, key2 = keys2; key1 != NIL && key2 != NIL;
+ key1 = lnext(key1), key2 = lnext(key2))
+ if (!member(lfirst(key1), lfirst(key2)))
+ allmember = false;
+
+ if ((length(keys2) >= length(keys1)) && allmember)
+ return (true);
+ else
+ return (false);
}
-/*
+/*
* collect-index-pathkeys--
- * Creates a list of subkeys by retrieving var nodes corresponding to
- * each index key in 'index-keys' from the relation's target list
- * 'tlist'. If the key is not in the target list, the key is irrelevant
- * and is thrown away. The returned subkey list is of the form:
- * ((var1) (var2) ... (varn))
- *
+ * Creates a list of subkeys by retrieving var nodes corresponding to
+ * each index key in 'index-keys' from the relation's target list
+ * 'tlist'. If the key is not in the target list, the key is irrelevant
+ * and is thrown away. The returned subkey list is of the form:
+ * ((var1) (var2) ... (varn))
+ *
* 'index-keys' is a list of index keys
* 'tlist' is a relation target list
- *
+ *
* Returns the list of cons'd subkeys.
- *
+ *
*/
/* This function is identical to matching_tlvar and tlistentry_member.
* They should be merged.
*/
-static Expr *
-matching2_tlvar(int var, List *tlist, bool (*test)())
+static Expr *
+matching2_tlvar(int var, List * tlist, bool(*test) ())
{
- TargetEntry *tlentry = NULL;
-
- if (var) {
- List *temp;
- foreach (temp,tlist) {
- if ((*test)(var, get_expr(lfirst(temp)))) {
- tlentry = lfirst(temp);
- break;
- }
+ TargetEntry *tlentry = NULL;
+
+ if (var)
+ {
+ List *temp;
+
+ foreach(temp, tlist)
+ {
+ if ((*test) (var, get_expr(lfirst(temp))))
+ {
+ tlentry = lfirst(temp);
+ break;
+ }
+ }
}
- }
- if (tlentry)
- return((Expr*)get_expr(tlentry));
- else
- return((Expr*)NULL);
+ if (tlentry)
+ return ((Expr *) get_expr(tlentry));
+ else
+ return ((Expr *) NULL);
}
-List *
-collect_index_pathkeys(int *index_keys, List *tlist)
+List *
+collect_index_pathkeys(int *index_keys, List * tlist)
{
- List *retval = NIL;
-
- Assert (index_keys != NULL);
-
- while(index_keys[0] != 0) {
- Expr *mvar;
- mvar = matching2_tlvar(index_keys[0],
- tlist,
- equal_indexkey_var);
- if (mvar)
- retval = nconc(retval,lcons(lcons(mvar,NIL),
- NIL));
- index_keys++;
- }
- return(retval);
-}
+ List *retval = NIL;
+
+ Assert(index_keys != NULL);
+
+ while (index_keys[0] != 0)
+ {
+ Expr *mvar;
+ mvar = matching2_tlvar(index_keys[0],
+ tlist,
+ equal_indexkey_var);
+ if (mvar)
+ retval = nconc(retval, lcons(lcons(mvar, NIL),
+ NIL));
+ index_keys++;
+ }
+ return (retval);
+}
diff --git a/src/backend/optimizer/util/ordering.c b/src/backend/optimizer/util/ordering.c
index 40699e81e0b..504d48bdce5 100644
--- a/src/backend/optimizer/util/ordering.c
+++ b/src/backend/optimizer/util/ordering.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* ordering.c--
- * Routines to manipulate and compare merge and path orderings
+ * Routines to manipulate and compare merge and path orderings
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/ordering.c,v 1.3 1997/08/19 21:32:06 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/ordering.c,v 1.4 1997/09/07 04:44:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,81 +18,88 @@
#include "optimizer/internal.h"
#include "optimizer/ordering.h"
-static bool equal_sortops_order(Oid *ordering1, Oid *ordering2);
+static bool equal_sortops_order(Oid * ordering1, Oid * ordering2);
-/*
+/*
* equal-path-path-ordering--
- * Returns t iff two path orderings are equal.
- *
+ * Returns t iff two path orderings are equal.
+ *
*/
bool
-equal_path_path_ordering(PathOrder *path_ordering1,
- PathOrder *path_ordering2)
+equal_path_path_ordering(PathOrder * path_ordering1,
+ PathOrder * path_ordering2)
{
- if (path_ordering1 == path_ordering2)
- return true;
-
- if (!path_ordering1 || !path_ordering2)
- return false;
-
- if (path_ordering1->ordtype == MERGE_ORDER &&
- path_ordering2->ordtype == MERGE_ORDER) {
-
- return equal(path_ordering1->ord.merge, path_ordering2->ord.merge);
-
- } else if (path_ordering1->ordtype == SORTOP_ORDER &&
- path_ordering2->ordtype == SORTOP_ORDER) {
-
- return
- (equal_sortops_order(path_ordering1->ord.sortop,
- path_ordering2->ord.sortop));
- } else if (path_ordering1->ordtype == MERGE_ORDER &&
- path_ordering2->ordtype == SORTOP_ORDER) {
-
- return (path_ordering2->ord.sortop &&
- (path_ordering1->ord.merge->left_operator ==
- path_ordering2->ord.sortop[0]));
- } else {
-
- return (path_ordering1->ord.sortop &&
- (path_ordering1->ord.sortop[0] ==
- path_ordering2->ord.merge->left_operator));
- }
+ if (path_ordering1 == path_ordering2)
+ return true;
+
+ if (!path_ordering1 || !path_ordering2)
+ return false;
+
+ if (path_ordering1->ordtype == MERGE_ORDER &&
+ path_ordering2->ordtype == MERGE_ORDER)
+ {
+
+ return equal(path_ordering1->ord.merge, path_ordering2->ord.merge);
+
+ }
+ else if (path_ordering1->ordtype == SORTOP_ORDER &&
+ path_ordering2->ordtype == SORTOP_ORDER)
+ {
+
+ return
+ (equal_sortops_order(path_ordering1->ord.sortop,
+ path_ordering2->ord.sortop));
+ }
+ else if (path_ordering1->ordtype == MERGE_ORDER &&
+ path_ordering2->ordtype == SORTOP_ORDER)
+ {
+
+ return (path_ordering2->ord.sortop &&
+ (path_ordering1->ord.merge->left_operator ==
+ path_ordering2->ord.sortop[0]));
+ }
+ else
+ {
+
+ return (path_ordering1->ord.sortop &&
+ (path_ordering1->ord.sortop[0] ==
+ path_ordering2->ord.merge->left_operator));
+ }
}
-/*
+/*
* equal-path-merge-ordering--
- * Returns t iff a path ordering is usable for ordering a merge join.
+ * Returns t iff a path ordering is usable for ordering a merge join.
*
* XXX Presently, this means that the first sortop of the path matches
- * either of the merge sortops. Is there a "right" and "wrong"
- * sortop to match?
- *
+ * either of the merge sortops. Is there a "right" and "wrong"
+ * sortop to match?
+ *
*/
bool
-equal_path_merge_ordering(Oid *path_ordering,
- MergeOrder *merge_ordering)
+equal_path_merge_ordering(Oid * path_ordering,
+ MergeOrder * merge_ordering)
{
- if (path_ordering == NULL || merge_ordering == NULL)
- return(false);
-
- if (path_ordering[0] == merge_ordering->left_operator ||
- path_ordering[0] == merge_ordering->right_operator)
- return(true);
- else
- return(false);
+ if (path_ordering == NULL || merge_ordering == NULL)
+ return (false);
+
+ if (path_ordering[0] == merge_ordering->left_operator ||
+ path_ordering[0] == merge_ordering->right_operator)
+ return (true);
+ else
+ return (false);
}
-/*
+/*
* equal-merge-merge-ordering--
- * Returns t iff two merge orderings are equal.
- *
+ * Returns t iff two merge orderings are equal.
+ *
*/
bool
-equal_merge_merge_ordering(MergeOrder *merge_ordering1,
- MergeOrder *merge_ordering2)
+equal_merge_merge_ordering(MergeOrder * merge_ordering1,
+ MergeOrder * merge_ordering2)
{
- return (equal(merge_ordering1, merge_ordering2));
+ return (equal(merge_ordering1, merge_ordering2));
}
/*****************************************************************************
@@ -101,21 +108,22 @@ equal_merge_merge_ordering(MergeOrder *merge_ordering1,
/*
* equal_sort_ops_order -
- * Returns true iff the sort operators are in the same order.
+ * Returns true iff the sort operators are in the same order.
*/
-static bool
-equal_sortops_order(Oid *ordering1, Oid *ordering2)
+static bool
+equal_sortops_order(Oid * ordering1, Oid * ordering2)
{
- int i = 0;
-
- if (ordering1 == NULL || ordering2 == NULL)
- return (ordering1==ordering2);
-
- while (ordering1[i]!=0 && ordering2[i]!=0) {
- if (ordering1[i] != ordering2[i])
- break;
- i++;
- }
-
- return (ordering1[i]==0 && ordering2[i]==0);
+ int i = 0;
+
+ if (ordering1 == NULL || ordering2 == NULL)
+ return (ordering1 == ordering2);
+
+ while (ordering1[i] != 0 && ordering2[i] != 0)
+ {
+ if (ordering1[i] != ordering2[i])
+ break;
+ i++;
+ }
+
+ return (ordering1[i] == 0 && ordering2[i] == 0);
}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index d79788b0e6e..6b37d2f36d4 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* pathnode.c--
- * Routines to manipulate pathlists and create path nodes
+ * Routines to manipulate pathlists and create path nodes
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.3 1997/09/05 18:10:36 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.4 1997/09/07 04:44:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,418 +27,459 @@
#include "optimizer/xfunc.h"
#include "optimizer/ordering.h"
-#include "parser/parsetree.h" /* for getrelid() */
+#include "parser/parsetree.h" /* for getrelid() */
-static Path *better_path(Path *new_path, List *unique_paths, bool *noOther);
+static Path *better_path(Path * new_path, List * unique_paths, bool * noOther);
/*****************************************************************************
- * MISC. PATH UTILITIES
+ * MISC. PATH UTILITIES
*****************************************************************************/
-/*
+/*
* path-is-cheaper--
- * Returns t iff 'path1' is cheaper than 'path2'.
- *
+ * Returns t iff 'path1' is cheaper than 'path2'.
+ *
*/
bool
-path_is_cheaper(Path *path1, Path *path2)
+path_is_cheaper(Path * path1, Path * path2)
{
- Cost cost1 = path1->path_cost;
- Cost cost2 = path2->path_cost;
+ Cost cost1 = path1->path_cost;
+ Cost cost2 = path2->path_cost;
- return((bool)(cost1 < cost2));
+ return ((bool) (cost1 < cost2));
}
-/*
+/*
* set_cheapest--
- * Finds the minimum cost path from among a relation's paths.
- *
+ * Finds the minimum cost path from among a relation's paths.
+ *
* 'parent-rel' is the parent relation
* 'pathlist' is a list of path nodes corresponding to 'parent-rel'
- *
- * Returns and sets the relation entry field with the pathnode that
+ *
+ * Returns and sets the relation entry field with the pathnode that
* is minimum.
- *
+ *
*/
-Path *
-set_cheapest(Rel *parent_rel, List *pathlist)
+Path *
+set_cheapest(Rel * parent_rel, List * pathlist)
{
- List *p;
- Path *cheapest_so_far;
+ List *p;
+ Path *cheapest_so_far;
- Assert(pathlist!=NIL);
- Assert(IsA(parent_rel,Rel));
+ Assert(pathlist != NIL);
+ Assert(IsA(parent_rel, Rel));
- cheapest_so_far = (Path*)lfirst(pathlist);
+ cheapest_so_far = (Path *) lfirst(pathlist);
- foreach (p, lnext(pathlist)) {
- Path *path = (Path*)lfirst(p);
+ foreach(p, lnext(pathlist))
+ {
+ Path *path = (Path *) lfirst(p);
- if (path_is_cheaper(path, cheapest_so_far)) {
- cheapest_so_far = path;
+ if (path_is_cheaper(path, cheapest_so_far))
+ {
+ cheapest_so_far = path;
+ }
}
- }
- parent_rel->cheapestpath = cheapest_so_far;
+ parent_rel->cheapestpath = cheapest_so_far;
- return(cheapest_so_far);
+ return (cheapest_so_far);
}
-/*
+/*
* add_pathlist--
- * For each path in the list 'new-paths', add to the list 'unique-paths'
- * only those paths that are unique (i.e., unique ordering and ordering
- * keys). Should a conflict arise, the more expensive path is thrown out,
- * thereby pruning the plan space. But we don't prune if xfunc
- * told us not to.
- *
+ * For each path in the list 'new-paths', add to the list 'unique-paths'
+ * only those paths that are unique (i.e., unique ordering and ordering
+ * keys). Should a conflict arise, the more expensive path is thrown out,
+ * thereby pruning the plan space. But we don't prune if xfunc
+ * told us not to.
+ *
* 'parent-rel' is the relation entry to which these paths correspond.
- *
+ *
* Returns the list of unique pathnodes.
- *
+ *
*/
-List *
-add_pathlist(Rel *parent_rel, List *unique_paths, List *new_paths)
+List *
+add_pathlist(Rel * parent_rel, List * unique_paths, List * new_paths)
{
- List *x;
- Path *new_path;
- Path *old_path;
- bool noOther;
-
- foreach (x, new_paths) {
- new_path = (Path*)lfirst(x);
- if (member(new_path, unique_paths))
- continue;
- old_path = better_path(new_path,unique_paths,&noOther);
-
- if (noOther) {
- /* Is a brand new path. */
- new_path->parent = parent_rel;
- unique_paths = lcons(new_path, unique_paths);
- } else if (old_path==NULL) {
- ; /* do nothing if path is not cheaper */
- } else if (old_path != NULL) { /* (IsA(old_path,Path)) { */
- new_path->parent = parent_rel;
- if (!parent_rel->pruneable) {
- unique_paths = lcons(new_path, unique_paths);
- }else
- unique_paths = lcons(new_path,
- LispRemove(old_path,unique_paths));
+ List *x;
+ Path *new_path;
+ Path *old_path;
+ bool noOther;
+
+ foreach(x, new_paths)
+ {
+ new_path = (Path *) lfirst(x);
+ if (member(new_path, unique_paths))
+ continue;
+ old_path = better_path(new_path, unique_paths, &noOther);
+
+ if (noOther)
+ {
+ /* Is a brand new path. */
+ new_path->parent = parent_rel;
+ unique_paths = lcons(new_path, unique_paths);
+ }
+ else if (old_path == NULL)
+ {
+ ; /* do nothing if path is not cheaper */
+ }
+ else if (old_path != NULL)
+ { /* (IsA(old_path,Path)) { */
+ new_path->parent = parent_rel;
+ if (!parent_rel->pruneable)
+ {
+ unique_paths = lcons(new_path, unique_paths);
+ }
+ else
+ unique_paths = lcons(new_path,
+ LispRemove(old_path, unique_paths));
+ }
}
- }
- return(unique_paths);
+ return (unique_paths);
}
-/*
+/*
* better_path--
- * Determines whether 'new-path' has the same ordering and keys as some
- * path in the list 'unique-paths'. If there is a redundant path,
- * eliminate the more expensive path.
- *
+ * Determines whether 'new-path' has the same ordering and keys as some
+ * path in the list 'unique-paths'. If there is a redundant path,
+ * eliminate the more expensive path.
+ *
* Returns:
- * The old path - if 'new-path' matches some path in 'unique-paths' and is
- * cheaper
- * nil - if 'new-path' matches but isn't cheaper
- * t - if there is no path in the list with the same ordering and keys
- *
+ * The old path - if 'new-path' matches some path in 'unique-paths' and is
+ * cheaper
+ * nil - if 'new-path' matches but isn't cheaper
+ * t - if there is no path in the list with the same ordering and keys
+ *
*/
-static Path *
-better_path(Path *new_path, List *unique_paths, bool *noOther)
+static Path *
+better_path(Path * new_path, List * unique_paths, bool * noOther)
{
- Path *old_path = (Path*)NULL;
- Path *path = (Path*)NULL;
- List *temp = NIL;
- Path *retval = NULL;
-
- /* XXX - added the following two lines which weren't int
- * the lisp planner, but otherwise, doesn't seem to work
- * for the case where new_path is 'nil
- */
- foreach (temp,unique_paths) {
- path = (Path*) lfirst(temp);
-
- if ((equal_path_path_ordering(&new_path->p_ordering,
- &path->p_ordering) &&
- samekeys(new_path->keys, path->keys))) {
- old_path = path;
- break;
+ Path *old_path = (Path *) NULL;
+ Path *path = (Path *) NULL;
+ List *temp = NIL;
+ Path *retval = NULL;
+
+ /*
+ * XXX - added the following two lines which weren't int the lisp
+ * planner, but otherwise, doesn't seem to work for the case where
+ * new_path is 'nil
+ */
+ foreach(temp, unique_paths)
+ {
+ path = (Path *) lfirst(temp);
+
+ if ((equal_path_path_ordering(&new_path->p_ordering,
+ &path->p_ordering) &&
+ samekeys(new_path->keys, path->keys)))
+ {
+ old_path = path;
+ break;
+ }
}
- }
-
- if (old_path==NULL) {
- *noOther = true;
- } else {
- *noOther = false;
- if (path_is_cheaper(new_path,old_path)) {
- retval = old_path;
+
+ if (old_path == NULL)
+ {
+ *noOther = true;
+ }
+ else
+ {
+ *noOther = false;
+ if (path_is_cheaper(new_path, old_path))
+ {
+ retval = old_path;
+ }
}
- }
-
- return(retval);
+
+ return (retval);
}
/*****************************************************************************
- * PATH NODE CREATION ROUTINES
+ * PATH NODE CREATION ROUTINES
*****************************************************************************/
-/*
+/*
* create_seqscan_path--
- * Creates a path corresponding to a sequential scan, returning the
- * pathnode.
- *
+ * Creates a path corresponding to a sequential scan, returning the
+ * pathnode.
+ *
*/
-Path *
-create_seqscan_path(Rel *rel)
+Path *
+create_seqscan_path(Rel * rel)
{
- int relid=0;
-
- Path *pathnode = makeNode(Path);
-
- pathnode->pathtype = T_SeqScan;
- pathnode->parent = rel;
- pathnode->path_cost = 0.0;
- pathnode->p_ordering.ordtype = SORTOP_ORDER;
- pathnode->p_ordering.ord.sortop = NULL;
- pathnode->keys = NIL;
- /* copy clauseinfo list into path for expensive function processing
- * -- JMH, 7/7/92
- */
- pathnode->locclauseinfo=
- (List*)copyObject((Node*)rel->clauseinfo);
-
- if (rel->relids !=NULL)
- relid = lfirsti(rel->relids);
-
- pathnode->path_cost = cost_seqscan (relid,
- rel->pages, rel->tuples);
- /* add in expensive functions cost! -- JMH, 7/7/92 */
+ int relid = 0;
+
+ Path *pathnode = makeNode(Path);
+
+ pathnode->pathtype = T_SeqScan;
+ pathnode->parent = rel;
+ pathnode->path_cost = 0.0;
+ pathnode->p_ordering.ordtype = SORTOP_ORDER;
+ pathnode->p_ordering.ord.sortop = NULL;
+ pathnode->keys = NIL;
+
+ /*
+ * copy clauseinfo list into path for expensive function processing --
+ * JMH, 7/7/92
+ */
+ pathnode->locclauseinfo =
+ (List *) copyObject((Node *) rel->clauseinfo);
+
+ if (rel->relids != NULL)
+ relid = lfirsti(rel->relids);
+
+ pathnode->path_cost = cost_seqscan(relid,
+ rel->pages, rel->tuples);
+ /* add in expensive functions cost! -- JMH, 7/7/92 */
#if 0
- if (XfuncMode != XFUNC_OFF) {
- pathnode->path_cost +=
- xfunc_get_path_cost(pathnode);
- }
+ if (XfuncMode != XFUNC_OFF)
+ {
+ pathnode->path_cost +=
+ xfunc_get_path_cost(pathnode);
+ }
#endif
- return (pathnode);
+ return (pathnode);
}
-/*
+/*
* create_index_path--
- * Creates a single path node for an index scan.
- *
+ * Creates a single path node for an index scan.
+ *
* 'rel' is the parent rel
* 'index' is the pathnode for the index on 'rel'
* 'restriction-clauses' is a list of restriction clause nodes.
* 'is-join-scan' is a flag indicating whether or not the index is being
- * considered because of its sort order.
- *
+ * considered because of its sort order.
+ *
* Returns the new path node.
- *
+ *
*/
-IndexPath *
-create_index_path(Query *root,
- Rel *rel,
- Rel *index,
- List *restriction_clauses,
- bool is_join_scan)
+IndexPath *
+create_index_path(Query * root,
+ Rel * rel,
+ Rel * index,
+ List * restriction_clauses,
+ bool is_join_scan)
{
- IndexPath *pathnode = makeNode(IndexPath);
-
- pathnode->path.pathtype = T_IndexScan;
- pathnode->path.parent = rel;
- pathnode->path.p_ordering.ordtype = SORTOP_ORDER;
- pathnode->path.p_ordering.ord.sortop = index->ordering;
-
- pathnode->indexid = index->relids;
- pathnode->indexkeys = index->indexkeys;
- pathnode->indexqual = NIL;
-
- /* copy clauseinfo list into path for expensive function processing
- * -- JMH, 7/7/92
- */
- pathnode->path.locclauseinfo =
- set_difference((List*) copyObject((Node*)rel->clauseinfo),
- (List*) restriction_clauses);
-
- /*
- * The index must have an ordering for the path to have (ordering) keys,
- * and vice versa.
- */
- if (pathnode->path.p_ordering.ord.sortop) {
- pathnode->path.keys = collect_index_pathkeys(index->indexkeys,
- rel->targetlist);
+ IndexPath *pathnode = makeNode(IndexPath);
+
+ pathnode->path.pathtype = T_IndexScan;
+ pathnode->path.parent = rel;
+ pathnode->path.p_ordering.ordtype = SORTOP_ORDER;
+ pathnode->path.p_ordering.ord.sortop = index->ordering;
+
+ pathnode->indexid = index->relids;
+ pathnode->indexkeys = index->indexkeys;
+ pathnode->indexqual = NIL;
+
/*
- * Check that the keys haven't 'disappeared', since they may
- * no longer be in the target list (i.e., index keys that are not
- * relevant to the scan are not applied to the scan path node,
- * so if no index keys were found, we can't order the path).
+ * copy clauseinfo list into path for expensive function processing --
+ * JMH, 7/7/92
*/
- if (pathnode->path.keys==NULL) {
- pathnode->path.p_ordering.ord.sortop = NULL;
- }
- } else {
- pathnode->path.keys = NULL;
- }
+ pathnode->path.locclauseinfo =
+ set_difference((List *) copyObject((Node *) rel->clauseinfo),
+ (List *) restriction_clauses);
- if (is_join_scan || restriction_clauses==NULL) {
/*
- * Indices used for joins or sorting result nodes don't
- * restrict the result at all, they simply order it,
- * so compute the scan cost
- * accordingly -- use a selectivity of 1.0.
+ * The index must have an ordering for the path to have (ordering)
+ * keys, and vice versa.
*/
-/* is the statement above really true? what about IndexScan as the
+ if (pathnode->path.p_ordering.ord.sortop)
+ {
+ pathnode->path.keys = collect_index_pathkeys(index->indexkeys,
+ rel->targetlist);
+
+ /*
+ * Check that the keys haven't 'disappeared', since they may no
+ * longer be in the target list (i.e., index keys that are not
+ * relevant to the scan are not applied to the scan path node, so
+ * if no index keys were found, we can't order the path).
+ */
+ if (pathnode->path.keys == NULL)
+ {
+ pathnode->path.p_ordering.ord.sortop = NULL;
+ }
+ }
+ else
+ {
+ pathnode->path.keys = NULL;
+ }
+
+ if (is_join_scan || restriction_clauses == NULL)
+ {
+
+ /*
+ * Indices used for joins or sorting result nodes don't restrict
+ * the result at all, they simply order it, so compute the scan
+ * cost accordingly -- use a selectivity of 1.0.
+ */
+/* is the statement above really true? what about IndexScan as the
inner of a join? */
- pathnode->path.path_cost =
- cost_index (lfirsti(index->relids),
- index->pages,
- 1.0,
- rel->pages,
- rel->tuples,
- index->pages,
- index->tuples,
- false);
- /* add in expensive functions cost! -- JMH, 7/7/92 */
+ pathnode->path.path_cost =
+ cost_index(lfirsti(index->relids),
+ index->pages,
+ 1.0,
+ rel->pages,
+ rel->tuples,
+ index->pages,
+ index->tuples,
+ false);
+ /* add in expensive functions cost! -- JMH, 7/7/92 */
#if 0
- if (XfuncMode != XFUNC_OFF) {
- pathnode->path_cost =
- (pathnode->path_cost +
- xfunc_get_path_cost((Path*)pathnode));
- }
+ if (XfuncMode != XFUNC_OFF)
+ {
+ pathnode->path_cost =
+ (pathnode->path_cost +
+ xfunc_get_path_cost((Path *) pathnode));
+ }
#endif
- } else {
- /*
- * Compute scan cost for the case when 'index' is used with a
- * restriction clause.
- */
- List *attnos;
- List *values;
- List *flags;
- float npages;
- float selec;
- Cost clausesel;
-
- get_relattvals(restriction_clauses,
- &attnos,
- &values,
- &flags);
- index_selectivity(lfirsti(index->relids),
- index->classlist,
- get_opnos(restriction_clauses),
- getrelid(lfirsti(rel->relids),
- root->rtable),
- attnos,
- values,
- flags,
- length(restriction_clauses),
- &npages,
- &selec);
- /* each clause gets an equal selectivity */
- clausesel =
- pow(selec,
- 1.0 / (double) length(restriction_clauses));
-
- pathnode->indexqual = restriction_clauses;
- pathnode->path.path_cost =
- cost_index (lfirsti(index->relids),
- (int)npages,
- selec,
- rel->pages,
- rel->tuples,
- index->pages,
- index->tuples,
- false);
+ }
+ else
+ {
+
+ /*
+ * Compute scan cost for the case when 'index' is used with a
+ * restriction clause.
+ */
+ List *attnos;
+ List *values;
+ List *flags;
+ float npages;
+ float selec;
+ Cost clausesel;
+
+ get_relattvals(restriction_clauses,
+ &attnos,
+ &values,
+ &flags);
+ index_selectivity(lfirsti(index->relids),
+ index->classlist,
+ get_opnos(restriction_clauses),
+ getrelid(lfirsti(rel->relids),
+ root->rtable),
+ attnos,
+ values,
+ flags,
+ length(restriction_clauses),
+ &npages,
+ &selec);
+ /* each clause gets an equal selectivity */
+ clausesel =
+ pow(selec,
+ 1.0 / (double) length(restriction_clauses));
+
+ pathnode->indexqual = restriction_clauses;
+ pathnode->path.path_cost =
+ cost_index(lfirsti(index->relids),
+ (int) npages,
+ selec,
+ rel->pages,
+ rel->tuples,
+ index->pages,
+ index->tuples,
+ false);
#if 0
- /* add in expensive functions cost! -- JMH, 7/7/92 */
- if (XfuncMode != XFUNC_OFF) {
- pathnode->path_cost +=
- xfunc_get_path_cost((Path*)pathnode);
- }
+ /* add in expensive functions cost! -- JMH, 7/7/92 */
+ if (XfuncMode != XFUNC_OFF)
+ {
+ pathnode->path_cost +=
+ xfunc_get_path_cost((Path *) pathnode);
+ }
#endif
- /* Set selectivities of clauses used with index to the selectivity
- * of this index, subdividing the selectivity equally over each of
- * the clauses.
- */
- /* XXX Can this divide the selectivities in a better way? */
- set_clause_selectivities(restriction_clauses, clausesel);
- }
- return(pathnode);
+ /*
+ * Set selectivities of clauses used with index to the selectivity
+ * of this index, subdividing the selectivity equally over each of
+ * the clauses.
+ */
+
+ /* XXX Can this divide the selectivities in a better way? */
+ set_clause_selectivities(restriction_clauses, clausesel);
+ }
+ return (pathnode);
}
-/*
+/*
* create_nestloop_path--
- * Creates a pathnode corresponding to a nestloop join between two
- * relations.
- *
+ * Creates a pathnode corresponding to a nestloop join between two
+ * relations.
+ *
* 'joinrel' is the join relation.
* 'outer_rel' is the outer join relation
* 'outer_path' is the outer join path.
* 'inner_path' is the inner join path.
* 'keys' are the keys of the path
- *
+ *
* Returns the resulting path node.
- *
+ *
*/
-JoinPath *
-create_nestloop_path(Rel *joinrel,
- Rel *outer_rel,
- Path *outer_path,
- Path *inner_path,
- List *keys)
+JoinPath *
+create_nestloop_path(Rel * joinrel,
+ Rel * outer_rel,
+ Path * outer_path,
+ Path * inner_path,
+ List * keys)
{
- JoinPath *pathnode = makeNode(JoinPath);
-
- pathnode->path.pathtype = T_NestLoop;
- pathnode->path.parent = joinrel;
- pathnode->outerjoinpath = outer_path;
- pathnode->innerjoinpath = inner_path;
- pathnode->pathclauseinfo = joinrel->clauseinfo;
- pathnode->path.keys = keys;
- pathnode->path.joinid = NIL;
- pathnode->path.outerjoincost = (Cost)0.0;
- pathnode->path.locclauseinfo = NIL;
-
- if (keys) {
- pathnode->path.p_ordering.ordtype =
- outer_path->p_ordering.ordtype;
- if (outer_path->p_ordering.ordtype == SORTOP_ORDER) {
- pathnode->path.p_ordering.ord.sortop =
- outer_path->p_ordering.ord.sortop;
- } else {
- pathnode->path.p_ordering.ord.merge =
- outer_path->p_ordering.ord.merge;
+ JoinPath *pathnode = makeNode(JoinPath);
+
+ pathnode->path.pathtype = T_NestLoop;
+ pathnode->path.parent = joinrel;
+ pathnode->outerjoinpath = outer_path;
+ pathnode->innerjoinpath = inner_path;
+ pathnode->pathclauseinfo = joinrel->clauseinfo;
+ pathnode->path.keys = keys;
+ pathnode->path.joinid = NIL;
+ pathnode->path.outerjoincost = (Cost) 0.0;
+ pathnode->path.locclauseinfo = NIL;
+
+ if (keys)
+ {
+ pathnode->path.p_ordering.ordtype =
+ outer_path->p_ordering.ordtype;
+ if (outer_path->p_ordering.ordtype == SORTOP_ORDER)
+ {
+ pathnode->path.p_ordering.ord.sortop =
+ outer_path->p_ordering.ord.sortop;
+ }
+ else
+ {
+ pathnode->path.p_ordering.ord.merge =
+ outer_path->p_ordering.ord.merge;
+ }
}
- } else {
- pathnode->path.p_ordering.ordtype = SORTOP_ORDER;
- pathnode->path.p_ordering.ord.sortop = NULL;
- }
-
- pathnode->path.path_cost =
- cost_nestloop(outer_path->path_cost,
- inner_path->path_cost,
- outer_rel->size,
- inner_path->parent->size,
- page_size(outer_rel->size,
- outer_rel->width),
- IsA(inner_path,IndexPath));
- /* add in expensive function costs -- JMH 7/7/92 */
+ else
+ {
+ pathnode->path.p_ordering.ordtype = SORTOP_ORDER;
+ pathnode->path.p_ordering.ord.sortop = NULL;
+ }
+
+ pathnode->path.path_cost =
+ cost_nestloop(outer_path->path_cost,
+ inner_path->path_cost,
+ outer_rel->size,
+ inner_path->parent->size,
+ page_size(outer_rel->size,
+ outer_rel->width),
+ IsA(inner_path, IndexPath));
+ /* add in expensive function costs -- JMH 7/7/92 */
#if 0
- if (XfuncMode != XFUNC_OFF) {
- pathnode->path_cost += xfunc_get_path_cost((Path*)pathnode);
- }
+ if (XfuncMode != XFUNC_OFF)
+ {
+ pathnode->path_cost += xfunc_get_path_cost((Path *) pathnode);
+ }
#endif
- return(pathnode);
+ return (pathnode);
}
-/*
+/*
* create_mergesort_path--
- * Creates a pathnode corresponding to a mergesort join between
- * two relations
- *
+ * Creates a pathnode corresponding to a mergesort join between
+ * two relations
+ *
* 'joinrel' is the join relation
* 'outersize' is the number of tuples in the outer relation
* 'innersize' is the number of tuples in the inner relation
@@ -451,59 +492,60 @@ create_nestloop_path(Rel *joinrel,
* 'mergeclauses' are the applicable join/restriction clauses
* 'outersortkeys' are the sort varkeys for the outer relation
* 'innersortkeys' are the sort varkeys for the inner relation
- *
+ *
*/
-MergePath *
-create_mergesort_path(Rel *joinrel,
- int outersize,
- int innersize,
- int outerwidth,
- int innerwidth,
- Path *outer_path,
- Path *inner_path,
- List *keys,
- MergeOrder *order,
- List *mergeclauses,
- List *outersortkeys,
- List *innersortkeys)
+MergePath *
+create_mergesort_path(Rel * joinrel,
+ int outersize,
+ int innersize,
+ int outerwidth,
+ int innerwidth,
+ Path * outer_path,
+ Path * inner_path,
+ List * keys,
+ MergeOrder * order,
+ List * mergeclauses,
+ List * outersortkeys,
+ List * innersortkeys)
{
- MergePath *pathnode = makeNode(MergePath);
-
- pathnode->jpath.path.pathtype = T_MergeJoin;
- pathnode->jpath.path.parent = joinrel;
- pathnode->jpath.outerjoinpath = outer_path;
- pathnode->jpath.innerjoinpath = inner_path;
- pathnode->jpath.pathclauseinfo = joinrel->clauseinfo;
- pathnode->jpath.path.keys = keys;
- pathnode->jpath.path.p_ordering.ordtype = MERGE_ORDER;
- pathnode->jpath.path.p_ordering.ord.merge = order;
- pathnode->path_mergeclauses = mergeclauses;
- pathnode->jpath.path.locclauseinfo = NIL;
- pathnode->outersortkeys = outersortkeys;
- pathnode->innersortkeys = innersortkeys;
- pathnode->jpath.path.path_cost =
- cost_mergesort(outer_path->path_cost,
- inner_path->path_cost,
- outersortkeys,
- innersortkeys,
- outersize,
- innersize,
- outerwidth,
- innerwidth);
- /* add in expensive function costs -- JMH 7/7/92 */
+ MergePath *pathnode = makeNode(MergePath);
+
+ pathnode->jpath.path.pathtype = T_MergeJoin;
+ pathnode->jpath.path.parent = joinrel;
+ pathnode->jpath.outerjoinpath = outer_path;
+ pathnode->jpath.innerjoinpath = inner_path;
+ pathnode->jpath.pathclauseinfo = joinrel->clauseinfo;
+ pathnode->jpath.path.keys = keys;
+ pathnode->jpath.path.p_ordering.ordtype = MERGE_ORDER;
+ pathnode->jpath.path.p_ordering.ord.merge = order;
+ pathnode->path_mergeclauses = mergeclauses;
+ pathnode->jpath.path.locclauseinfo = NIL;
+ pathnode->outersortkeys = outersortkeys;
+ pathnode->innersortkeys = innersortkeys;
+ pathnode->jpath.path.path_cost =
+ cost_mergesort(outer_path->path_cost,
+ inner_path->path_cost,
+ outersortkeys,
+ innersortkeys,
+ outersize,
+ innersize,
+ outerwidth,
+ innerwidth);
+ /* add in expensive function costs -- JMH 7/7/92 */
#if 0
- if (XfuncMode != XFUNC_OFF) {
- pathnode->path_cost +=
- xfunc_get_path_cost((Path*)pathnode);
- }
+ if (XfuncMode != XFUNC_OFF)
+ {
+ pathnode->path_cost +=
+ xfunc_get_path_cost((Path *) pathnode);
+ }
#endif
- return(pathnode);
+ return (pathnode);
}
-/*
- * create_hashjoin_path-- XXX HASH
- * Creates a pathnode corresponding to a hash join between two relations.
- *
+/*
+ * create_hashjoin_path-- XXX HASH
+ * Creates a pathnode corresponding to a hash join between two relations.
+ *
* 'joinrel' is the join relation
* 'outersize' is the number of tuples in the outer relation
* 'innersize' is the number of tuples in the inner relation
@@ -516,52 +558,53 @@ create_mergesort_path(Rel *joinrel,
* 'hashclauses' are the applicable join/restriction clauses
* 'outerkeys' are the sort varkeys for the outer relation
* 'innerkeys' are the sort varkeys for the inner relation
- *
+ *
*/
-HashPath *
-create_hashjoin_path(Rel *joinrel,
- int outersize,
- int innersize,
- int outerwidth,
- int innerwidth,
- Path *outer_path,
- Path *inner_path,
- List *keys,
- Oid operator,
- List *hashclauses,
- List *outerkeys,
- List *innerkeys)
+HashPath *
+create_hashjoin_path(Rel * joinrel,
+ int outersize,
+ int innersize,
+ int outerwidth,
+ int innerwidth,
+ Path * outer_path,
+ Path * inner_path,
+ List * keys,
+ Oid operator,
+ List * hashclauses,
+ List * outerkeys,
+ List * innerkeys)
{
- HashPath *pathnode = makeNode(HashPath);
-
- pathnode->jpath.path.pathtype = T_HashJoin;
- pathnode->jpath.path.parent = joinrel;
- pathnode->jpath.outerjoinpath = outer_path;
- pathnode->jpath.innerjoinpath = inner_path;
- pathnode->jpath.pathclauseinfo = joinrel->clauseinfo;
- pathnode->jpath.path.locclauseinfo = NIL;
- pathnode->jpath.path.keys = keys;
- pathnode->jpath.path.p_ordering.ordtype = SORTOP_ORDER;
- pathnode->jpath.path.p_ordering.ord.sortop = NULL;
- pathnode->jpath.path.outerjoincost = (Cost)0.0;
- pathnode->jpath.path.joinid = (Relid)NULL;
- /* pathnode->hashjoinoperator = operator; */
- pathnode->path_hashclauses = hashclauses;
- pathnode->outerhashkeys = outerkeys;
- pathnode->innerhashkeys = innerkeys;
- pathnode->jpath.path.path_cost =
- cost_hashjoin(outer_path->path_cost,
- inner_path->path_cost,
- outerkeys,
- innerkeys,
- outersize,innersize,
- outerwidth,innerwidth);
- /* add in expensive function costs -- JMH 7/7/92 */
+ HashPath *pathnode = makeNode(HashPath);
+
+ pathnode->jpath.path.pathtype = T_HashJoin;
+ pathnode->jpath.path.parent = joinrel;
+ pathnode->jpath.outerjoinpath = outer_path;
+ pathnode->jpath.innerjoinpath = inner_path;
+ pathnode->jpath.pathclauseinfo = joinrel->clauseinfo;
+ pathnode->jpath.path.locclauseinfo = NIL;
+ pathnode->jpath.path.keys = keys;
+ pathnode->jpath.path.p_ordering.ordtype = SORTOP_ORDER;
+ pathnode->jpath.path.p_ordering.ord.sortop = NULL;
+ pathnode->jpath.path.outerjoincost = (Cost) 0.0;
+ pathnode->jpath.path.joinid = (Relid) NULL;
+ /* pathnode->hashjoinoperator = operator; */
+ pathnode->path_hashclauses = hashclauses;
+ pathnode->outerhashkeys = outerkeys;
+ pathnode->innerhashkeys = innerkeys;
+ pathnode->jpath.path.path_cost =
+ cost_hashjoin(outer_path->path_cost,
+ inner_path->path_cost,
+ outerkeys,
+ innerkeys,
+ outersize, innersize,
+ outerwidth, innerwidth);
+ /* add in expensive function costs -- JMH 7/7/92 */
#if 0
- if (XfuncMode != XFUNC_OFF) {
- pathnode->path_cost +=
- xfunc_get_path_cost((Path*)pathnode);
- }
+ if (XfuncMode != XFUNC_OFF)
+ {
+ pathnode->path_cost +=
+ xfunc_get_path_cost((Path *) pathnode);
+ }
#endif
- return(pathnode);
+ return (pathnode);
}
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index abe764aa4e0..0e88a72c4eb 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* plancat.c--
- * routines for accessing the system catalogs
+ * routines for accessing the system catalogs
*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.6 1997/04/24 16:07:14 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.7 1997/09/07 04:44:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,7 +26,7 @@
#include "catalog/pg_inherits.h"
#include "catalog/pg_version.h"
-#include "parser/parsetree.h" /* for getrelid() */
+#include "parser/parsetree.h" /* for getrelid() */
#include "fmgr.h"
#include "optimizer/internal.h"
@@ -34,193 +34,203 @@
#include "utils/syscache.h"
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static void IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys,
- Oid AccessMethodOperatorClasses[], Oid operatorObjectIds[],
+static void
+IndexSelectivity(Oid indexrelid, Oid indrelid, int32 nIndexKeys,
+ Oid AccessMethodOperatorClasses[], Oid operatorObjectIds[],
int32 varAttributeNumbers[], char *constValues[], int32 constFlags[],
- float *idxPages, float *idxSelec);
+ float *idxPages, float *idxSelec);
/*
* relation-info -
- * Retrieves catalog information for a given relation. Given the oid of
- * the relation, return the following information:
- * whether the relation has secondary indices
- * number of pages
- * number of tuples
+ * Retrieves catalog information for a given relation. Given the oid of
+ * the relation, return the following information:
+ * whether the relation has secondary indices
+ * number of pages
+ * number of tuples
*/
void
-relation_info(Query *root, Index relid,
- bool *hasindex, int *pages, int *tuples)
+relation_info(Query * root, Index relid,
+ bool * hasindex, int *pages, int *tuples)
{
- HeapTuple relationTuple;
- Form_pg_class relation;
- Oid relationObjectId;
-
- relationObjectId = getrelid(relid, root->rtable);
- relationTuple = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(relationObjectId),
- 0,0,0);
- if (HeapTupleIsValid(relationTuple)) {
- relation = (Form_pg_class)GETSTRUCT(relationTuple);
-
- *hasindex = (relation->relhasindex) ? TRUE : FALSE;
- *pages = relation->relpages;
- *tuples = relation->reltuples;
- } else {
- elog(WARN, "RelationCatalogInformation: Relation %d not found",
- relationObjectId);
- }
-
- return;
+ HeapTuple relationTuple;
+ Form_pg_class relation;
+ Oid relationObjectId;
+
+ relationObjectId = getrelid(relid, root->rtable);
+ relationTuple = SearchSysCacheTuple(RELOID,
+ ObjectIdGetDatum(relationObjectId),
+ 0, 0, 0);
+ if (HeapTupleIsValid(relationTuple))
+ {
+ relation = (Form_pg_class) GETSTRUCT(relationTuple);
+
+ *hasindex = (relation->relhasindex) ? TRUE : FALSE;
+ *pages = relation->relpages;
+ *tuples = relation->reltuples;
+ }
+ else
+ {
+ elog(WARN, "RelationCatalogInformation: Relation %d not found",
+ relationObjectId);
+ }
+
+ return;
}
-/*
+/*
* index-info--
- * Retrieves catalog information on an index on a given relation.
- *
- * The index relation is opened on the first invocation. The current
- * retrieves the next index relation within the catalog that has not
- * already been retrieved by a previous call. The index catalog
- * is closed when no more indices for 'relid' can be found.
- *
- * 'first' is 1 if this is the first call
- *
+ * Retrieves catalog information on an index on a given relation.
+ *
+ * The index relation is opened on the first invocation. The current
+ * retrieves the next index relation within the catalog that has not
+ * already been retrieved by a previous call. The index catalog
+ * is closed when no more indices for 'relid' can be found.
+ *
+ * 'first' is 1 if this is the first call
+ *
* Returns true if successful and false otherwise. Index info is returned
* via the transient data structure 'info'.
- *
+ *
*/
bool
-index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
+index_info(Query * root, bool first, int relid, IdxInfoRetval * info)
{
- register i;
- HeapTuple indexTuple, amopTuple;
- IndexTupleForm index;
- Relation indexRelation;
- uint16 amstrategy;
- Oid relam;
- Oid indrelid;
-
- static Relation relation = (Relation) NULL;
- static HeapScanDesc scan = (HeapScanDesc) NULL;
- static ScanKeyData indexKey;
-
-
- /* find the oid of the indexed relation */
- indrelid = getrelid(relid, root->rtable);
-
- memset(info, 0, sizeof(IdxInfoRetval));
-
- /*
- * the maximum number of elements in each of the following arrays is
- * 8. We allocate one more for a terminating 0 to indicate the end
- * of the array.
- */
- info->indexkeys = (int *)palloc(sizeof(int)*9);
- memset(info->indexkeys, 0, sizeof(int)*9);
- info->orderOprs = (Oid *)palloc(sizeof(Oid)*9);
- memset(info->orderOprs, 0, sizeof(Oid)*9);
- info->classlist = (Oid *)palloc(sizeof(Oid)*9);
- memset(info->classlist, 0, sizeof(Oid)*9);
-
- /* Find an index on the given relation */
- if (first) {
- if (RelationIsValid(relation))
- heap_close(relation);
- if (HeapScanIsValid(scan))
- heap_endscan(scan);
-
- ScanKeyEntryInitialize(&indexKey, 0,
- Anum_pg_index_indrelid,
- F_OIDEQ,
- ObjectIdGetDatum(indrelid));
-
- relation = heap_openr(IndexRelationName);
- scan = heap_beginscan(relation, 0, NowTimeQual,
- 1, &indexKey);
- }
- if (!HeapScanIsValid(scan))
- elog(WARN, "index_info: scan not started");
- indexTuple = heap_getnext(scan, 0, (Buffer *) NULL);
- if (!HeapTupleIsValid(indexTuple)) {
- heap_endscan(scan);
- heap_close(relation);
- scan = (HeapScanDesc) NULL;
- relation = (Relation) NULL;
- return(0);
- }
-
- /* Extract info from the index tuple */
- index = (IndexTupleForm)GETSTRUCT(indexTuple);
- info->relid = index->indexrelid; /* index relation */
- for (i = 0; i < 8; i++)
- info->indexkeys[i] = index->indkey[i];
- for (i = 0; i < 8; i++)
- info->classlist[i] = index->indclass[i];
-
- info->indproc = index->indproc; /* functional index ?? */
-
- /* partial index ?? */
- if (VARSIZE(&index->indpred) != 0) {
+ register i;
+ HeapTuple indexTuple,
+ amopTuple;
+ IndexTupleForm index;
+ Relation indexRelation;
+ uint16 amstrategy;
+ Oid relam;
+ Oid indrelid;
+
+ static Relation relation = (Relation) NULL;
+ static HeapScanDesc scan = (HeapScanDesc) NULL;
+ static ScanKeyData indexKey;
+
+
+ /* find the oid of the indexed relation */
+ indrelid = getrelid(relid, root->rtable);
+
+ memset(info, 0, sizeof(IdxInfoRetval));
+
/*
- * The memory allocated here for the predicate (in lispReadString)
- * only needs to stay around until it's used in find_index_paths,
- * which is all within a command, so the automatic pfree at end
- * of transaction should be ok.
+ * the maximum number of elements in each of the following arrays is
+ * 8. We allocate one more for a terminating 0 to indicate the end of
+ * the array.
*/
- char *predString;
+ info->indexkeys = (int *) palloc(sizeof(int) * 9);
+ memset(info->indexkeys, 0, sizeof(int) * 9);
+ info->orderOprs = (Oid *) palloc(sizeof(Oid) * 9);
+ memset(info->orderOprs, 0, sizeof(Oid) * 9);
+ info->classlist = (Oid *) palloc(sizeof(Oid) * 9);
+ memset(info->classlist, 0, sizeof(Oid) * 9);
+
+ /* Find an index on the given relation */
+ if (first)
+ {
+ if (RelationIsValid(relation))
+ heap_close(relation);
+ if (HeapScanIsValid(scan))
+ heap_endscan(scan);
+
+ ScanKeyEntryInitialize(&indexKey, 0,
+ Anum_pg_index_indrelid,
+ F_OIDEQ,
+ ObjectIdGetDatum(indrelid));
+
+ relation = heap_openr(IndexRelationName);
+ scan = heap_beginscan(relation, 0, NowTimeQual,
+ 1, &indexKey);
+ }
+ if (!HeapScanIsValid(scan))
+ elog(WARN, "index_info: scan not started");
+ indexTuple = heap_getnext(scan, 0, (Buffer *) NULL);
+ if (!HeapTupleIsValid(indexTuple))
+ {
+ heap_endscan(scan);
+ heap_close(relation);
+ scan = (HeapScanDesc) NULL;
+ relation = (Relation) NULL;
+ return (0);
+ }
+
+ /* Extract info from the index tuple */
+ index = (IndexTupleForm) GETSTRUCT(indexTuple);
+ info->relid = index->indexrelid; /* index relation */
+ for (i = 0; i < 8; i++)
+ info->indexkeys[i] = index->indkey[i];
+ for (i = 0; i < 8; i++)
+ info->classlist[i] = index->indclass[i];
- predString = fmgr(F_TEXTOUT, &index->indpred);
- info->indpred = (Node*)stringToNode(predString);
- pfree(predString);
- }
+ info->indproc = index->indproc; /* functional index ?? */
- /* Extract info from the relation descriptor for the index */
- indexRelation = index_open(index->indexrelid);
+ /* partial index ?? */
+ if (VARSIZE(&index->indpred) != 0)
+ {
+
+ /*
+ * The memory allocated here for the predicate (in lispReadString)
+ * only needs to stay around until it's used in find_index_paths,
+ * which is all within a command, so the automatic pfree at end of
+ * transaction should be ok.
+ */
+ char *predString;
+
+ predString = fmgr(F_TEXTOUT, &index->indpred);
+ info->indpred = (Node *) stringToNode(predString);
+ pfree(predString);
+ }
+
+ /* Extract info from the relation descriptor for the index */
+ indexRelation = index_open(index->indexrelid);
#ifdef notdef
- /* XXX should iterate through strategies -- but how? use #1 for now */
- amstrategy = indexRelation->rd_am->amstrategies;
-#endif /* notdef */
- amstrategy = 1;
- relam = indexRelation->rd_rel->relam;
- info->relam = relam;
- info->pages = indexRelation->rd_rel->relpages;
- info->tuples = indexRelation->rd_rel->reltuples;
- heap_close(indexRelation);
-
- /*
- * Find the index ordering keys
- *
- * Must use indclass to know when to stop looking since with
- * functional indices there could be several keys (args) for
- * one opclass. -mer 27 Sept 1991
- */
- for (i = 0; i < 8 && index->indclass[i]; ++i) {
- amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
- ObjectIdGetDatum(relam),
- ObjectIdGetDatum(index->indclass[i]),
- UInt16GetDatum(amstrategy),
- 0);
- if (!HeapTupleIsValid(amopTuple))
- elog(WARN, "index_info: no amop %d %d %d",
- relam, index->indclass[i], amstrategy);
- info->orderOprs[i] =
- ((Form_pg_amop)GETSTRUCT(amopTuple))->amopopr;
- }
- return(TRUE);
+ /* XXX should iterate through strategies -- but how? use #1 for now */
+ amstrategy = indexRelation->rd_am->amstrategies;
+#endif /* notdef */
+ amstrategy = 1;
+ relam = indexRelation->rd_rel->relam;
+ info->relam = relam;
+ info->pages = indexRelation->rd_rel->relpages;
+ info->tuples = indexRelation->rd_rel->reltuples;
+ heap_close(indexRelation);
+
+ /*
+ * Find the index ordering keys
+ *
+ * Must use indclass to know when to stop looking since with functional
+ * indices there could be several keys (args) for one opclass. -mer 27
+ * Sept 1991
+ */
+ for (i = 0; i < 8 && index->indclass[i]; ++i)
+ {
+ amopTuple = SearchSysCacheTuple(AMOPSTRATEGY,
+ ObjectIdGetDatum(relam),
+ ObjectIdGetDatum(index->indclass[i]),
+ UInt16GetDatum(amstrategy),
+ 0);
+ if (!HeapTupleIsValid(amopTuple))
+ elog(WARN, "index_info: no amop %d %d %d",
+ relam, index->indclass[i], amstrategy);
+ info->orderOprs[i] =
+ ((Form_pg_amop) GETSTRUCT(amopTuple))->amopopr;
+ }
+ return (TRUE);
}
-/*
+/*
* index-selectivity--
- *
- * Call util/plancat.c:IndexSelectivity with the indicated arguments.
- *
+ *
+ * Call util/plancat.c:IndexSelectivity with the indicated arguments.
+ *
* 'indid' is the index OID
* 'classes' is a list of index key classes
* 'opnos' is a list of index key operator OIDs
@@ -229,153 +239,162 @@ index_info(Query *root, bool first, int relid, IdxInfoRetval *info)
* 'values' is a list of the values of the clause's constants
* 'flags' is a list of fixnums which describe the constants
* 'nkeys' is the number of index keys
- *
+ *
* Returns two floats: index pages and index selectivity in 'idxPages' and
- * 'idxSelec'.
- *
+ * 'idxSelec'.
+ *
*/
void
index_selectivity(Oid indid,
- Oid *classes,
- List *opnos,
- Oid relid,
- List *attnos,
- List *values,
- List *flags,
- int32 nkeys,
- float *idxPages,
- float *idxSelec)
+ Oid * classes,
+ List * opnos,
+ Oid relid,
+ List * attnos,
+ List * values,
+ List * flags,
+ int32 nkeys,
+ float *idxPages,
+ float *idxSelec)
{
- Oid *opno_array;
- int *attno_array, *flag_array;
- char **value_array;
- int i = 0;
- List *xopno, *xattno, *value, *flag;
+ Oid *opno_array;
+ int *attno_array,
+ *flag_array;
+ char **value_array;
+ int i = 0;
+ List *xopno,
+ *xattno,
+ *value,
+ *flag;
+
+ if (length(opnos) != nkeys || length(attnos) != nkeys ||
+ length(values) != nkeys || length(flags) != nkeys)
+ {
+
+ *idxPages = 0.0;
+ *idxSelec = 1.0;
+ return;
+ }
- if (length(opnos)!=nkeys || length(attnos)!=nkeys ||
- length(values)!=nkeys || length(flags)!=nkeys) {
+ opno_array = (Oid *) palloc(nkeys * sizeof(Oid));
+ attno_array = (int *) palloc(nkeys * sizeof(int32));
+ value_array = (char **) palloc(nkeys * sizeof(char *));
+ flag_array = (int *) palloc(nkeys * sizeof(int32));
- *idxPages = 0.0;
- *idxSelec = 1.0;
+ i = 0;
+ foreach(xopno, opnos)
+ {
+ opno_array[i++] = lfirsti(xopno);
+ }
+
+ i = 0;
+ foreach(xattno, attnos)
+ {
+ attno_array[i++] = lfirsti(xattno);
+ }
+
+ i = 0;
+ foreach(value, values)
+ {
+ value_array[i++] = (char *) lfirst(value);
+ }
+
+ i = 0;
+ foreach(flag, flags)
+ {
+ flag_array[i++] = lfirsti(flag);
+ }
+
+ IndexSelectivity(indid,
+ relid,
+ nkeys,
+ classes, /* not used */
+ opno_array,
+ attno_array,
+ value_array,
+ flag_array,
+ idxPages,
+ idxSelec);
return;
- }
-
- opno_array = (Oid *)palloc(nkeys*sizeof(Oid));
- attno_array = (int *)palloc(nkeys*sizeof(int32));
- value_array = (char **)palloc(nkeys*sizeof(char *));
- flag_array = (int *)palloc(nkeys*sizeof(int32));
-
- i = 0;
- foreach(xopno, opnos) {
- opno_array[i++] = lfirsti(xopno);
- }
-
- i = 0;
- foreach(xattno,attnos) {
- attno_array[i++] = lfirsti(xattno);
- }
-
- i = 0;
- foreach(value, values) {
- value_array[i++] = (char *)lfirst(value);
- }
-
- i = 0;
- foreach(flag,flags) {
- flag_array[i++] = lfirsti(flag);
- }
-
- IndexSelectivity(indid,
- relid,
- nkeys,
- classes, /* not used */
- opno_array,
- attno_array,
- value_array,
- flag_array,
- idxPages,
- idxSelec);
- return;
}
/*
* restriction_selectivity in lisp system.--
*
- * NOTE: The routine is now merged with RestrictionClauseSelectivity
- * as defined in plancat.c
+ * NOTE: The routine is now merged with RestrictionClauseSelectivity
+ * as defined in plancat.c
*
* Returns the selectivity of a specified operator.
* This code executes registered procedures stored in the
* operator relation, by calling the function manager.
*
* XXX The assumption in the selectivity procedures is that if the
- * relation OIDs or attribute numbers are -1, then the clause
- * isn't of the form (op var const).
+ * relation OIDs or attribute numbers are -1, then the clause
+ * isn't of the form (op var const).
*/
Cost
restriction_selectivity(Oid functionObjectId,
- Oid operatorObjectId,
- Oid relationObjectId,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag)
+ Oid operatorObjectId,
+ Oid relationObjectId,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag)
{
- float64 result;
-
- result = (float64) fmgr(functionObjectId,
- (char *) operatorObjectId,
- (char *) relationObjectId,
- (char *) (int)attributeNumber,
- (char *) constValue,
- (char *) constFlag,
- NULL);
- if (!PointerIsValid(result))
- elog(WARN, "RestrictionClauseSelectivity: bad pointer");
-
- if (*result < 0.0 || *result > 1.0)
- elog(WARN, "RestrictionClauseSelectivity: bad value %lf",
- *result);
-
- return ((Cost)*result);
+ float64 result;
+
+ result = (float64) fmgr(functionObjectId,
+ (char *) operatorObjectId,
+ (char *) relationObjectId,
+ (char *) (int) attributeNumber,
+ (char *) constValue,
+ (char *) constFlag,
+ NULL);
+ if (!PointerIsValid(result))
+ elog(WARN, "RestrictionClauseSelectivity: bad pointer");
+
+ if (*result < 0.0 || *result > 1.0)
+ elog(WARN, "RestrictionClauseSelectivity: bad value %lf",
+ *result);
+
+ return ((Cost) * result);
}
/*
* join_selectivity--
- * Similarly, this routine is merged with JoinClauseSelectivity in
- * plancat.c
+ * Similarly, this routine is merged with JoinClauseSelectivity in
+ * plancat.c
*
- * Returns the selectivity of an operator, given the join clause
- * information.
+ * Returns the selectivity of an operator, given the join clause
+ * information.
*
* XXX The assumption in the selectivity procedures is that if the
- * relation OIDs or attribute numbers are -1, then the clause
- * isn't of the form (op var var).
+ * relation OIDs or attribute numbers are -1, then the clause
+ * isn't of the form (op var var).
*/
Cost
-join_selectivity (Oid functionObjectId,
- Oid operatorObjectId,
- Oid relationObjectId1,
- AttrNumber attributeNumber1,
- Oid relationObjectId2,
- AttrNumber attributeNumber2)
+join_selectivity(Oid functionObjectId,
+ Oid operatorObjectId,
+ Oid relationObjectId1,
+ AttrNumber attributeNumber1,
+ Oid relationObjectId2,
+ AttrNumber attributeNumber2)
{
- float64 result;
-
- result = (float64) fmgr(functionObjectId,
- (char *) operatorObjectId,
- (char *) relationObjectId1,
- (char *) (int)attributeNumber1,
- (char *) relationObjectId2,
- (char *) (int)attributeNumber2,
- NULL);
- if (!PointerIsValid(result))
- elog(WARN, "JoinClauseSelectivity: bad pointer");
-
- if (*result < 0.0 || *result > 1.0)
- elog(WARN, "JoinClauseSelectivity: bad value %lf",
- *result);
-
- return((Cost)*result);
+ float64 result;
+
+ result = (float64) fmgr(functionObjectId,
+ (char *) operatorObjectId,
+ (char *) relationObjectId1,
+ (char *) (int) attributeNumber1,
+ (char *) relationObjectId2,
+ (char *) (int) attributeNumber2,
+ NULL);
+ if (!PointerIsValid(result))
+ elog(WARN, "JoinClauseSelectivity: bad pointer");
+
+ if (*result < 0.0 || *result > 1.0)
+ elog(WARN, "JoinClauseSelectivity: bad value %lf",
+ *result);
+
+ return ((Cost) * result);
}
/*
@@ -384,33 +403,34 @@ join_selectivity (Oid functionObjectId,
* Returns a LISP list containing the OIDs of all relations which
* inherits from the relation with OID 'inhparent'.
*/
-List *
+List *
find_inheritance_children(Oid inhparent)
{
- static ScanKeyData key[1] = {
- { 0, Anum_pg_inherits_inhparent, F_OIDEQ }
- };
-
- HeapTuple inheritsTuple;
- Relation relation;
- HeapScanDesc scan;
- List *list = NIL;
- Oid inhrelid;
-
- fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs);
-
- key[0].sk_argument = ObjectIdGetDatum((Oid)inhparent);
- relation = heap_openr(InheritsRelationName);
- scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
- while (HeapTupleIsValid(inheritsTuple =
- heap_getnext(scan, 0,
- (Buffer *) NULL))) {
- inhrelid = ((InheritsTupleForm)GETSTRUCT(inheritsTuple))->inhrel;
- list = lappendi(list, inhrelid);
- }
- heap_endscan(scan);
- heap_close(relation);
- return(list);
+ static ScanKeyData key[1] = {
+ {0, Anum_pg_inherits_inhparent, F_OIDEQ}
+ };
+
+ HeapTuple inheritsTuple;
+ Relation relation;
+ HeapScanDesc scan;
+ List *list = NIL;
+ Oid inhrelid;
+
+ fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs);
+
+ key[0].sk_argument = ObjectIdGetDatum((Oid) inhparent);
+ relation = heap_openr(InheritsRelationName);
+ scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
+ while (HeapTupleIsValid(inheritsTuple =
+ heap_getnext(scan, 0,
+ (Buffer *) NULL)))
+ {
+ inhrelid = ((InheritsTupleForm) GETSTRUCT(inheritsTuple))->inhrel;
+ list = lappendi(list, inhrelid);
+ }
+ heap_endscan(scan);
+ heap_close(relation);
+ return (list);
}
/*
@@ -419,39 +439,40 @@ find_inheritance_children(Oid inhparent)
* Returns a LISP list containing the OIDs of all relations which are
* base relations of the relation with OID 'verrelid'.
*/
-List *
+List *
VersionGetParents(Oid verrelid)
{
- static ScanKeyData key[1] = {
- { 0, Anum_pg_version_verrelid, F_OIDEQ }
- };
-
- HeapTuple versionTuple;
- Relation relation;
- HeapScanDesc scan;
- Oid verbaseid;
- List *list= NIL;
-
- fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs);
- relation = heap_openr(VersionRelationName);
- key[0].sk_argument = ObjectIdGetDatum(verrelid);
- scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
- for (;;) {
- versionTuple = heap_getnext(scan, 0,
- (Buffer *) NULL);
- if (!HeapTupleIsValid(versionTuple))
- break;
- verbaseid = ((VersionTupleForm)
- GETSTRUCT(versionTuple))->verbaseid;
-
- list = lconsi(verbaseid, list);
-
- key[0].sk_argument = ObjectIdGetDatum(verbaseid);
- heap_rescan(scan, 0, key);
- }
- heap_endscan(scan);
- heap_close(relation);
- return(list);
+ static ScanKeyData key[1] = {
+ {0, Anum_pg_version_verrelid, F_OIDEQ}
+ };
+
+ HeapTuple versionTuple;
+ Relation relation;
+ HeapScanDesc scan;
+ Oid verbaseid;
+ List *list = NIL;
+
+ fmgr_info(F_OIDEQ, &key[0].sk_func, &key[0].sk_nargs);
+ relation = heap_openr(VersionRelationName);
+ key[0].sk_argument = ObjectIdGetDatum(verrelid);
+ scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
+ for (;;)
+ {
+ versionTuple = heap_getnext(scan, 0,
+ (Buffer *) NULL);
+ if (!HeapTupleIsValid(versionTuple))
+ break;
+ verbaseid = ((VersionTupleForm)
+ GETSTRUCT(versionTuple))->verbaseid;
+
+ list = lconsi(verbaseid, list);
+
+ key[0].sk_argument = ObjectIdGetDatum(verbaseid);
+ heap_rescan(scan, 0, key);
+ }
+ heap_endscan(scan);
+ heap_close(relation);
+ return (list);
}
/*****************************************************************************
@@ -461,14 +482,14 @@ VersionGetParents(Oid verrelid)
/*
* IdexSelectivity--
*
- * Retrieves the 'amopnpages' and 'amopselect' parameters for each
- * AM operator when a given index (specified by 'indexrelid') is used.
- * These two parameters are returned by copying them to into an array of
- * floats.
+ * Retrieves the 'amopnpages' and 'amopselect' parameters for each
+ * AM operator when a given index (specified by 'indexrelid') is used.
+ * These two parameters are returned by copying them to into an array of
+ * floats.
*
- * Assumption: the attribute numbers and operator ObjectIds are in order
- * WRT to each other (otherwise, you have no way of knowing which
- * AM operator class or attribute number corresponds to which operator.
+ * Assumption: the attribute numbers and operator ObjectIds are in order
+ * WRT to each other (otherwise, you have no way of knowing which
+ * AM operator class or attribute number corresponds to which operator.
*
* 'varAttributeNumbers' contains attribute numbers for variables
* 'constValues' contains the constant values
@@ -481,144 +502,154 @@ VersionGetParents(Oid verrelid)
*/
static void
IndexSelectivity(Oid indexrelid,
- Oid indrelid,
- int32 nIndexKeys,
- Oid AccessMethodOperatorClasses[], /* XXX not used? */
- Oid operatorObjectIds[],
- int32 varAttributeNumbers[],
- char *constValues[],
- int32 constFlags[],
- float *idxPages,
- float *idxSelec)
+ Oid indrelid,
+ int32 nIndexKeys,
+ Oid AccessMethodOperatorClasses[], /* XXX not used? */
+ Oid operatorObjectIds[],
+ int32 varAttributeNumbers[],
+ char *constValues[],
+ int32 constFlags[],
+ float *idxPages,
+ float *idxSelec)
{
- register i, n;
- HeapTuple indexTuple, amopTuple, indRel;
- IndexTupleForm index;
- Form_pg_amop amop;
- Oid indclass;
- float64data npages, select;
- float64 amopnpages, amopselect;
- Oid relam;
- bool nphack = false;
- float64data fattr_select = 1.0;
-
- indRel = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(indexrelid),
- 0,0,0);
- if (!HeapTupleIsValid(indRel))
- elog(WARN, "IndexSelectivity: index %d not found",
- indexrelid);
- relam = ((Form_pg_class)GETSTRUCT(indRel))->relam;
-
- indexTuple = SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(indexrelid),
- 0,0,0);
- if (!HeapTupleIsValid(indexTuple))
- elog(WARN, "IndexSelectivity: index %d not found",
- indexrelid);
- index = (IndexTupleForm)GETSTRUCT(indexTuple);
-
- /*
- * Hack for non-functional btree npages estimation:
- * npages = index_pages * selectivity_of_1st_attr_clause(s)
- * - vadim 04/24/97
- */
- if ( relam == BTREE_AM_OID &&
- varAttributeNumbers[0] != InvalidAttrNumber )
- nphack = true;
-
- npages = 0.0;
- select = 1.0;
- for (n = 0; n < nIndexKeys; ++n) {
- /*
- * Find the AM class for this key.
- *
- * If the first attribute number is invalid then we have a
- * functional index, and AM class is the first one defined
- * since functional indices have exactly one key.
+ register i,
+ n;
+ HeapTuple indexTuple,
+ amopTuple,
+ indRel;
+ IndexTupleForm index;
+ Form_pg_amop amop;
+ Oid indclass;
+ float64data npages,
+ select;
+ float64 amopnpages,
+ amopselect;
+ Oid relam;
+ bool nphack = false;
+ float64data fattr_select = 1.0;
+
+ indRel = SearchSysCacheTuple(RELOID,
+ ObjectIdGetDatum(indexrelid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(indRel))
+ elog(WARN, "IndexSelectivity: index %d not found",
+ indexrelid);
+ relam = ((Form_pg_class) GETSTRUCT(indRel))->relam;
+
+ indexTuple = SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(indexrelid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(indexTuple))
+ elog(WARN, "IndexSelectivity: index %d not found",
+ indexrelid);
+ index = (IndexTupleForm) GETSTRUCT(indexTuple);
+
+ /*
+ * Hack for non-functional btree npages estimation: npages =
+ * index_pages * selectivity_of_1st_attr_clause(s) - vadim 04/24/97
*/
- indclass = (varAttributeNumbers[0] == InvalidAttrNumber) ?
- index->indclass[0] : InvalidOid;
- i = 0;
- while ((i < nIndexKeys) && (indclass == InvalidOid)) {
- if (varAttributeNumbers[n] == index->indkey[i]) {
- indclass = index->indclass[i];
- break;
- }
- i++;
- }
- if (!OidIsValid(indclass)) {
- /*
- * Presumably this means that we are using a functional
- * index clause and so had no variable to match to
- * the index key ... if not we are in trouble.
- */
- elog(NOTICE, "IndexSelectivity: no key %d in index %d",
- varAttributeNumbers[n], indexrelid);
- continue;
- }
+ if (relam == BTREE_AM_OID &&
+ varAttributeNumbers[0] != InvalidAttrNumber)
+ nphack = true;
- amopTuple = SearchSysCacheTuple(AMOPOPID,
- ObjectIdGetDatum(indclass),
- ObjectIdGetDatum(operatorObjectIds[n]),
- ObjectIdGetDatum(relam),
- 0);
- if (!HeapTupleIsValid(amopTuple))
- elog(WARN, "IndexSelectivity: no amop %d %d",
- indclass, operatorObjectIds[n]);
- amop = (Form_pg_amop)GETSTRUCT(amopTuple);
-
- if ( !nphack )
+ npages = 0.0;
+ select = 1.0;
+ for (n = 0; n < nIndexKeys; ++n)
{
- amopnpages = (float64) fmgr(amop->amopnpages,
- (char *) operatorObjectIds[n],
- (char *) indrelid,
- (char *) varAttributeNumbers[n],
- (char *) constValues[n],
- (char *) constFlags[n],
- (char *) nIndexKeys,
- (char *) indexrelid);
-#if 0
-/*
+
+ /*
+ * Find the AM class for this key.
+ *
+ * If the first attribute number is invalid then we have a functional
+ * index, and AM class is the first one defined since functional
+ * indices have exactly one key.
+ */
+ indclass = (varAttributeNumbers[0] == InvalidAttrNumber) ?
+ index->indclass[0] : InvalidOid;
+ i = 0;
+ while ((i < nIndexKeys) && (indclass == InvalidOid))
+ {
+ if (varAttributeNumbers[n] == index->indkey[i])
+ {
+ indclass = index->indclass[i];
+ break;
+ }
+ i++;
+ }
+ if (!OidIsValid(indclass))
+ {
+
+ /*
+ * Presumably this means that we are using a functional index
+ * clause and so had no variable to match to the index key ...
+ * if not we are in trouble.
+ */
+ elog(NOTICE, "IndexSelectivity: no key %d in index %d",
+ varAttributeNumbers[n], indexrelid);
+ continue;
+ }
+
+ amopTuple = SearchSysCacheTuple(AMOPOPID,
+ ObjectIdGetDatum(indclass),
+ ObjectIdGetDatum(operatorObjectIds[n]),
+ ObjectIdGetDatum(relam),
+ 0);
+ if (!HeapTupleIsValid(amopTuple))
+ elog(WARN, "IndexSelectivity: no amop %d %d",
+ indclass, operatorObjectIds[n]);
+ amop = (Form_pg_amop) GETSTRUCT(amopTuple);
+
+ if (!nphack)
+ {
+ amopnpages = (float64) fmgr(amop->amopnpages,
+ (char *) operatorObjectIds[n],
+ (char *) indrelid,
+ (char *) varAttributeNumbers[n],
+ (char *) constValues[n],
+ (char *) constFlags[n],
+ (char *) nIndexKeys,
+ (char *) indexrelid);
+#if 0
+/*
* So cool guys! Npages for x > 10 and x < 20 is twice as
* npages for x > 10! - vadim 04/09/97
*/
- npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
- if ((i = npages) < npages) /* ceil(npages)? */
- npages += 1.0;
+ npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
+ if ((i = npages) < npages) /* ceil(npages)? */
+ npages += 1.0;
#endif
- npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
+ npages += PointerIsValid(amopnpages) ? *amopnpages : 0.0;
+ }
+
+ amopselect = (float64) fmgr(amop->amopselect,
+ (char *) operatorObjectIds[n],
+ (char *) indrelid,
+ (char *) varAttributeNumbers[n],
+ (char *) constValues[n],
+ (char *) constFlags[n],
+ (char *) nIndexKeys,
+ (char *) indexrelid);
+
+ if (nphack && varAttributeNumbers[n] == index->indkey[0])
+ fattr_select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
+
+ select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
}
-
- amopselect = (float64) fmgr(amop->amopselect,
- (char *) operatorObjectIds[n],
- (char *) indrelid,
- (char *) varAttributeNumbers[n],
- (char *) constValues[n],
- (char *) constFlags[n],
- (char *) nIndexKeys,
- (char *) indexrelid);
-
- if ( nphack && varAttributeNumbers[n] == index->indkey[0] )
- fattr_select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
-
- select *= PointerIsValid(amopselect) ? *amopselect : 1.0;
- }
- /*
- * Estimation of npages below is hack of course, but it's
- * better than it was before. - vadim 04/09/97
- */
- if ( nphack )
- {
- npages = fattr_select * ((Form_pg_class)GETSTRUCT(indRel))->relpages;
- *idxPages = ceil ((double)npages);
- }
- else
- {
- if ( nIndexKeys > 1 )
- npages = npages / (1.0 + nIndexKeys);
- *idxPages = ceil ((double)(npages/nIndexKeys));
- }
- *idxSelec = select;
-}
+ /*
+ * Estimation of npages below is hack of course, but it's better than
+ * it was before. - vadim 04/09/97
+ */
+ if (nphack)
+ {
+ npages = fattr_select * ((Form_pg_class) GETSTRUCT(indRel))->relpages;
+ *idxPages = ceil((double) npages);
+ }
+ else
+ {
+ if (nIndexKeys > 1)
+ npages = npages / (1.0 + nIndexKeys);
+ *idxPages = ceil((double) (npages / nIndexKeys));
+ }
+ *idxSelec = select;
+}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 351fb182107..229dff98092 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* relnode.c--
- * Relation manipulation routines
+ * Relation manipulation routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.1.1.1 1996/07/09 06:21:39 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.2 1997/09/07 04:44:32 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,108 +16,118 @@
#include "nodes/relation.h"
#include "optimizer/internal.h"
-#include "optimizer/pathnode.h" /* where the decls go */
+#include "optimizer/pathnode.h" /* where the decls go */
#include "optimizer/plancat.h"
-/*
+/*
* get_base_rel--
- * Returns relation entry corresponding to 'relid', creating a new one if
- * necessary. This is for base relations.
- *
+ * Returns relation entry corresponding to 'relid', creating a new one if
+ * necessary. This is for base relations.
+ *
*/
-Rel *get_base_rel(Query* root, int relid)
+Rel *
+get_base_rel(Query * root, int relid)
{
- List *relids;
- Rel *rel;
+ List *relids;
+ Rel *rel;
+
+ relids = lconsi(relid, NIL);
+ rel = rel_member(relids, root->base_relation_list_);
+ if (rel == NULL)
+ {
+ rel = makeNode(Rel);
+ rel->relids = relids;
+ rel->indexed = false;
+ rel->pages = 0;
+ rel->tuples = 0;
+ rel->width = 0;
+ rel->targetlist = NIL;
+ rel->pathlist = NIL;
+ rel->unorderedpath = (Path *) NULL;
+ rel->cheapestpath = (Path *) NULL;
+ rel->pruneable = true;
+ rel->classlist = NULL;
+ rel->ordering = NULL;
+ rel->relam = InvalidOid;
+ rel->clauseinfo = NIL;
+ rel->joininfo = NIL;
+ rel->innerjoin = NIL;
+ rel->superrels = NIL;
+
+ root->base_relation_list_ = lcons(rel,
+ root->base_relation_list_);
+
+ /*
+ * ??? the old lispy C code (get_rel) do a listp(relid) here but
+ * that can never happen since we already established relid is not
+ * a list. -ay 10/94
+ */
+ if (relid < 0)
+ {
+
+ /*
+ * If the relation is a materialized relation, assume
+ * constants for sizes.
+ */
+ rel->pages = _TEMP_RELATION_PAGES_;
+ rel->tuples = _TEMP_RELATION_TUPLES_;
+
+ }
+ else
+ {
+ bool hasindex;
+ int pages,
+ tuples;
- relids = lconsi(relid, NIL);
- rel = rel_member(relids, root->base_relation_list_);
- if (rel==NULL) {
- rel = makeNode(Rel);
- rel->relids = relids;
- rel->indexed = false;
- rel->pages = 0;
- rel->tuples = 0;
- rel->width = 0;
- rel->targetlist = NIL;
- rel->pathlist = NIL;
- rel->unorderedpath = (Path *)NULL;
- rel->cheapestpath = (Path *)NULL;
- rel->pruneable = true;
- rel->classlist = NULL;
- rel->ordering = NULL;
- rel->relam = InvalidOid;
- rel->clauseinfo = NIL;
- rel->joininfo = NIL;
- rel->innerjoin = NIL;
- rel->superrels = NIL;
-
- root->base_relation_list_ = lcons(rel,
- root->base_relation_list_);
-
- /*
- * ??? the old lispy C code (get_rel) do a listp(relid) here but
- * that can never happen since we already established relid is not
- * a list. -ay 10/94
- */
- if(relid < 0) {
- /*
- * If the relation is a materialized relation, assume
- * constants for sizes.
- */
- rel->pages = _TEMP_RELATION_PAGES_;
- rel->tuples = _TEMP_RELATION_TUPLES_;
-
- } else {
- bool hasindex;
- int pages, tuples;
-
- /*
- * Otherwise, retrieve relation characteristics from the
- * system catalogs.
- */
- relation_info(root, relid, &hasindex, &pages, &tuples);
- rel->indexed = hasindex;
- rel->pages = pages;
- rel->tuples = tuples;
- }
- }
- return rel;
+ /*
+ * Otherwise, retrieve relation characteristics from the
+ * system catalogs.
+ */
+ relation_info(root, relid, &hasindex, &pages, &tuples);
+ rel->indexed = hasindex;
+ rel->pages = pages;
+ rel->tuples = tuples;
+ }
+ }
+ return rel;
}
-/*
+/*
* get_join_rel--
- * Returns relation entry corresponding to 'relid' (a list of relids),
- * creating a new one if necessary. This is for join relations.
- *
+ * Returns relation entry corresponding to 'relid' (a list of relids),
+ * creating a new one if necessary. This is for join relations.
+ *
*/
-Rel *get_join_rel(Query *root, List *relid)
+Rel *
+get_join_rel(Query * root, List * relid)
{
- return rel_member(relid, root->join_relation_list_);
+ return rel_member(relid, root->join_relation_list_);
}
-/*
+/*
* rel-member--
- * Determines whether a relation of id 'relid' is contained within a list
- * 'rels'.
- *
+ * Determines whether a relation of id 'relid' is contained within a list
+ * 'rels'.
+ *
* Returns the corresponding entry in 'rels' if it is there.
- *
+ *
*/
-Rel *
-rel_member(List *relid, List *rels)
+Rel *
+rel_member(List * relid, List * rels)
{
- List *temp = NIL;
- List *temprelid = NIL;
-
- if (relid!=NIL && rels!=NIL) {
- foreach(temp,rels) {
- temprelid = ((Rel*)lfirst(temp))->relids;
- if(same(temprelid, relid))
- return((Rel*)(lfirst(temp)));
+ List *temp = NIL;
+ List *temprelid = NIL;
+
+ if (relid != NIL && rels != NIL)
+ {
+ foreach(temp, rels)
+ {
+ temprelid = ((Rel *) lfirst(temp))->relids;
+ if (same(temprelid, relid))
+ return ((Rel *) (lfirst(temp)));
+ }
}
- }
- return(NULL);
+ return (NULL);
}
diff --git a/src/backend/optimizer/util/tlist.c b/src/backend/optimizer/util/tlist.c
index c0f11ff3293..7e8563d31ab 100644
--- a/src/backend/optimizer/util/tlist.c
+++ b/src/backend/optimizer/util/tlist.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* tlist.c--
- * Target list manipulation routines
+ * Target list manipulation routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.4 1997/08/20 14:53:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/tlist.c,v 1.5 1997/09/07 04:44:33 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,498 +28,538 @@
#include "nodes/makefuncs.h"
#include "parser/catalog_utils.h"
-static Node *flatten_tlistentry(Node *tlistentry, List *flat_tlist);
+static Node *flatten_tlistentry(Node * tlistentry, List * flat_tlist);
/*****************************************************************************
- * ---------- RELATION node target list routines ----------
+ * ---------- RELATION node target list routines ----------
*****************************************************************************/
-/*
+/*
* tlistentry-member--
- *
+ *
* RETURNS: the leftmost member of sequence "targetlist" that satisfies
- * the predicate "var_equal"
+ * the predicate "var_equal"
* MODIFIES: nothing
* REQUIRES: test = function which can operate on a lispval union
- * var = valid var-node
- * targetlist = valid sequence
+ * var = valid var-node
+ * targetlist = valid sequence
*/
-TargetEntry *
-tlistentry_member(Var *var, List *targetlist)
+TargetEntry *
+tlistentry_member(Var * var, List * targetlist)
{
- if (var) {
- List *temp = NIL;
-
- foreach (temp,targetlist) {
- if (var_equal(var,
- get_expr(lfirst(temp))))
- return((TargetEntry*)lfirst(temp));
+ if (var)
+ {
+ List *temp = NIL;
+
+ foreach(temp, targetlist)
+ {
+ if (var_equal(var,
+ get_expr(lfirst(temp))))
+ return ((TargetEntry *) lfirst(temp));
+ }
}
- }
- return (NULL);
+ return (NULL);
}
-/*
+/*
* matching_tlvar--
- *
+ *
* RETURNS: var node in a target list which is var_equal to 'var',
- * if one exists.
+ * if one exists.
* REQUIRES: "test" operates on lispval unions,
- *
+ *
*/
-Expr *
-matching_tlvar(Var *var, List *targetlist)
+Expr *
+matching_tlvar(Var * var, List * targetlist)
{
- TargetEntry *tlentry;
+ TargetEntry *tlentry;
- tlentry = tlistentry_member(var,targetlist);
- if (tlentry)
- return((Expr*)get_expr (tlentry) );
+ tlentry = tlistentry_member(var, targetlist);
+ if (tlentry)
+ return ((Expr *) get_expr(tlentry));
- return((Expr*) NULL);
+ return ((Expr *) NULL);
}
-/*
+/*
* add_tl_element--
- * Creates a targetlist entry corresponding to the supplied var node
+ * Creates a targetlist entry corresponding to the supplied var node
*
* 'var' and adds the new targetlist entry to the targetlist field of
- * 'rel'
- *
+ * 'rel'
+ *
* RETURNS: nothing
* MODIFIES: vartype and varid fields of leftmost varnode that matches
- * argument "var" (sometimes).
+ * argument "var" (sometimes).
* CREATES: new var-node iff no matching var-node exists in targetlist
*/
void
-add_tl_element(Rel *rel, Var *var)
+add_tl_element(Rel * rel, Var * var)
{
- Expr *oldvar = (Expr *)NULL;
-
- oldvar = matching_tlvar(var, rel->targetlist);
-
- /*
- * If 'var' is not already in 'rel's target list, add a new node.
- */
- if (oldvar==NULL) {
- List *tlist = rel->targetlist;
- Var *newvar = makeVar(var->varno,
- var->varattno,
- var->vartype,
- var->varno,
- var->varoattno);
-
- rel->targetlist =
- lappend (tlist,
- create_tl_element(newvar,
- length(tlist) + 1));
-
- }
+ Expr *oldvar = (Expr *) NULL;
+
+ oldvar = matching_tlvar(var, rel->targetlist);
+
+ /*
+ * If 'var' is not already in 'rel's target list, add a new node.
+ */
+ if (oldvar == NULL)
+ {
+ List *tlist = rel->targetlist;
+ Var *newvar = makeVar(var->varno,
+ var->varattno,
+ var->vartype,
+ var->varno,
+ var->varoattno);
+
+ rel->targetlist =
+ lappend(tlist,
+ create_tl_element(newvar,
+ length(tlist) + 1));
+
+ }
}
-/*
+/*
* create_tl_element--
- * Creates a target list entry node and its associated (resdom var) pair
- * with its resdom number equal to 'resdomno' and the joinlist field set
- * to 'joinlist'.
- *
+ * Creates a target list entry node and its associated (resdom var) pair
+ * with its resdom number equal to 'resdomno' and the joinlist field set
+ * to 'joinlist'.
+ *
* RETURNS: newly created tlist-entry
* CREATES: new targetlist entry (always).
*/
-TargetEntry*
-create_tl_element(Var *var, int resdomno)
+TargetEntry *
+create_tl_element(Var * var, int resdomno)
{
- TargetEntry *tlelement= makeNode(TargetEntry);
-
- tlelement->resdom =
- makeResdom(resdomno,
- var->vartype,
- get_typlen(var->vartype),
- NULL,
- (Index)0,
- (Oid)0,
- 0);
- tlelement->expr = (Node*)var;
-
- return(tlelement);
+ TargetEntry *tlelement = makeNode(TargetEntry);
+
+ tlelement->resdom =
+ makeResdom(resdomno,
+ var->vartype,
+ get_typlen(var->vartype),
+ NULL,
+ (Index) 0,
+ (Oid) 0,
+ 0);
+ tlelement->expr = (Node *) var;
+
+ return (tlelement);
}
-/*
+/*
* get-actual-tlist--
- * Returns the targetlist elements from a relation tlist.
- *
+ * Returns the targetlist elements from a relation tlist.
+ *
*/
-List *
-get_actual_tlist(List *tlist)
+List *
+get_actual_tlist(List * tlist)
{
- /*
- * this function is not making sense. - ay 10/94
- */
-#if 0
- List *element = NIL;
- List *result = NIL;
-
- if (tlist==NULL) {
- elog(DEBUG,"calling get_actual_tlist with empty tlist");
- return(NIL);
- }
- /* XXX - it is unclear to me what exactly get_entry
- should be doing, as it is unclear to me the exact
- relationship between "TL" "TLE" and joinlists */
-
- foreach(element,tlist)
- result = lappend(result, lfirst((List*)lfirst(element)));
-
- return(result);
+
+ /*
+ * this function is not making sense. - ay 10/94
+ */
+#if 0
+ List *element = NIL;
+ List *result = NIL;
+
+ if (tlist == NULL)
+ {
+ elog(DEBUG, "calling get_actual_tlist with empty tlist");
+ return (NIL);
+ }
+
+ /*
+ * XXX - it is unclear to me what exactly get_entry should be doing,
+ * as it is unclear to me the exact relationship between "TL" "TLE"
+ * and joinlists
+ */
+
+ foreach(element, tlist)
+ result = lappend(result, lfirst((List *) lfirst(element)));
+
+ return (result);
#endif
- return tlist;
+ return tlist;
}
/*****************************************************************************
- * ---------- GENERAL target list routines ----------
+ * ---------- GENERAL target list routines ----------
*****************************************************************************/
-/*
+/*
* tlist-member--
- * Determines whether a var node is already contained within a
- * target list.
- *
+ * Determines whether a var node is already contained within a
+ * target list.
+ *
* 'var' is the var node
* 'tlist' is the target list
* 'dots' is t if we must match dotfields to determine uniqueness
- *
+ *
* Returns the resdom entry of the matching var node.
- *
+ *
*/
-Resdom *
-tlist_member(Var *var, List *tlist)
+Resdom *
+tlist_member(Var * var, List * tlist)
{
- List *i = NIL;
- TargetEntry *temp_tle = (TargetEntry *)NULL;
- TargetEntry *tl_elt = (TargetEntry *)NULL;
-
- if (var) {
- foreach (i,tlist) {
- temp_tle = (TargetEntry *)lfirst(i);
- if (var_equal(var, get_expr(temp_tle))) {
- tl_elt = temp_tle;
- break;
- }
+ List *i = NIL;
+ TargetEntry *temp_tle = (TargetEntry *) NULL;
+ TargetEntry *tl_elt = (TargetEntry *) NULL;
+
+ if (var)
+ {
+ foreach(i, tlist)
+ {
+ temp_tle = (TargetEntry *) lfirst(i);
+ if (var_equal(var, get_expr(temp_tle)))
+ {
+ tl_elt = temp_tle;
+ break;
+ }
+ }
+
+ if (tl_elt != NULL)
+ return (tl_elt->resdom);
+ else
+ return ((Resdom *) NULL);
}
-
- if (tl_elt != NULL)
- return(tl_elt->resdom);
- else
- return((Resdom*)NULL);
- }
- return ((Resdom*)NULL);
+ return ((Resdom *) NULL);
}
/*
- * Routine to get the resdom out of a targetlist.
+ * Routine to get the resdom out of a targetlist.
*/
-Resdom *
-tlist_resdom(List *tlist, Resdom *resnode)
+Resdom *
+tlist_resdom(List * tlist, Resdom * resnode)
{
- Resdom *resdom = (Resdom*)NULL;
- List *i = NIL;
- TargetEntry *temp_tle = (TargetEntry *)NULL;
-
- foreach(i,tlist) {
- temp_tle = (TargetEntry *)lfirst(i);
- resdom = temp_tle->resdom;
- /* Since resnos are supposed to be unique */
- if (resnode->resno == resdom->resno)
- return(resdom);
- }
- return((Resdom*)NULL);
+ Resdom *resdom = (Resdom *) NULL;
+ List *i = NIL;
+ TargetEntry *temp_tle = (TargetEntry *) NULL;
+
+ foreach(i, tlist)
+ {
+ temp_tle = (TargetEntry *) lfirst(i);
+ resdom = temp_tle->resdom;
+ /* Since resnos are supposed to be unique */
+ if (resnode->resno == resdom->resno)
+ return (resdom);
+ }
+ return ((Resdom *) NULL);
}
-/*
+/*
* match_varid--
- * Searches a target list for an entry with some desired varid.
- *
+ * Searches a target list for an entry with some desired varid.
+ *
* 'varid' is the desired id
* 'tlist' is the target list that is searched
- *
+ *
* Returns the target list entry (resdom var) of the matching var.
*
* Now checks to make sure array references (in addition to range
* table indices) are identical - retrieve (a.b[1],a.b[2]) should
* not be turned into retrieve (a.b[1],a.b[1]).
- *
+ *
* [what used to be varid is now broken up into two fields varnoold and
- * varoattno. Also, nested attnos are long gone. - ay 2/95]
+ * varoattno. Also, nested attnos are long gone. - ay 2/95]
*/
-TargetEntry *
-match_varid(Var *test_var, List *tlist)
+TargetEntry *
+match_varid(Var * test_var, List * tlist)
{
- List *tl;
- Oid type_var;
+ List *tl;
+ Oid type_var;
- type_var = (Oid) test_var->vartype;
+ type_var = (Oid) test_var->vartype;
- foreach (tl, tlist) {
- TargetEntry *entry;
- Var *tlvar;
+ foreach(tl, tlist)
+ {
+ TargetEntry *entry;
+ Var *tlvar;
- entry = lfirst(tl);
- tlvar = get_expr(entry);
-
- if ( !IsA (tlvar, Var) )
- continue;
+ entry = lfirst(tl);
+ tlvar = get_expr(entry);
- /*
- * we test the original varno (instead of varno which might
- * be changed to INNER/OUTER.
- */
- if (tlvar->varnoold == test_var->varnoold &&
- tlvar->varoattno == test_var->varoattno) {
+ if (!IsA(tlvar, Var))
+ continue;
+
+ /*
+ * we test the original varno (instead of varno which might be
+ * changed to INNER/OUTER.
+ */
+ if (tlvar->varnoold == test_var->varnoold &&
+ tlvar->varoattno == test_var->varoattno)
+ {
- if (tlvar->vartype == type_var)
- return(entry);
+ if (tlvar->vartype == type_var)
+ return (entry);
+ }
}
- }
- return (NULL);
+ return (NULL);
}
-/*
+/*
* new-unsorted-tlist--
- * Creates a copy of a target list by creating new resdom nodes
- * without sort information.
- *
+ * Creates a copy of a target list by creating new resdom nodes
+ * without sort information.
+ *
* 'targetlist' is the target list to be copied.
- *
+ *
* Returns the resulting target list.
- *
+ *
*/
-List *
-new_unsorted_tlist(List *targetlist)
+List *
+new_unsorted_tlist(List * targetlist)
{
- List *new_targetlist = (List*)copyObject ((Node*)targetlist);
- List *x = NIL;
-
- foreach (x, new_targetlist) {
- TargetEntry *tle = (TargetEntry *)lfirst(x);
- tle->resdom->reskey = 0;
- tle->resdom->reskeyop = (Oid)0;
- }
- return(new_targetlist);
+ List *new_targetlist = (List *) copyObject((Node *) targetlist);
+ List *x = NIL;
+
+ foreach(x, new_targetlist)
+ {
+ TargetEntry *tle = (TargetEntry *) lfirst(x);
+
+ tle->resdom->reskey = 0;
+ tle->resdom->reskeyop = (Oid) 0;
+ }
+ return (new_targetlist);
}
-/*
+/*
* copy-vars--
- * Replaces the var nodes in the first target list with those from
- * the second target list. The two target lists are assumed to be
- * identical except their actual resdoms and vars are different.
- *
+ * Replaces the var nodes in the first target list with those from
+ * the second target list. The two target lists are assumed to be
+ * identical except their actual resdoms and vars are different.
+ *
* 'target' is the target list to be replaced
* 'source' is the target list to be copied
- *
+ *
* Returns a new target list.
- *
+ *
*/
-List *
-copy_vars(List *target, List *source)
+List *
+copy_vars(List * target, List * source)
{
- List *result = NIL;
- List *src = NIL;
- List *dest = NIL;
-
- for ( src = source, dest = target; src != NIL &&
- dest != NIL; src = lnext(src), dest = lnext(dest)) {
- TargetEntry *temp = MakeTLE(((TargetEntry *)lfirst(dest))->resdom,
- (Node*)get_expr(lfirst(src)));
- result = lappend(result,temp);
- }
- return(result);
+ List *result = NIL;
+ List *src = NIL;
+ List *dest = NIL;
+
+ for (src = source, dest = target; src != NIL &&
+ dest != NIL; src = lnext(src), dest = lnext(dest))
+ {
+ TargetEntry *temp = MakeTLE(((TargetEntry *) lfirst(dest))->resdom,
+ (Node *) get_expr(lfirst(src)));
+
+ result = lappend(result, temp);
+ }
+ return (result);
}
-/*
+/*
* flatten-tlist--
- * Create a target list that only contains unique variables.
+ * Create a target list that only contains unique variables.
*
*
* 'tlist' is the current target list
- *
+ *
* Returns the "flattened" new target list.
- *
+ *
*/
-List *
-flatten_tlist(List *tlist)
+List *
+flatten_tlist(List * tlist)
{
- int last_resdomno = 1;
- List *new_tlist = NIL;
- List *tlist_vars = NIL;
- List *temp;
-
- foreach (temp, tlist) {
- TargetEntry *temp_entry = NULL;
- List *vars;
-
- temp_entry = lfirst(temp);
- vars = pull_var_clause((Node*)get_expr(temp_entry));
- if(vars != NULL) {
- tlist_vars = nconc(tlist_vars, vars);
+ int last_resdomno = 1;
+ List *new_tlist = NIL;
+ List *tlist_vars = NIL;
+ List *temp;
+
+ foreach(temp, tlist)
+ {
+ TargetEntry *temp_entry = NULL;
+ List *vars;
+
+ temp_entry = lfirst(temp);
+ vars = pull_var_clause((Node *) get_expr(temp_entry));
+ if (vars != NULL)
+ {
+ tlist_vars = nconc(tlist_vars, vars);
+ }
}
- }
-
- foreach (temp, tlist_vars) {
- Var *var = lfirst(temp);
- if (!(tlist_member(var, new_tlist))) {
- Resdom *r;
-
- r = makeResdom(last_resdomno,
- var->vartype,
- get_typlen(var->vartype),
- NULL,
- (Index)0,
- (Oid)0,
- 0);
- last_resdomno++;
- new_tlist = lappend(new_tlist, MakeTLE (r, (Node*)var));
+
+ foreach(temp, tlist_vars)
+ {
+ Var *var = lfirst(temp);
+
+ if (!(tlist_member(var, new_tlist)))
+ {
+ Resdom *r;
+
+ r = makeResdom(last_resdomno,
+ var->vartype,
+ get_typlen(var->vartype),
+ NULL,
+ (Index) 0,
+ (Oid) 0,
+ 0);
+ last_resdomno++;
+ new_tlist = lappend(new_tlist, MakeTLE(r, (Node *) var));
+ }
}
- }
- return new_tlist;
+ return new_tlist;
}
-/*
+/*
* flatten-tlist-vars--
- * Redoes the target list of a query with no nested attributes by
- * replacing vars within computational expressions with vars from
- * the 'flattened' target list of the query.
- *
+ * Redoes the target list of a query with no nested attributes by
+ * replacing vars within computational expressions with vars from
+ * the 'flattened' target list of the query.
+ *
* 'full-tlist' is the actual target list
* 'flat-tlist' is the flattened (var-only) target list
- *
+ *
* Returns the modified actual target list.
- *
+ *
*/
-List *
-flatten_tlist_vars(List *full_tlist, List *flat_tlist)
+List *
+flatten_tlist_vars(List * full_tlist, List * flat_tlist)
{
- List *x = NIL;
- List *result = NIL;
-
- foreach(x,full_tlist) {
- TargetEntry *tle= lfirst(x);
- result =
- lappend(result,
- MakeTLE(tle->resdom,
- flatten_tlistentry((Node*)get_expr(tle),
- flat_tlist)));
- }
-
- return(result);
+ List *x = NIL;
+ List *result = NIL;
+
+ foreach(x, full_tlist)
+ {
+ TargetEntry *tle = lfirst(x);
+
+ result =
+ lappend(result,
+ MakeTLE(tle->resdom,
+ flatten_tlistentry((Node *) get_expr(tle),
+ flat_tlist)));
+ }
+
+ return (result);
}
-/*
+/*
* flatten-tlistentry--
- * Replaces vars within a target list entry with vars from a flattened
- * target list.
- *
+ * Replaces vars within a target list entry with vars from a flattened
+ * target list.
+ *
* 'tlistentry' is the target list entry to be modified
* 'flat-tlist' is the flattened target list
- *
+ *
* Returns the (modified) target_list entry from the target list.
- *
+ *
*/
-static Node *
-flatten_tlistentry(Node *tlistentry, List *flat_tlist)
+static Node *
+flatten_tlistentry(Node * tlistentry, List * flat_tlist)
{
- if (tlistentry==NULL) {
-
- return NULL;
-
- } else if (IsA (tlistentry,Var)) {
-
- return
- ((Node *)get_expr(match_varid((Var*)tlistentry,
- flat_tlist)));
- } else if (IsA (tlistentry,Iter)) {
-
- ((Iter*)tlistentry)->iterexpr =
- flatten_tlistentry((Node*)((Iter*)tlistentry)->iterexpr,
- flat_tlist);
- return tlistentry;
-
- } else if (single_node(tlistentry)) {
-
- return tlistentry;
-
- } else if (is_funcclause (tlistentry)) {
- Expr *expr = (Expr*)tlistentry;
- List *temp_result = NIL;
- List *elt = NIL;
-
- foreach(elt, expr->args)
- temp_result = lappend(temp_result,
- flatten_tlistentry(lfirst(elt),flat_tlist));
-
- return
- ((Node *)make_funcclause((Func*)expr->oper, temp_result));
-
- } else if (IsA(tlistentry,Aggreg)) {
-
- return tlistentry;
-
- } else if (IsA(tlistentry,ArrayRef)) {
- ArrayRef *aref = (ArrayRef *)tlistentry;
- List *temp = NIL;
- List *elt = NIL;
-
- foreach(elt, aref->refupperindexpr)
- temp = lappend(temp, flatten_tlistentry(lfirst(elt), flat_tlist));
- aref->refupperindexpr = temp;
-
- temp = NIL;
- foreach(elt, aref->reflowerindexpr)
- temp = lappend(temp, flatten_tlistentry(lfirst(elt), flat_tlist));
- aref->reflowerindexpr = temp;
-
- aref->refexpr =
- flatten_tlistentry(aref->refexpr, flat_tlist);
-
- aref->refassgnexpr =
- flatten_tlistentry(aref->refassgnexpr, flat_tlist);
-
- return tlistentry;
- } else {
- Expr *expr = (Expr*)tlistentry;
- Var *left =
- (Var*)flatten_tlistentry((Node*)get_leftop(expr),
- flat_tlist);
- Var *right =
- (Var*)flatten_tlistentry((Node*)get_rightop(expr),
- flat_tlist);
-
- return((Node *)
- make_opclause((Oper*)expr->oper, left, right));
- }
+ if (tlistentry == NULL)
+ {
+
+ return NULL;
+
+ }
+ else if (IsA(tlistentry, Var))
+ {
+
+ return
+ ((Node *) get_expr(match_varid((Var *) tlistentry,
+ flat_tlist)));
+ }
+ else if (IsA(tlistentry, Iter))
+ {
+
+ ((Iter *) tlistentry)->iterexpr =
+ flatten_tlistentry((Node *) ((Iter *) tlistentry)->iterexpr,
+ flat_tlist);
+ return tlistentry;
+
+ }
+ else if (single_node(tlistentry))
+ {
+
+ return tlistentry;
+
+ }
+ else if (is_funcclause(tlistentry))
+ {
+ Expr *expr = (Expr *) tlistentry;
+ List *temp_result = NIL;
+ List *elt = NIL;
+
+ foreach(elt, expr->args)
+ temp_result = lappend(temp_result,
+ flatten_tlistentry(lfirst(elt), flat_tlist));
+
+ return
+ ((Node *) make_funcclause((Func *) expr->oper, temp_result));
+
+ }
+ else if (IsA(tlistentry, Aggreg))
+ {
+
+ return tlistentry;
+
+ }
+ else if (IsA(tlistentry, ArrayRef))
+ {
+ ArrayRef *aref = (ArrayRef *) tlistentry;
+ List *temp = NIL;
+ List *elt = NIL;
+
+ foreach(elt, aref->refupperindexpr)
+ temp = lappend(temp, flatten_tlistentry(lfirst(elt), flat_tlist));
+ aref->refupperindexpr = temp;
+
+ temp = NIL;
+ foreach(elt, aref->reflowerindexpr)
+ temp = lappend(temp, flatten_tlistentry(lfirst(elt), flat_tlist));
+ aref->reflowerindexpr = temp;
+
+ aref->refexpr =
+ flatten_tlistentry(aref->refexpr, flat_tlist);
+
+ aref->refassgnexpr =
+ flatten_tlistentry(aref->refassgnexpr, flat_tlist);
+
+ return tlistentry;
+ }
+ else
+ {
+ Expr *expr = (Expr *) tlistentry;
+ Var *left =
+ (Var *) flatten_tlistentry((Node *) get_leftop(expr),
+ flat_tlist);
+ Var *right =
+ (Var *) flatten_tlistentry((Node *) get_rightop(expr),
+ flat_tlist);
+
+ return ((Node *)
+ make_opclause((Oper *) expr->oper, left, right));
+ }
}
-TargetEntry *
-MakeTLE(Resdom *resdom, Node *expr)
+TargetEntry *
+MakeTLE(Resdom * resdom, Node * expr)
{
- TargetEntry *rt = makeNode(TargetEntry);
+ TargetEntry *rt = makeNode(TargetEntry);
- rt->resdom = resdom;
- rt->expr = expr;
- return rt;
+ rt->resdom = resdom;
+ rt->expr = expr;
+ return rt;
}
-Var *
-get_expr(TargetEntry *tle)
+Var *
+get_expr(TargetEntry * tle)
{
- Assert(tle!=NULL);
- Assert(tle->expr!=NULL);
+ Assert(tle != NULL);
+ Assert(tle->expr != NULL);
- return ((Var *)tle->expr);
+ return ((Var *) tle->expr);
}
@@ -529,54 +569,56 @@ get_expr(TargetEntry *tle)
/*
* AddGroupAttrToTlist -
- * append the group attribute to the target list if it's not already
- * in there.
+ * append the group attribute to the target list if it's not already
+ * in there.
*/
#ifdef NOT_USED
void
-AddGroupAttrToTlist(List *tlist, List *grpCl)
+AddGroupAttrToTlist(List * tlist, List * grpCl)
{
- List *gl;
- int last_resdomno = length(tlist) + 1;
-
- foreach (gl, grpCl) {
- GroupClause *gc = (GroupClause*)lfirst(gl);
- Var *var = gc->grpAttr;
-
- if (!(tlist_member(var, tlist))) {
- Resdom *r;
-
- r = makeResdom(last_resdomno,
- var->vartype,
- get_typlen(var->vartype),
- NULL,
- (Index)0,
- (Oid)0,
- 0);
- last_resdomno++;
- tlist = lappend(tlist, MakeTLE(r, (Node*)var));
+ List *gl;
+ int last_resdomno = length(tlist) + 1;
+
+ foreach(gl, grpCl)
+ {
+ GroupClause *gc = (GroupClause *) lfirst(gl);
+ Var *var = gc->grpAttr;
+
+ if (!(tlist_member(var, tlist)))
+ {
+ Resdom *r;
+
+ r = makeResdom(last_resdomno,
+ var->vartype,
+ get_typlen(var->vartype),
+ NULL,
+ (Index) 0,
+ (Oid) 0,
+ 0);
+ last_resdomno++;
+ tlist = lappend(tlist, MakeTLE(r, (Node *) var));
+ }
}
- }
}
+
#endif
-/* was ExecTargetListLength() in execQual.c,
+/* was ExecTargetListLength() in execQual.c,
moved here to reduce dependencies on the executor module */
int
-exec_tlist_length(List *targetlist)
+exec_tlist_length(List * targetlist)
{
- int len;
- List *tl;
- TargetEntry *curTle;
-
- len = 0;
- foreach (tl, targetlist) {
- curTle = lfirst(tl);
-
- if (curTle->resdom != NULL)
- len++;
- }
- return len;
-}
+ int len;
+ List *tl;
+ TargetEntry *curTle;
+ len = 0;
+ foreach(tl, targetlist)
+ {
+ curTle = lfirst(tl);
+ if (curTle->resdom != NULL)
+ len++;
+ }
+ return len;
+}
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 3eb0787e3ef..40abf5f80cb 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* var.c--
- * Var node manipulation routines
+ * Var node manipulation routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.3 1996/11/06 09:29:26 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.4 1997/09/07 04:44:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,169 +27,193 @@
#include "parser/parsetree.h"
/*
- * find_varnos
+ * find_varnos
*
- * Descends down part of a parsetree (qual or tlist),
+ * Descends down part of a parsetree (qual or tlist),
*
- * XXX assumes varno's are always integers, which shouldn't be true...
- * (though it currently is, see primnodes.h)
+ * XXX assumes varno's are always integers, which shouldn't be true...
+ * (though it currently is, see primnodes.h)
*/
-List *
-pull_varnos(Node *me)
+List *
+pull_varnos(Node * me)
{
- List *i, *result = NIL;
-
- if (me == NULL)
- return (NIL);
-
- switch (nodeTag(me)) {
- case T_List:
- foreach (i, (List*)me) {
- result = nconc(result, pull_varnos(lfirst(i)));
+ List *i,
+ *result = NIL;
+
+ if (me == NULL)
+ return (NIL);
+
+ switch (nodeTag(me))
+ {
+ case T_List:
+ foreach(i, (List *) me)
+ {
+ result = nconc(result, pull_varnos(lfirst(i)));
+ }
+ break;
+ case T_ArrayRef:
+ foreach(i, ((ArrayRef *) me)->refupperindexpr)
+ result = nconc(result, pull_varnos(lfirst(i)));
+ foreach(i, ((ArrayRef *) me)->reflowerindexpr)
+ result = nconc(result, pull_varnos(lfirst(i)));
+ result = nconc(result, pull_varnos(((ArrayRef *) me)->refassgnexpr));
+ break;
+ case T_Var:
+ result = lconsi(((Var *) me)->varno, NIL);
+ break;
+ default:
+ break;
}
- break;
- case T_ArrayRef:
- foreach (i, ((ArrayRef*) me)->refupperindexpr)
- result = nconc(result, pull_varnos(lfirst(i)));
- foreach (i, ((ArrayRef*) me)->reflowerindexpr)
- result = nconc(result, pull_varnos(lfirst(i)));
- result = nconc(result, pull_varnos(((ArrayRef*) me)->refassgnexpr));
- break;
- case T_Var:
- result = lconsi(((Var*) me)->varno, NIL);
- break;
- default:
- break;
- }
- return(result);
+ return (result);
}
-/*
+/*
* contain_var_clause--
- * Recursively find var nodes from a clause by pulling vars from the
- * left and right operands of the clause.
- *
- * Returns true if any varnode found.
+ * Recursively find var nodes from a clause by pulling vars from the
+ * left and right operands of the clause.
+ *
+ * Returns true if any varnode found.
*/
-bool contain_var_clause(Node *clause)
+bool
+contain_var_clause(Node * clause)
{
- if (clause==NULL)
- return FALSE;
- else if (IsA(clause,Var))
- return TRUE;
- else if (IsA(clause,Iter))
- return contain_var_clause(((Iter*)clause)->iterexpr);
- else if (single_node(clause))
- return FALSE;
- else if (or_clause(clause)) {
- List *temp;
-
- foreach (temp, ((Expr*)clause)->args) {
- if (contain_var_clause(lfirst(temp)))
- return TRUE;
- }
- return FALSE;
- } else if (is_funcclause (clause)) {
- List *temp;
-
- foreach(temp, ((Expr *)clause)->args) {
- if (contain_var_clause(lfirst(temp)))
+ if (clause == NULL)
+ return FALSE;
+ else if (IsA(clause, Var))
return TRUE;
+ else if (IsA(clause, Iter))
+ return contain_var_clause(((Iter *) clause)->iterexpr);
+ else if (single_node(clause))
+ return FALSE;
+ else if (or_clause(clause))
+ {
+ List *temp;
+
+ foreach(temp, ((Expr *) clause)->args)
+ {
+ if (contain_var_clause(lfirst(temp)))
+ return TRUE;
+ }
+ return FALSE;
}
- return FALSE;
- } else if (IsA(clause,ArrayRef)) {
- List *temp;
-
- foreach(temp, ((ArrayRef*)clause)->refupperindexpr) {
- if (contain_var_clause(lfirst(temp)))
- return TRUE;
+ else if (is_funcclause(clause))
+ {
+ List *temp;
+
+ foreach(temp, ((Expr *) clause)->args)
+ {
+ if (contain_var_clause(lfirst(temp)))
+ return TRUE;
+ }
+ return FALSE;
}
- foreach(temp, ((ArrayRef*)clause)->reflowerindexpr) {
- if (contain_var_clause(lfirst(temp)))
- return TRUE;
+ else if (IsA(clause, ArrayRef))
+ {
+ List *temp;
+
+ foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
+ {
+ if (contain_var_clause(lfirst(temp)))
+ return TRUE;
+ }
+ foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
+ {
+ if (contain_var_clause(lfirst(temp)))
+ return TRUE;
+ }
+ if (contain_var_clause(((ArrayRef *) clause)->refexpr))
+ return TRUE;
+ if (contain_var_clause(((ArrayRef *) clause)->refassgnexpr))
+ return TRUE;
+ return FALSE;
}
- if (contain_var_clause(((ArrayRef*)clause)->refexpr))
- return TRUE;
- if (contain_var_clause(((ArrayRef*)clause)->refassgnexpr))
- return TRUE;
- return FALSE;
- } else if (not_clause(clause))
- return contain_var_clause((Node*)get_notclausearg((Expr*)clause));
- else if (is_opclause(clause))
- return (contain_var_clause((Node*)get_leftop((Expr*)clause)) ||
- contain_var_clause((Node*)get_rightop((Expr*)clause)));
+ else if (not_clause(clause))
+ return contain_var_clause((Node *) get_notclausearg((Expr *) clause));
+ else if (is_opclause(clause))
+ return (contain_var_clause((Node *) get_leftop((Expr *) clause)) ||
+ contain_var_clause((Node *) get_rightop((Expr *) clause)));
- return FALSE;
+ return FALSE;
}
-/*
+/*
* pull_var_clause--
- * Recursively pulls all var nodes from a clause by pulling vars from the
- * left and right operands of the clause.
- *
- * Returns list of varnodes found.
+ * Recursively pulls all var nodes from a clause by pulling vars from the
+ * left and right operands of the clause.
+ *
+ * Returns list of varnodes found.
*/
-List *
-pull_var_clause(Node *clause)
+List *
+pull_var_clause(Node * clause)
{
- List *retval = NIL;
-
- if (clause==NULL)
- return(NIL);
- else if (IsA(clause,Var))
- retval = lcons(clause,NIL);
- else if (IsA(clause,Iter))
- retval = pull_var_clause(((Iter*)clause)->iterexpr);
- else if (single_node(clause))
- retval = NIL;
- else if (or_clause(clause)) {
- List *temp;
-
- foreach (temp, ((Expr*)clause)->args)
- retval = nconc(retval, pull_var_clause(lfirst(temp)));
- } else if (is_funcclause (clause)) {
- List *temp;
-
- foreach(temp, ((Expr *)clause)->args)
- retval = nconc (retval,pull_var_clause(lfirst(temp)));
- } else if (IsA(clause,Aggreg)) {
- retval = pull_var_clause(((Aggreg*)clause)->target);
- } else if (IsA(clause,ArrayRef)) {
- List *temp;
-
- foreach(temp, ((ArrayRef*)clause)->refupperindexpr)
- retval = nconc (retval,pull_var_clause(lfirst(temp)));
- foreach(temp, ((ArrayRef*)clause)->reflowerindexpr)
- retval = nconc (retval,pull_var_clause(lfirst(temp)));
- retval = nconc(retval,
- pull_var_clause(((ArrayRef*)clause)->refexpr));
- retval = nconc(retval,
- pull_var_clause(((ArrayRef*)clause)->refassgnexpr));
- } else if (not_clause(clause))
- retval = pull_var_clause((Node*)get_notclausearg((Expr*)clause));
- else if (is_opclause(clause))
- retval = nconc(pull_var_clause((Node*)get_leftop((Expr*)clause)),
- pull_var_clause((Node*)get_rightop((Expr*)clause)));
- else
- retval = NIL;
-
- return (retval);
+ List *retval = NIL;
+
+ if (clause == NULL)
+ return (NIL);
+ else if (IsA(clause, Var))
+ retval = lcons(clause, NIL);
+ else if (IsA(clause, Iter))
+ retval = pull_var_clause(((Iter *) clause)->iterexpr);
+ else if (single_node(clause))
+ retval = NIL;
+ else if (or_clause(clause))
+ {
+ List *temp;
+
+ foreach(temp, ((Expr *) clause)->args)
+ retval = nconc(retval, pull_var_clause(lfirst(temp)));
+ }
+ else if (is_funcclause(clause))
+ {
+ List *temp;
+
+ foreach(temp, ((Expr *) clause)->args)
+ retval = nconc(retval, pull_var_clause(lfirst(temp)));
+ }
+ else if (IsA(clause, Aggreg))
+ {
+ retval = pull_var_clause(((Aggreg *) clause)->target);
+ }
+ else if (IsA(clause, ArrayRef))
+ {
+ List *temp;
+
+ foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
+ retval = nconc(retval, pull_var_clause(lfirst(temp)));
+ foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
+ retval = nconc(retval, pull_var_clause(lfirst(temp)));
+ retval = nconc(retval,
+ pull_var_clause(((ArrayRef *) clause)->refexpr));
+ retval = nconc(retval,
+ pull_var_clause(((ArrayRef *) clause)->refassgnexpr));
+ }
+ else if (not_clause(clause))
+ retval = pull_var_clause((Node *) get_notclausearg((Expr *) clause));
+ else if (is_opclause(clause))
+ retval = nconc(pull_var_clause((Node *) get_leftop((Expr *) clause)),
+ pull_var_clause((Node *) get_rightop((Expr *) clause)));
+ else
+ retval = NIL;
+
+ return (retval);
}
-/*
- * var_equal
- *
- * Returns t iff two var nodes correspond to the same attribute.
+/*
+ * var_equal
+ *
+ * Returns t iff two var nodes correspond to the same attribute.
*/
bool
-var_equal(Var *var1, Var *var2)
+var_equal(Var * var1, Var * var2)
{
- if (IsA (var1,Var) && IsA (var2,Var) &&
- (((Var*)var1)->varno == ((Var*)var2)->varno) &&
- (((Var*)var1)->vartype == ((Var*)var2)->vartype) &&
- (((Var*)var1)->varattno == ((Var*)var2)->varattno)) {
-
- return(true);
- } else
- return(false);
+ if (IsA(var1, Var) && IsA(var2, Var) &&
+ (((Var *) var1)->varno == ((Var *) var2)->varno) &&
+ (((Var *) var1)->vartype == ((Var *) var2)->vartype) &&
+ (((Var *) var1)->varattno == ((Var *) var2)->varattno))
+ {
+
+ return (true);
+ }
+ else
+ return (false);
}
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index a78d2c5c70e..8f63522812e 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* analyze.c--
- * transform the parse tree into a query tree
+ * transform the parse tree into a query tree
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.38 1997/09/05 19:32:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.39 1997/09/07 04:44:38 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,11 +20,11 @@
#include "nodes/primnodes.h"
#include "nodes/parsenodes.h"
#include "nodes/relation.h"
-#include "parse.h" /* for AND, OR, etc. */
+#include "parse.h" /* for AND, OR, etc. */
#include "catalog/pg_type.h" /* for INT4OID, etc. */
#include "catalog/pg_proc.h"
#include "utils/elog.h"
-#include "utils/builtins.h" /* namecmp(), textout() */
+#include "utils/builtins.h" /* namecmp(), textout() */
#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
@@ -41,502 +41,519 @@
#include "miscadmin.h"
-#include "port-protos.h" /* strdup() */
+#include "port-protos.h" /* strdup() */
/* convert the parse tree into a query tree */
-static Query *transformStmt(ParseState *pstate, Node *stmt);
-
-static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
-static Query *transformInsertStmt(ParseState *pstate, AppendStmt *stmt);
-static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
-static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
-static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
-static Query *transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt);
-static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
-static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
-static Node *handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno);
-
-#define EXPR_COLUMN_FIRST 1
+static Query *transformStmt(ParseState * pstate, Node * stmt);
+
+static Query *transformDeleteStmt(ParseState * pstate, DeleteStmt * stmt);
+static Query *transformInsertStmt(ParseState * pstate, AppendStmt * stmt);
+static Query *transformIndexStmt(ParseState * pstate, IndexStmt * stmt);
+static Query *transformExtendStmt(ParseState * pstate, ExtendStmt * stmt);
+static Query *transformRuleStmt(ParseState * query, RuleStmt * stmt);
+static Query *transformSelectStmt(ParseState * pstate, RetrieveStmt * stmt);
+static Query *transformUpdateStmt(ParseState * pstate, ReplaceStmt * stmt);
+static Query *transformCursorStmt(ParseState * pstate, CursorStmt * stmt);
+static Node *handleNestedDots(ParseState * pstate, Attr * attr, int *curr_resno);
+
+#define EXPR_COLUMN_FIRST 1
#define EXPR_RELATION_FIRST 2
-static Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
-static Node *transformIdent(ParseState *pstate, Node *expr, int precedence);
-
-static void makeRangeTable(ParseState *pstate, char *relname, List *frmList);
-static List *expandAllTables(ParseState *pstate);
-static char *figureColname(Node *expr, Node *resval);
-static List *makeTargetNames(ParseState *pstate, List *cols);
-static List *transformTargetList(ParseState *pstate, List *targetlist);
-static TargetEntry *make_targetlist_expr(ParseState *pstate,
- char *colname, Node *expr,
- List *arrayRef);
-static bool inWhereClause = false;
-static Node *transformWhereClause(ParseState *pstate, Node *a_expr);
-static List *transformGroupClause(ParseState *pstate, List *grouplist,
- List *targetlist);
-static List *transformSortClause(ParseState *pstate,
- List *orderlist, List *targetlist,
- char* uniqueFlag);
-
-static void parseFromClause(ParseState *pstate, List *frmList);
-static Node *ParseFunc(ParseState *pstate, char *funcname,
- List *fargs, int *curr_resno);
-static List *setup_tlist(char *attname, Oid relid);
-static List *setup_base_tlist(Oid typeid);
-static void make_arguments(int nargs, List *fargs, Oid *input_typeids,
- Oid *function_typeids);
-static void AddAggToParseState(ParseState *pstate, Aggreg *aggreg);
-static void finalizeAggregates(ParseState *pstate, Query *qry);
-static void parseCheckAggregates(ParseState *pstate, Query *qry);
-static ParseState* makeParseState(void);
+static Node *transformExpr(ParseState * pstate, Node * expr, int precedence);
+static Node *transformIdent(ParseState * pstate, Node * expr, int precedence);
+
+static void makeRangeTable(ParseState * pstate, char *relname, List * frmList);
+static List *expandAllTables(ParseState * pstate);
+static char *figureColname(Node * expr, Node * resval);
+static List *makeTargetNames(ParseState * pstate, List * cols);
+static List *transformTargetList(ParseState * pstate, List * targetlist);
+static TargetEntry *
+make_targetlist_expr(ParseState * pstate,
+ char *colname, Node * expr,
+ List * arrayRef);
+static bool inWhereClause = false;
+static Node *transformWhereClause(ParseState * pstate, Node * a_expr);
+static List *
+transformGroupClause(ParseState * pstate, List * grouplist,
+ List * targetlist);
+static List *
+transformSortClause(ParseState * pstate,
+ List * orderlist, List * targetlist,
+ char *uniqueFlag);
+
+static void parseFromClause(ParseState * pstate, List * frmList);
+static Node *
+ParseFunc(ParseState * pstate, char *funcname,
+ List * fargs, int *curr_resno);
+static List *setup_tlist(char *attname, Oid relid);
+static List *setup_base_tlist(Oid typeid);
+static void
+make_arguments(int nargs, List * fargs, Oid * input_typeids,
+ Oid * function_typeids);
+static void AddAggToParseState(ParseState * pstate, Aggreg * aggreg);
+static void finalizeAggregates(ParseState * pstate, Query * qry);
+static void parseCheckAggregates(ParseState * pstate, Query * qry);
+static ParseState *makeParseState(void);
/*****************************************************************************
*
*****************************************************************************/
/*
- * makeParseState() --
- * allocate and initialize a new ParseState.
- * the CALLERS is responsible for freeing the ParseState* returned
+ * makeParseState() --
+ * allocate and initialize a new ParseState.
+ * the CALLERS is responsible for freeing the ParseState* returned
*
*/
-static ParseState*
+static ParseState *
makeParseState(void)
{
- ParseState *pstate;
-
- pstate = malloc(sizeof(ParseState));
- pstate->p_last_resno = 1;
- pstate->p_rtable = NIL;
- pstate->p_numAgg = 0;
- pstate->p_aggs = NIL;
- pstate->p_is_insert = false;
- pstate->p_insert_columns = NIL;
- pstate->p_is_update = false;
- pstate->p_is_rule = false;
- pstate->p_target_relation = NULL;
- pstate->p_target_rangetblentry = NULL;
-
- return (pstate);
+ ParseState *pstate;
+
+ pstate = malloc(sizeof(ParseState));
+ pstate->p_last_resno = 1;
+ pstate->p_rtable = NIL;
+ pstate->p_numAgg = 0;
+ pstate->p_aggs = NIL;
+ pstate->p_is_insert = false;
+ pstate->p_insert_columns = NIL;
+ pstate->p_is_update = false;
+ pstate->p_is_rule = false;
+ pstate->p_target_relation = NULL;
+ pstate->p_target_rangetblentry = NULL;
+
+ return (pstate);
}
/*
* parse_analyze -
- * analyze a list of parse trees and transform them if necessary.
+ * analyze a list of parse trees and transform them if necessary.
*
* Returns a list of transformed parse trees. Optimizable statements are
* all transformed to Query while the rest stays the same.
*
* CALLER is responsible for freeing the QueryTreeList* returned
*/
-QueryTreeList *
-parse_analyze(List *pl)
+QueryTreeList *
+parse_analyze(List * pl)
{
- QueryTreeList *result;
- ParseState *pstate;
- int i = 0;
-
- result = malloc(sizeof(QueryTreeList));
- result->len = length(pl);
- result->qtrees = (Query**)malloc(result->len * sizeof(Query*));
-
- inWhereClause = false; /* to avoid nextval(sequence) in WHERE */
-
- while(pl!=NIL) {
- pstate = makeParseState();
- result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
- pl = lnext(pl);
- if (pstate->p_target_relation != NULL)
- heap_close(pstate->p_target_relation);
- free(pstate);
- }
-
- return result;
+ QueryTreeList *result;
+ ParseState *pstate;
+ int i = 0;
+
+ result = malloc(sizeof(QueryTreeList));
+ result->len = length(pl);
+ result->qtrees = (Query **) malloc(result->len * sizeof(Query *));
+
+ inWhereClause = false; /* to avoid nextval(sequence) in WHERE */
+
+ while (pl != NIL)
+ {
+ pstate = makeParseState();
+ result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
+ pl = lnext(pl);
+ if (pstate->p_target_relation != NULL)
+ heap_close(pstate->p_target_relation);
+ free(pstate);
+ }
+
+ return result;
}
/*
* transformStmt -
- * transform a Parse tree. If it is an optimizable statement, turn it
- * into a Query tree.
+ * transform a Parse tree. If it is an optimizable statement, turn it
+ * into a Query tree.
*/
-static Query *
-transformStmt(ParseState* pstate, Node *parseTree)
+static Query *
+transformStmt(ParseState * pstate, Node * parseTree)
{
- Query* result = NULL;
-
- switch(nodeTag(parseTree)) {
- /*------------------------
- * Non-optimizable statements
- *------------------------
- */
- case T_IndexStmt:
- result = transformIndexStmt(pstate, (IndexStmt *)parseTree);
- break;
-
- case T_ExtendStmt:
- result = transformExtendStmt(pstate, (ExtendStmt *)parseTree);
- break;
-
- case T_RuleStmt:
- result = transformRuleStmt(pstate, (RuleStmt *)parseTree);
- break;
-
- case T_ViewStmt:
- {
- ViewStmt *n = (ViewStmt *)parseTree;
- n->query = (Query *)transformStmt(pstate, (Node*)n->query);
- result = makeNode(Query);
- result->commandType = CMD_UTILITY;
- result->utilityStmt = (Node*)n;
- }
- break;
-
- case T_VacuumStmt:
- {
- MemoryContext oldcontext;
- /* make sure that this Query is allocated in TopMemory context
- because vacuum spans transactions and we don't want to lose
- the vacuum Query due to end-of-transaction free'ing*/
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- result = makeNode(Query);
- result->commandType = CMD_UTILITY;
- result->utilityStmt = (Node*)parseTree;
- MemoryContextSwitchTo(oldcontext);
- break;
-
- }
- case T_ExplainStmt:
- {
- ExplainStmt *n = (ExplainStmt *)parseTree;
- result = makeNode(Query);
- result->commandType = CMD_UTILITY;
- n->query = transformStmt(pstate, (Node*)n->query);
- result->utilityStmt = (Node*)parseTree;
- }
- break;
-
- /*------------------------
- * Optimizable statements
- *------------------------
- */
- case T_AppendStmt:
- result = transformInsertStmt(pstate, (AppendStmt *)parseTree);
- break;
-
- case T_DeleteStmt:
- result = transformDeleteStmt(pstate, (DeleteStmt *)parseTree);
- break;
-
- case T_ReplaceStmt:
- result = transformUpdateStmt(pstate, (ReplaceStmt *)parseTree);
- break;
-
- case T_CursorStmt:
- result = transformCursorStmt(pstate, (CursorStmt *)parseTree);
- break;
-
- case T_RetrieveStmt:
- result = transformSelectStmt(pstate, (RetrieveStmt *)parseTree);
- break;
-
- default:
- /*
- * other statments don't require any transformation-- just
- * return the original parsetree
- */
- result = makeNode(Query);
- result->commandType = CMD_UTILITY;
- result->utilityStmt = (Node*)parseTree;
- break;
- }
- return result;
+ Query *result = NULL;
+
+ switch (nodeTag(parseTree))
+ {
+ /*------------------------
+ * Non-optimizable statements
+ *------------------------
+ */
+ case T_IndexStmt:
+ result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
+ break;
+
+ case T_ExtendStmt:
+ result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
+ break;
+
+ case T_RuleStmt:
+ result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
+ break;
+
+ case T_ViewStmt:
+ {
+ ViewStmt *n = (ViewStmt *) parseTree;
+
+ n->query = (Query *) transformStmt(pstate, (Node *) n->query);
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) n;
+ }
+ break;
+
+ case T_VacuumStmt:
+ {
+ MemoryContext oldcontext;
+
+ /*
+ * make sure that this Query is allocated in TopMemory context
+ * because vacuum spans transactions and we don't want to lose
+ * the vacuum Query due to end-of-transaction free'ing
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) parseTree;
+ MemoryContextSwitchTo(oldcontext);
+ break;
+
+ }
+ case T_ExplainStmt:
+ {
+ ExplainStmt *n = (ExplainStmt *) parseTree;
+
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ n->query = transformStmt(pstate, (Node *) n->query);
+ result->utilityStmt = (Node *) parseTree;
+ }
+ break;
+
+ /*------------------------
+ * Optimizable statements
+ *------------------------
+ */
+ case T_AppendStmt:
+ result = transformInsertStmt(pstate, (AppendStmt *) parseTree);
+ break;
+
+ case T_DeleteStmt:
+ result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
+ break;
+
+ case T_ReplaceStmt:
+ result = transformUpdateStmt(pstate, (ReplaceStmt *) parseTree);
+ break;
+
+ case T_CursorStmt:
+ result = transformCursorStmt(pstate, (CursorStmt *) parseTree);
+ break;
+
+ case T_RetrieveStmt:
+ result = transformSelectStmt(pstate, (RetrieveStmt *) parseTree);
+ break;
+
+ default:
+
+ /*
+ * other statments don't require any transformation-- just return
+ * the original parsetree
+ */
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) parseTree;
+ break;
+ }
+ return result;
}
/*
* transformDeleteStmt -
- * transforms a Delete Statement
+ * transforms a Delete Statement
*/
-static Query *
-transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
+static Query *
+transformDeleteStmt(ParseState * pstate, DeleteStmt * stmt)
{
- Query *qry = makeNode(Query);
+ Query *qry = makeNode(Query);
- qry->commandType = CMD_DELETE;
+ qry->commandType = CMD_DELETE;
- /* set up a range table */
- makeRangeTable(pstate, stmt->relname, NULL);
-
- qry->uniqueFlag = NULL;
+ /* set up a range table */
+ makeRangeTable(pstate, stmt->relname, NULL);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate, stmt->whereClause);
+ qry->uniqueFlag = NULL;
- qry->rtable = pstate->p_rtable;
- qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- /* make sure we don't have aggregates in the where clause */
- if (pstate->p_numAgg > 0)
- parseCheckAggregates(pstate, qry);
+ qry->rtable = pstate->p_rtable;
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
+
+ /* make sure we don't have aggregates in the where clause */
+ if (pstate->p_numAgg > 0)
+ parseCheckAggregates(pstate, qry);
- return (Query *)qry;
+ return (Query *) qry;
}
/*
* transformInsertStmt -
- * transform an Insert Statement
+ * transform an Insert Statement
*/
-static Query *
-transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
+static Query *
+transformInsertStmt(ParseState * pstate, AppendStmt * stmt)
{
- Query *qry = makeNode(Query); /* make a new query tree */
+ Query *qry = makeNode(Query); /* make a new query tree */
- qry->commandType = CMD_INSERT;
- pstate->p_is_insert = true;
+ qry->commandType = CMD_INSERT;
+ pstate->p_is_insert = true;
- /* set up a range table */
- makeRangeTable(pstate, stmt->relname, stmt->fromClause);
+ /* set up a range table */
+ makeRangeTable(pstate, stmt->relname, stmt->fromClause);
- qry->uniqueFlag = NULL;
+ qry->uniqueFlag = NULL;
- /* fix the target list */
- pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
+ /* fix the target list */
+ pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
- qry->targetList = transformTargetList(pstate, stmt->targetList);
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate, stmt->whereClause);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- /* now the range table will not change */
- qry->rtable = pstate->p_rtable;
- qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
+ /* now the range table will not change */
+ qry->rtable = pstate->p_rtable;
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
- if (pstate->p_numAgg > 0)
- finalizeAggregates(pstate, qry);
+ if (pstate->p_numAgg > 0)
+ finalizeAggregates(pstate, qry);
- return (Query *)qry;
+ return (Query *) qry;
}
/*
* transformIndexStmt -
- * transforms the qualification of the index statement
+ * transforms the qualification of the index statement
*/
-static Query *
-transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
+static Query *
+transformIndexStmt(ParseState * pstate, IndexStmt * stmt)
{
- Query* q;
+ Query *q;
- q = makeNode(Query);
- q->commandType = CMD_UTILITY;
-
- /* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate,stmt->whereClause);
- stmt->rangetable = pstate->p_rtable;
+ q = makeNode(Query);
+ q->commandType = CMD_UTILITY;
- q->utilityStmt = (Node*)stmt;
+ /* take care of the where clause */
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+ stmt->rangetable = pstate->p_rtable;
- return q;
+ q->utilityStmt = (Node *) stmt;
+
+ return q;
}
/*
* transformExtendStmt -
- * transform the qualifications of the Extend Index Statement
+ * transform the qualifications of the Extend Index Statement
*
*/
-static Query *
-transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
+static Query *
+transformExtendStmt(ParseState * pstate, ExtendStmt * stmt)
{
- Query *q;
+ Query *q;
- q = makeNode(Query);
- q->commandType = CMD_UTILITY;
+ q = makeNode(Query);
+ q->commandType = CMD_UTILITY;
- /* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate,stmt->whereClause);
- stmt->rangetable = pstate->p_rtable;
+ /* take care of the where clause */
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+ stmt->rangetable = pstate->p_rtable;
- q->utilityStmt = (Node*)stmt;
- return q;
+ q->utilityStmt = (Node *) stmt;
+ return q;
}
/*
* transformRuleStmt -
- * transform a Create Rule Statement. The actions is a list of parse
- * trees which is transformed into a list of query trees.
+ * transform a Create Rule Statement. The actions is a list of parse
+ * trees which is transformed into a list of query trees.
*/
-static Query *
-transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
+static Query *
+transformRuleStmt(ParseState * pstate, RuleStmt * stmt)
{
- Query *q;
- List *actions;
-
- q = makeNode(Query);
- q->commandType = CMD_UTILITY;
-
- actions = stmt->actions;
- /*
- * transform each statment, like parse_analyze()
- */
- while (actions != NIL) {
+ Query *q;
+ List *actions;
+
+ q = makeNode(Query);
+ q->commandType = CMD_UTILITY;
+
+ actions = stmt->actions;
+
/*
- * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
- * equal to 2.
+ * transform each statment, like parse_analyze()
*/
- addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
- FALSE, FALSE, NULL);
- addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
- FALSE, FALSE, NULL);
+ while (actions != NIL)
+ {
- pstate->p_last_resno = 1;
- pstate->p_is_rule = true; /* for expand all */
- pstate->p_numAgg = 0;
- pstate->p_aggs = NULL;
-
- lfirst(actions) = transformStmt(pstate, lfirst(actions));
- actions = lnext(actions);
- }
+ /*
+ * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
+ * equal to 2.
+ */
+ addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
+ FALSE, FALSE, NULL);
+ addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
+ FALSE, FALSE, NULL);
+
+ pstate->p_last_resno = 1;
+ pstate->p_is_rule = true; /* for expand all */
+ pstate->p_numAgg = 0;
+ pstate->p_aggs = NULL;
+
+ lfirst(actions) = transformStmt(pstate, lfirst(actions));
+ actions = lnext(actions);
+ }
- /* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate,stmt->whereClause);
+ /* take care of the where clause */
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
- q->utilityStmt = (Node*)stmt;
- return q;
+ q->utilityStmt = (Node *) stmt;
+ return q;
}
/*
* transformSelectStmt -
- * transforms a Select Statement
+ * transforms a Select Statement
*
*/
-static Query *
-transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
+static Query *
+transformSelectStmt(ParseState * pstate, RetrieveStmt * stmt)
{
- Query *qry = makeNode(Query);
+ Query *qry = makeNode(Query);
+
+ qry->commandType = CMD_SELECT;
- qry->commandType = CMD_SELECT;
+ /* set up a range table */
+ makeRangeTable(pstate, NULL, stmt->fromClause);
- /* set up a range table */
- makeRangeTable(pstate, NULL, stmt->fromClause);
+ qry->uniqueFlag = stmt->unique;
- qry->uniqueFlag = stmt->unique;
+ qry->into = stmt->into;
+ qry->isPortal = FALSE;
- qry->into = stmt->into;
- qry->isPortal = FALSE;
+ /* fix the target list */
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
- /* fix the target list */
- qry->targetList = transformTargetList(pstate, stmt->targetList);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate,stmt->whereClause);
+ /* check subselect clause */
+ if (stmt->selectClause)
+ elog(NOTICE, "UNION not yet supported; using first SELECT only", NULL);
- /* check subselect clause */
- if (stmt->selectClause)
- elog(NOTICE,"UNION not yet supported; using first SELECT only",NULL);
+ /* check subselect clause */
+ if (stmt->havingClause)
+ elog(NOTICE, "HAVING not yet supported; ignore clause", NULL);
- /* check subselect clause */
- if (stmt->havingClause)
- elog(NOTICE,"HAVING not yet supported; ignore clause",NULL);
+ /* fix order clause */
+ qry->sortClause = transformSortClause(pstate,
+ stmt->sortClause,
+ qry->targetList,
+ qry->uniqueFlag);
- /* fix order clause */
- qry->sortClause = transformSortClause(pstate,
- stmt->sortClause,
- qry->targetList,
- qry->uniqueFlag);
+ /* fix group by clause */
+ qry->groupClause = transformGroupClause(pstate,
+ stmt->groupClause,
+ qry->targetList);
+ qry->rtable = pstate->p_rtable;
- /* fix group by clause */
- qry->groupClause = transformGroupClause(pstate,
- stmt->groupClause,
- qry->targetList);
- qry->rtable = pstate->p_rtable;
+ if (pstate->p_numAgg > 0)
+ finalizeAggregates(pstate, qry);
- if (pstate->p_numAgg > 0)
- finalizeAggregates(pstate, qry);
-
- return (Query *)qry;
+ return (Query *) qry;
}
/*
* transformUpdateStmt -
- * transforms an update statement
+ * transforms an update statement
*
*/
-static Query *
-transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt)
+static Query *
+transformUpdateStmt(ParseState * pstate, ReplaceStmt * stmt)
{
- Query *qry = makeNode(Query);
+ Query *qry = makeNode(Query);
+
+ qry->commandType = CMD_UPDATE;
+ pstate->p_is_update = true;
- qry->commandType = CMD_UPDATE;
- pstate->p_is_update = true;
- /*
- * the FROM clause is non-standard SQL syntax. We used to be able to
- * do this with REPLACE in POSTQUEL so we keep the feature.
- */
- makeRangeTable(pstate, stmt->relname, stmt->fromClause);
+ /*
+ * the FROM clause is non-standard SQL syntax. We used to be able to
+ * do this with REPLACE in POSTQUEL so we keep the feature.
+ */
+ makeRangeTable(pstate, stmt->relname, stmt->fromClause);
- /* fix the target list */
- qry->targetList = transformTargetList(pstate, stmt->targetList);
+ /* fix the target list */
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate,stmt->whereClause);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- qry->rtable = pstate->p_rtable;
- qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
+ qry->rtable = pstate->p_rtable;
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
- /* make sure we don't have aggregates in the where clause */
- if (pstate->p_numAgg > 0)
- parseCheckAggregates(pstate, qry);
+ /* make sure we don't have aggregates in the where clause */
+ if (pstate->p_numAgg > 0)
+ parseCheckAggregates(pstate, qry);
- return (Query *)qry;
+ return (Query *) qry;
}
/*
* transformCursorStmt -
- * transform a Create Cursor Statement
+ * transform a Create Cursor Statement
*
*/
-static Query *
-transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
+static Query *
+transformCursorStmt(ParseState * pstate, CursorStmt * stmt)
{
- Query *qry = makeNode(Query);
+ Query *qry = makeNode(Query);
- /*
- * in the old days, a cursor statement is a 'retrieve into portal';
- * If you change the following, make sure you also go through the code
- * in various places that tests the kind of operation.
- */
- qry->commandType = CMD_SELECT;
+ /*
+ * in the old days, a cursor statement is a 'retrieve into portal'; If
+ * you change the following, make sure you also go through the code in
+ * various places that tests the kind of operation.
+ */
+ qry->commandType = CMD_SELECT;
- /* set up a range table */
- makeRangeTable(pstate, NULL, stmt->fromClause);
+ /* set up a range table */
+ makeRangeTable(pstate, NULL, stmt->fromClause);
- qry->uniqueFlag = stmt->unique;
+ qry->uniqueFlag = stmt->unique;
- qry->into = stmt->portalname;
- qry->isPortal = TRUE;
- qry->isBinary = stmt->binary; /* internal portal */
+ qry->into = stmt->portalname;
+ qry->isPortal = TRUE;
+ qry->isBinary = stmt->binary; /* internal portal */
- /* fix the target list */
- qry->targetList = transformTargetList(pstate, stmt->targetList);
+ /* fix the target list */
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate,stmt->whereClause);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- /* fix order clause */
- qry->sortClause = transformSortClause(pstate,
- stmt->sortClause,
- qry->targetList,
- qry->uniqueFlag);
- /* fix group by clause */
- qry->groupClause = transformGroupClause(pstate,
- stmt->groupClause,
- qry->targetList);
+ /* fix order clause */
+ qry->sortClause = transformSortClause(pstate,
+ stmt->sortClause,
+ qry->targetList,
+ qry->uniqueFlag);
+ /* fix group by clause */
+ qry->groupClause = transformGroupClause(pstate,
+ stmt->groupClause,
+ qry->targetList);
- qry->rtable = pstate->p_rtable;
+ qry->rtable = pstate->p_rtable;
- if (pstate->p_numAgg > 0)
- finalizeAggregates(pstate, qry);
+ if (pstate->p_numAgg > 0)
+ finalizeAggregates(pstate, qry);
- return (Query *)qry;
+ return (Query *) qry;
}
/*****************************************************************************
@@ -547,236 +564,278 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
/*
* transformExpr -
- * analyze and transform expressions. Type checking and type casting is
- * done here. The optimizer and the executor cannot handle the original
- * (raw) expressions collected by the parse tree. Hence the transformation
- * here.
+ * analyze and transform expressions. Type checking and type casting is
+ * done here. The optimizer and the executor cannot handle the original
+ * (raw) expressions collected by the parse tree. Hence the transformation
+ * here.
*/
-static Node *
-transformExpr(ParseState *pstate, Node *expr, int precedence)
+static Node *
+transformExpr(ParseState * pstate, Node * expr, int precedence)
{
- Node *result = NULL;
+ Node *result = NULL;
- if (expr==NULL)
- return NULL;
-
- switch(nodeTag(expr)) {
- case T_Attr: {
- Attr *att = (Attr *)expr;
- Node *temp;
-
- /* what if att.attrs == "*"?? */
- temp = handleNestedDots(pstate, att, &pstate->p_last_resno);
- if (att->indirection != NIL) {
- List *idx = att->indirection;
- while(idx!=NIL) {
- A_Indices *ai = (A_Indices *)lfirst(idx);
- Node *lexpr=NULL, *uexpr;
- uexpr = transformExpr(pstate, ai->uidx, precedence); /* must exists */
- if (exprType(uexpr) != INT4OID)
- elog(WARN, "array index expressions must be int4's");
- if (ai->lidx != NULL) {
- lexpr = transformExpr(pstate, ai->lidx, precedence);
- if (exprType(lexpr) != INT4OID)
- elog(WARN, "array index expressions must be int4's");
- }
+ if (expr == NULL)
+ return NULL;
+
+ switch (nodeTag(expr))
+ {
+ case T_Attr:
+ {
+ Attr *att = (Attr *) expr;
+ Node *temp;
+
+ /* what if att.attrs == "*"?? */
+ temp = handleNestedDots(pstate, att, &pstate->p_last_resno);
+ if (att->indirection != NIL)
+ {
+ List *idx = att->indirection;
+
+ while (idx != NIL)
+ {
+ A_Indices *ai = (A_Indices *) lfirst(idx);
+ Node *lexpr = NULL,
+ *uexpr;
+
+ uexpr = transformExpr(pstate, ai->uidx, precedence); /* must exists */
+ if (exprType(uexpr) != INT4OID)
+ elog(WARN, "array index expressions must be int4's");
+ if (ai->lidx != NULL)
+ {
+ lexpr = transformExpr(pstate, ai->lidx, precedence);
+ if (exprType(lexpr) != INT4OID)
+ elog(WARN, "array index expressions must be int4's");
+ }
#if 0
- pfree(ai->uidx);
- if (ai->lidx!=NULL) pfree(ai->lidx);
+ pfree(ai->uidx);
+ if (ai->lidx != NULL)
+ pfree(ai->lidx);
#endif
- ai->lidx = lexpr;
- ai->uidx = uexpr;
- /* note we reuse the list of indices, make sure we don't free
- them! Otherwise, make a new list here */
- idx = lnext(idx);
- }
- result = (Node*)make_array_ref(temp, att->indirection);
- }else {
- result = temp;
- }
- break;
- }
- case T_A_Const: {
- A_Const *con= (A_Const *)expr;
- Value *val = &con->val;
- if (con->typename != NULL) {
- result = parser_typecast(val, con->typename, -1);
- }else {
- result = (Node *)make_const(val);
- }
- break;
- }
- case T_ParamNo: {
- ParamNo *pno = (ParamNo *)expr;
- Oid toid;
- int paramno;
- Param *param;
-
- paramno = pno->number;
- toid = param_type(paramno);
- if (!OidIsValid(toid)) {
- elog(WARN, "Parameter '$%d' is out of range",
- paramno);
- }
- param = makeNode(Param);
- param->paramkind = PARAM_NUM;
- param->paramid = (AttrNumber) paramno;
- param->paramname = "<unnamed>";
- param->paramtype = (Oid)toid;
- param->param_tlist = (List*) NULL;
-
- result = (Node *)param;
- break;
- }
- case T_A_Expr: {
- A_Expr *a = (A_Expr *)expr;
-
- switch(a->oper) {
- case OP:
- {
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
- Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
- result = (Node *)make_op(a->opname, lexpr, rexpr);
- }
- break;
- case ISNULL:
- {
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
- result = ParseFunc(pstate,
- "nullvalue", lcons(lexpr, NIL),
- &pstate->p_last_resno);
- }
- break;
- case NOTNULL:
- {
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
- result = ParseFunc(pstate,
- "nonnullvalue", lcons(lexpr, NIL),
- &pstate->p_last_resno);
- }
- break;
- case AND:
- {
- Expr *expr = makeNode(Expr);
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
- Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
- if (exprType(lexpr) != BOOLOID)
- elog(WARN,
- "left-hand side of AND is type '%s', not bool",
- tname(get_id_type(exprType(lexpr))));
- if (exprType(rexpr) != BOOLOID)
- elog(WARN,
- "right-hand side of AND is type '%s', not bool",
- tname(get_id_type(exprType(rexpr))));
- expr->typeOid = BOOLOID;
- expr->opType = AND_EXPR;
- expr->args = makeList(lexpr, rexpr, -1);
- result = (Node *)expr;
- }
- break;
- case OR:
- {
- Expr *expr = makeNode(Expr);
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
- Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
- if (exprType(lexpr) != BOOLOID)
- elog(WARN,
- "left-hand side of OR is type '%s', not bool",
- tname(get_id_type(exprType(lexpr))));
- if (exprType(rexpr) != BOOLOID)
- elog(WARN,
- "right-hand side of OR is type '%s', not bool",
- tname(get_id_type(exprType(rexpr))));
- expr->typeOid = BOOLOID;
- expr->opType = OR_EXPR;
- expr->args = makeList(lexpr, rexpr, -1);
- result = (Node *)expr;
- }
- break;
- case NOT:
- {
- Expr *expr = makeNode(Expr);
- Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
- if (exprType(rexpr) != BOOLOID)
- elog(WARN,
- "argument to NOT is type '%s', not bool",
- tname(get_id_type(exprType(rexpr))));
- expr->typeOid = BOOLOID;
- expr->opType = NOT_EXPR;
- expr->args = makeList(rexpr, -1);
- result = (Node *)expr;
- }
- break;
+ ai->lidx = lexpr;
+ ai->uidx = uexpr;
+
+ /*
+ * note we reuse the list of indices, make sure we
+ * don't free them! Otherwise, make a new list here
+ */
+ idx = lnext(idx);
+ }
+ result = (Node *) make_array_ref(temp, att->indirection);
+ }
+ else
+ {
+ result = temp;
+ }
+ break;
+ }
+ case T_A_Const:
+ {
+ A_Const *con = (A_Const *) expr;
+ Value *val = &con->val;
+
+ if (con->typename != NULL)
+ {
+ result = parser_typecast(val, con->typename, -1);
+ }
+ else
+ {
+ result = (Node *) make_const(val);
+ }
+ break;
+ }
+ case T_ParamNo:
+ {
+ ParamNo *pno = (ParamNo *) expr;
+ Oid toid;
+ int paramno;
+ Param *param;
+
+ paramno = pno->number;
+ toid = param_type(paramno);
+ if (!OidIsValid(toid))
+ {
+ elog(WARN, "Parameter '$%d' is out of range",
+ paramno);
+ }
+ param = makeNode(Param);
+ param->paramkind = PARAM_NUM;
+ param->paramid = (AttrNumber) paramno;
+ param->paramname = "<unnamed>";
+ param->paramtype = (Oid) toid;
+ param->param_tlist = (List *) NULL;
+
+ result = (Node *) param;
+ break;
+ }
+ case T_A_Expr:
+ {
+ A_Expr *a = (A_Expr *) expr;
+
+ switch (a->oper)
+ {
+ case OP:
+ {
+ Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
+ Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
+
+ result = (Node *) make_op(a->opname, lexpr, rexpr);
+ }
+ break;
+ case ISNULL:
+ {
+ Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
+
+ result = ParseFunc(pstate,
+ "nullvalue", lcons(lexpr, NIL),
+ &pstate->p_last_resno);
+ }
+ break;
+ case NOTNULL:
+ {
+ Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
+
+ result = ParseFunc(pstate,
+ "nonnullvalue", lcons(lexpr, NIL),
+ &pstate->p_last_resno);
+ }
+ break;
+ case AND:
+ {
+ Expr *expr = makeNode(Expr);
+ Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
+ Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
+
+ if (exprType(lexpr) != BOOLOID)
+ elog(WARN,
+ "left-hand side of AND is type '%s', not bool",
+ tname(get_id_type(exprType(lexpr))));
+ if (exprType(rexpr) != BOOLOID)
+ elog(WARN,
+ "right-hand side of AND is type '%s', not bool",
+ tname(get_id_type(exprType(rexpr))));
+ expr->typeOid = BOOLOID;
+ expr->opType = AND_EXPR;
+ expr->args = makeList(lexpr, rexpr, -1);
+ result = (Node *) expr;
+ }
+ break;
+ case OR:
+ {
+ Expr *expr = makeNode(Expr);
+ Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
+ Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
+
+ if (exprType(lexpr) != BOOLOID)
+ elog(WARN,
+ "left-hand side of OR is type '%s', not bool",
+ tname(get_id_type(exprType(lexpr))));
+ if (exprType(rexpr) != BOOLOID)
+ elog(WARN,
+ "right-hand side of OR is type '%s', not bool",
+ tname(get_id_type(exprType(rexpr))));
+ expr->typeOid = BOOLOID;
+ expr->opType = OR_EXPR;
+ expr->args = makeList(lexpr, rexpr, -1);
+ result = (Node *) expr;
+ }
+ break;
+ case NOT:
+ {
+ Expr *expr = makeNode(Expr);
+ Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
+
+ if (exprType(rexpr) != BOOLOID)
+ elog(WARN,
+ "argument to NOT is type '%s', not bool",
+ tname(get_id_type(exprType(rexpr))));
+ expr->typeOid = BOOLOID;
+ expr->opType = NOT_EXPR;
+ expr->args = makeList(rexpr, -1);
+ result = (Node *) expr;
+ }
+ break;
+ }
+ break;
+ }
+ case T_Ident:
+ {
+
+ /*
+ * look for a column name or a relation name (the default
+ * behavior)
+ */
+ result = transformIdent(pstate, expr, precedence);
+ break;
+ }
+ case T_FuncCall:
+ {
+ FuncCall *fn = (FuncCall *) expr;
+ List *args;
+
+ /* transform the list of arguments */
+ foreach(args, fn->args)
+ lfirst(args) = transformExpr(pstate, (Node *) lfirst(args), precedence);
+ result = ParseFunc(pstate,
+ fn->funcname, fn->args, &pstate->p_last_resno);
+ break;
+ }
+ default:
+ /* should not reach here */
+ elog(WARN, "transformExpr: does not know how to transform %d\n",
+ nodeTag(expr));
+ break;
}
- break;
- }
- case T_Ident: {
- /* look for a column name or a relation name (the default behavior) */
- result = transformIdent(pstate, expr, precedence);
- break;
- }
- case T_FuncCall: {
- FuncCall *fn = (FuncCall *)expr;
- List *args;
-
- /* transform the list of arguments */
- foreach(args, fn->args)
- lfirst(args) = transformExpr(pstate, (Node*)lfirst(args), precedence);
- result = ParseFunc(pstate,
- fn->funcname, fn->args, &pstate->p_last_resno);
- break;
- }
- default:
- /* should not reach here */
- elog(WARN, "transformExpr: does not know how to transform %d\n",
- nodeTag(expr));
- break;
- }
-
- return result;
+
+ return result;
}
-static Node *
-transformIdent(ParseState *pstate, Node *expr, int precedence)
+static Node *
+transformIdent(ParseState * pstate, Node * expr, int precedence)
{
- Ident *ident = (Ident*)expr;
- RangeTblEntry *rte;
- Node *column_result, *relation_result, *result;
-
- column_result = relation_result = result = 0;
- /* try to find the ident as a column */
- if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL) {
- Attr *att = makeNode(Attr);
-
- att->relname = rte->refname;
- att->attrs = lcons(makeString(ident->name), NIL);
- column_result =
- (Node*)handleNestedDots(pstate, att, &pstate->p_last_resno);
- }
-
- /* try to find the ident as a relation */
- if (refnameRangeTableEntry(pstate->p_rtable, ident->name) != NULL) {
- ident->isRel = TRUE;
- relation_result = (Node*)ident;
- }
-
- /* choose the right result based on the precedence */
- if(precedence == EXPR_COLUMN_FIRST) {
- if(column_result)
- result = column_result;
- else
- result = relation_result;
- } else {
- if(relation_result)
- result = relation_result;
+ Ident *ident = (Ident *) expr;
+ RangeTblEntry *rte;
+ Node *column_result,
+ *relation_result,
+ *result;
+
+ column_result = relation_result = result = 0;
+ /* try to find the ident as a column */
+ if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
+ {
+ Attr *att = makeNode(Attr);
+
+ att->relname = rte->refname;
+ att->attrs = lcons(makeString(ident->name), NIL);
+ column_result =
+ (Node *) handleNestedDots(pstate, att, &pstate->p_last_resno);
+ }
+
+ /* try to find the ident as a relation */
+ if (refnameRangeTableEntry(pstate->p_rtable, ident->name) != NULL)
+ {
+ ident->isRel = TRUE;
+ relation_result = (Node *) ident;
+ }
+
+ /* choose the right result based on the precedence */
+ if (precedence == EXPR_COLUMN_FIRST)
+ {
+ if (column_result)
+ result = column_result;
+ else
+ result = relation_result;
+ }
else
- result = column_result;
- }
+ {
+ if (relation_result)
+ result = relation_result;
+ else
+ result = column_result;
+ }
+
+ if (result == NULL)
+ elog(WARN, "attribute \"%s\" not found", ident->name);
- if(result == NULL)
- elog(WARN, "attribute \"%s\" not found", ident->name);
-
- return result;
+ return result;
}
/*****************************************************************************
@@ -787,201 +846,210 @@ transformIdent(ParseState *pstate, Node *expr, int precedence)
/*
* parseFromClause -
- * turns the table references specified in the from-clause into a
- * range table. The range table may grow as we transform the expressions
- * in the target list. (Note that this happens because in POSTQUEL, we
- * allow references to relations not specified in the from-clause. We
- * also allow that in our POST-SQL)
+ * turns the table references specified in the from-clause into a
+ * range table. The range table may grow as we transform the expressions
+ * in the target list. (Note that this happens because in POSTQUEL, we
+ * allow references to relations not specified in the from-clause. We
+ * also allow that in our POST-SQL)
*
*/
static void
-parseFromClause(ParseState *pstate, List *frmList)
+parseFromClause(ParseState * pstate, List * frmList)
{
- List *fl;
-
- foreach(fl, frmList)
- {
- RangeVar *r = lfirst(fl);
- RelExpr *baserel = r->relExpr;
- char *relname = baserel->relname;
- char *refname = r->name;
- RangeTblEntry *rte;
-
- if (refname==NULL)
- refname = relname;
+ List *fl;
- /*
- * marks this entry to indicate it comes from the FROM clause. In
- * SQL, the target list can only refer to range variables specified
- * in the from clause but we follow the more powerful POSTQUEL
- * semantics and automatically generate the range variable if not
- * specified. However there are times we need to know whether the
- * entries are legitimate.
- *
- * eg. select * from foo f where f.x = 1; will generate wrong answer
- * if we expand * to foo.x.
- */
- rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE,
- baserel->timeRange);
- }
+ foreach(fl, frmList)
+ {
+ RangeVar *r = lfirst(fl);
+ RelExpr *baserel = r->relExpr;
+ char *relname = baserel->relname;
+ char *refname = r->name;
+ RangeTblEntry *rte;
+
+ if (refname == NULL)
+ refname = relname;
+
+ /*
+ * marks this entry to indicate it comes from the FROM clause. In
+ * SQL, the target list can only refer to range variables
+ * specified in the from clause but we follow the more powerful
+ * POSTQUEL semantics and automatically generate the range
+ * variable if not specified. However there are times we need to
+ * know whether the entries are legitimate.
+ *
+ * eg. select * from foo f where f.x = 1; will generate wrong answer
+ * if we expand * to foo.x.
+ */
+ rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE,
+ baserel->timeRange);
+ }
}
/*
* makeRangeTable -
- * make a range table with the specified relation (optional) and the
- * from-clause.
+ * make a range table with the specified relation (optional) and the
+ * from-clause.
*/
static void
-makeRangeTable(ParseState *pstate, char *relname, List *frmList)
+makeRangeTable(ParseState * pstate, char *relname, List * frmList)
{
- RangeTblEntry *rte;
+ RangeTblEntry *rte;
- parseFromClause(pstate, frmList);
+ parseFromClause(pstate, frmList);
- if (relname == NULL)
- return;
-
- if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
- rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE, NULL);
- else
- rte = refnameRangeTableEntry(pstate->p_rtable, relname);
-
- pstate->p_target_rangetblentry = rte;
- Assert(pstate->p_target_relation == NULL);
- pstate->p_target_relation = heap_open(rte->relid);
- Assert(pstate->p_target_relation != NULL);
+ if (relname == NULL)
+ return;
+
+ if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
+ rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE, NULL);
+ else
+ rte = refnameRangeTableEntry(pstate->p_rtable, relname);
+
+ pstate->p_target_rangetblentry = rte;
+ Assert(pstate->p_target_relation == NULL);
+ pstate->p_target_relation = heap_open(rte->relid);
+ Assert(pstate->p_target_relation != NULL);
/* will close relation later */
}
/*
- * exprType -
- * returns the Oid of the type of the expression. (Used for typechecking.)
+ * exprType -
+ * returns the Oid of the type of the expression. (Used for typechecking.)
*/
Oid
-exprType(Node *expr)
+exprType(Node * expr)
{
- Oid type = (Oid)0;
-
- switch(nodeTag(expr)) {
- case T_Func:
- type = ((Func*)expr)->functype;
- break;
- case T_Iter:
- type = ((Iter*)expr)->itertype;
- break;
- case T_Var:
- type = ((Var*)expr)->vartype;
- break;
- case T_Expr:
- type = ((Expr*)expr)->typeOid;
- break;
- case T_Const:
- type = ((Const*)expr)->consttype;
- break;
- case T_ArrayRef:
- type = ((ArrayRef*)expr)->refelemtype;
- break;
- case T_Aggreg:
- type = ((Aggreg*)expr)->aggtype;
- break;
- case T_Param:
- type = ((Param*)expr)->paramtype;
- break;
- case T_Ident:
- /* is this right? */
- type = UNKNOWNOID;
- break;
- default:
- elog(WARN, "exprType: don't know how to get type for %d node",
- nodeTag(expr));
- break;
- }
- return type;
+ Oid type = (Oid) 0;
+
+ switch (nodeTag(expr))
+ {
+ case T_Func:
+ type = ((Func *) expr)->functype;
+ break;
+ case T_Iter:
+ type = ((Iter *) expr)->itertype;
+ break;
+ case T_Var:
+ type = ((Var *) expr)->vartype;
+ break;
+ case T_Expr:
+ type = ((Expr *) expr)->typeOid;
+ break;
+ case T_Const:
+ type = ((Const *) expr)->consttype;
+ break;
+ case T_ArrayRef:
+ type = ((ArrayRef *) expr)->refelemtype;
+ break;
+ case T_Aggreg:
+ type = ((Aggreg *) expr)->aggtype;
+ break;
+ case T_Param:
+ type = ((Param *) expr)->paramtype;
+ break;
+ case T_Ident:
+ /* is this right? */
+ type = UNKNOWNOID;
+ break;
+ default:
+ elog(WARN, "exprType: don't know how to get type for %d node",
+ nodeTag(expr));
+ break;
+ }
+ return type;
}
/*
* expandAllTables -
- * turns '*' (in the target list) into a list of attributes (of all
- * relations in the range table)
+ * turns '*' (in the target list) into a list of attributes (of all
+ * relations in the range table)
*/
-static List *
-expandAllTables(ParseState *pstate)
+static List *
+expandAllTables(ParseState * pstate)
{
- List *target= NIL;
- List *legit_rtable=NIL;
- List *rt, *rtable;
+ List *target = NIL;
+ List *legit_rtable = NIL;
+ List *rt,
+ *rtable;
- rtable = pstate->p_rtable;
- if (pstate->p_is_rule) {
- /*
- * skip first two entries, "*new*" and "*current*"
- */
- rtable = lnext(lnext(pstate->p_rtable));
- }
-
- /* this should not happen */
- if (rtable==NULL)
- elog(WARN, "cannot expand: null p_rtable");
-
- /*
- * go through the range table and make a list of range table entries
- * which we will expand.
- */
- foreach(rt, rtable) {
- RangeTblEntry *rte = lfirst(rt);
+ rtable = pstate->p_rtable;
+ if (pstate->p_is_rule)
+ {
+
+ /*
+ * skip first two entries, "*new*" and "*current*"
+ */
+ rtable = lnext(lnext(pstate->p_rtable));
+ }
+
+ /* this should not happen */
+ if (rtable == NULL)
+ elog(WARN, "cannot expand: null p_rtable");
/*
- * we only expand those specify in the from clause. (This will
- * also prevent us from using the wrong table in inserts: eg. tenk2
- * in "insert into tenk2 select * from tenk1;")
+ * go through the range table and make a list of range table entries
+ * which we will expand.
*/
- if (!rte->inFromCl)
- continue;
- legit_rtable = lappend(legit_rtable, rte);
- }
-
- foreach(rt, legit_rtable) {
- RangeTblEntry *rte = lfirst(rt);
- List *temp = target;
-
- if(temp == NIL )
- target = expandAll(pstate, rte->relname, rte->refname,
- &pstate->p_last_resno);
- else {
- while (temp != NIL && lnext(temp) != NIL)
- temp = lnext(temp);
- lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
- &pstate->p_last_resno);
+ foreach(rt, rtable)
+ {
+ RangeTblEntry *rte = lfirst(rt);
+
+ /*
+ * we only expand those specify in the from clause. (This will
+ * also prevent us from using the wrong table in inserts: eg.
+ * tenk2 in "insert into tenk2 select * from tenk1;")
+ */
+ if (!rte->inFromCl)
+ continue;
+ legit_rtable = lappend(legit_rtable, rte);
+ }
+
+ foreach(rt, legit_rtable)
+ {
+ RangeTblEntry *rte = lfirst(rt);
+ List *temp = target;
+
+ if (temp == NIL)
+ target = expandAll(pstate, rte->relname, rte->refname,
+ &pstate->p_last_resno);
+ else
+ {
+ while (temp != NIL && lnext(temp) != NIL)
+ temp = lnext(temp);
+ lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
+ &pstate->p_last_resno);
+ }
}
- }
- return target;
+ return target;
}
/*
* figureColname -
- * if the name of the resulting column is not specified in the target
- * list, we have to guess.
+ * if the name of the resulting column is not specified in the target
+ * list, we have to guess.
*
*/
-static char *
-figureColname(Node *expr, Node *resval)
+static char *
+figureColname(Node * expr, Node * resval)
{
- switch (nodeTag(expr)) {
- case T_Aggreg:
- return (char*) /* XXX */
- ((Aggreg *)expr)->aggname;
- case T_Expr:
- if (((Expr*)expr)->opType == FUNC_EXPR) {
- if (nodeTag(resval)==T_FuncCall)
- return ((FuncCall*)resval)->funcname;
+ switch (nodeTag(expr))
+ {
+ case T_Aggreg:
+ return (char *) /* XXX */
+ ((Aggreg *) expr)->aggname;
+ case T_Expr:
+ if (((Expr *) expr)->opType == FUNC_EXPR)
+ {
+ if (nodeTag(resval) == T_FuncCall)
+ return ((FuncCall *) resval)->funcname;
+ }
+ break;
+ default:
+ break;
}
- break;
- default:
- break;
- }
-
- return "?column?";
+
+ return "?column?";
}
/*****************************************************************************
@@ -992,452 +1060,531 @@ figureColname(Node *expr, Node *resval)
/*
* makeTargetNames -
- * generate a list of column names if not supplied or
- * test supplied column names to make sure they are in target table
- * (used exclusively for inserts)
+ * generate a list of column names if not supplied or
+ * test supplied column names to make sure they are in target table
+ * (used exclusively for inserts)
*/
-static List *
-makeTargetNames(ParseState *pstate, List *cols)
+static List *
+makeTargetNames(ParseState * pstate, List * cols)
{
- List *tl=NULL;
-
- /* Generate ResTarget if not supplied */
-
- if (cols == NIL) {
- int numcol;
- int i;
- AttributeTupleForm *attr = pstate->p_target_relation->rd_att->attrs;
-
- numcol = pstate->p_target_relation->rd_rel->relnatts;
- for(i=0; i < numcol; i++) {
- Ident *id = makeNode(Ident);
-
- id->name = palloc(NAMEDATALEN);
- strNcpy(id->name, attr[i]->attname.data, NAMEDATALEN-1);
- id->indirection = NIL;
- id->isRel = false;
- if (tl == NIL)
- cols = tl = lcons(id, NIL);
- else {
- lnext(tl) = lcons(id,NIL);
- tl = lnext(tl);
- }
+ List *tl = NULL;
+
+ /* Generate ResTarget if not supplied */
+
+ if (cols == NIL)
+ {
+ int numcol;
+ int i;
+ AttributeTupleForm *attr = pstate->p_target_relation->rd_att->attrs;
+
+ numcol = pstate->p_target_relation->rd_rel->relnatts;
+ for (i = 0; i < numcol; i++)
+ {
+ Ident *id = makeNode(Ident);
+
+ id->name = palloc(NAMEDATALEN);
+ strNcpy(id->name, attr[i]->attname.data, NAMEDATALEN - 1);
+ id->indirection = NIL;
+ id->isRel = false;
+ if (tl == NIL)
+ cols = tl = lcons(id, NIL);
+ else
+ {
+ lnext(tl) = lcons(id, NIL);
+ tl = lnext(tl);
+ }
+ }
}
- }
- else
- foreach(tl, cols)
- /* elog on failure */
- varattno(pstate->p_target_relation,((Ident *)lfirst(tl))->name);
+ else
+ foreach(tl, cols)
+ /* elog on failure */
+ varattno(pstate->p_target_relation, ((Ident *) lfirst(tl))->name);
- return cols;
+ return cols;
}
/*
* transformTargetList -
- * turns a list of ResTarget's into a list of TargetEntry's
+ * turns a list of ResTarget's into a list of TargetEntry's
*/
-static List *
-transformTargetList(ParseState *pstate, List *targetlist)
+static List *
+transformTargetList(ParseState * pstate, List * targetlist)
{
- List *p_target= NIL;
- List *tail_p_target = NIL;
-
- while(targetlist != NIL) {
- ResTarget *res= (ResTarget *)lfirst(targetlist);
- TargetEntry *tent = makeNode(TargetEntry);
-
- switch(nodeTag(res->val)) {
- case T_Ident: {
- Node *expr;
- Oid type_id;
- int type_len;
- char *identname;
- char *resname;
-
- identname = ((Ident*)res->val)->name;
- handleTargetColname(pstate, &res->name, NULL, identname );
-
- /* here we want to look for column names only, not relation */
- /* names (even though they can be stored in Ident nodes, */
- /* too) */
- expr = transformIdent(pstate, (Node*)res->val, EXPR_COLUMN_FIRST);
- type_id = exprType(expr);
- type_len = tlen(get_id_type(type_id));
- resname = (res->name) ? res->name : identname;
- tent->resdom = makeResdom((AttrNumber)pstate->p_last_resno++,
- (Oid)type_id,
- (Size)type_len,
- resname,
- (Index)0,
- (Oid)0,
- 0);
-
- tent->expr = expr;
- break;
- }
- case T_ParamNo:
- case T_FuncCall:
- case T_A_Const:
- case T_A_Expr: {
- Node *expr = transformExpr(pstate, (Node *)res->val, EXPR_COLUMN_FIRST);
-
- handleTargetColname(pstate, &res->name, NULL, NULL);
- /* note indirection has not been transformed */
- if (pstate->p_is_insert && res->indirection!=NIL) {
- /* this is an array assignment */
- char *val;
- char *str, *save_str;
- List *elt;
- int i = 0, ndims;
- int lindx[MAXDIM], uindx[MAXDIM];
- int resdomno;
- Relation rd;
- Value *constval;
-
- if (exprType(expr) != UNKNOWNOID ||
- !IsA(expr,Const))
- elog(WARN, "yyparse: string constant expected");
-
- val = (char *) textout((struct varlena *)
- ((Const *)expr)->constvalue);
- str = save_str = (char*)palloc(strlen(val) + MAXDIM * 25 + 2);
- foreach(elt, res->indirection) {
- A_Indices *aind = (A_Indices *)lfirst(elt);
- aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
- if (!IsA(aind->uidx,Const))
+ List *p_target = NIL;
+ List *tail_p_target = NIL;
+
+ while (targetlist != NIL)
+ {
+ ResTarget *res = (ResTarget *) lfirst(targetlist);
+ TargetEntry *tent = makeNode(TargetEntry);
+
+ switch (nodeTag(res->val))
+ {
+ case T_Ident:
+ {
+ Node *expr;
+ Oid type_id;
+ int type_len;
+ char *identname;
+ char *resname;
+
+ identname = ((Ident *) res->val)->name;
+ handleTargetColname(pstate, &res->name, NULL, identname);
+
+ /*
+ * here we want to look for column names only, not
+ * relation
+ */
+ /* names (even though they can be stored in Ident nodes, */
+ /* too) */
+ expr = transformIdent(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
+ type_id = exprType(expr);
+ type_len = tlen(get_id_type(type_id));
+ resname = (res->name) ? res->name : identname;
+ tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
+ (Oid) type_id,
+ (Size) type_len,
+ resname,
+ (Index) 0,
+ (Oid) 0,
+ 0);
+
+ tent->expr = expr;
+ break;
+ }
+ case T_ParamNo:
+ case T_FuncCall:
+ case T_A_Const:
+ case T_A_Expr:
+ {
+ Node *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
+
+ handleTargetColname(pstate, &res->name, NULL, NULL);
+ /* note indirection has not been transformed */
+ if (pstate->p_is_insert && res->indirection != NIL)
+ {
+ /* this is an array assignment */
+ char *val;
+ char *str,
+ *save_str;
+ List *elt;
+ int i = 0,
+ ndims;
+ int lindx[MAXDIM],
+ uindx[MAXDIM];
+ int resdomno;
+ Relation rd;
+ Value *constval;
+
+ if (exprType(expr) != UNKNOWNOID ||
+ !IsA(expr, Const))
+ elog(WARN, "yyparse: string constant expected");
+
+ val = (char *) textout((struct varlena *)
+ ((Const *) expr)->constvalue);
+ str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);
+ foreach(elt, res->indirection)
+ {
+ A_Indices *aind = (A_Indices *) lfirst(elt);
+
+ aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
+ if (!IsA(aind->uidx, Const))
+ elog(WARN,
+ "Array Index for Append should be a constant");
+ uindx[i] = ((Const *) aind->uidx)->constvalue;
+ if (aind->lidx != NULL)
+ {
+ aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
+ if (!IsA(aind->lidx, Const))
+ elog(WARN,
+ "Array Index for Append should be a constant");
+ lindx[i] = ((Const *) aind->lidx)->constvalue;
+ }
+ else
+ {
+ lindx[i] = 1;
+ }
+ if (lindx[i] > uindx[i])
+ elog(WARN, "yyparse: lower index cannot be greater than upper index");
+ sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
+ str += strlen(str);
+ i++;
+ }
+ sprintf(str, "=%s", val);
+ rd = pstate->p_target_relation;
+ Assert(rd != NULL);
+ resdomno = varattno(rd, res->name);
+ ndims = att_attnelems(rd, resdomno);
+ if (i != ndims)
+ elog(WARN, "yyparse: array dimensions do not match");
+ constval = makeNode(Value);
+ constval->type = T_String;
+ constval->val.str = save_str;
+ tent = make_targetlist_expr(pstate, res->name,
+ (Node *) make_const(constval),
+ NULL);
+ pfree(save_str);
+ }
+ else
+ {
+ char *colname = res->name;
+
+ /* this is not an array assignment */
+ if (colname == NULL)
+ {
+
+ /*
+ * if you're wondering why this is here, look at
+ * the yacc grammar for why a name can be missing.
+ * -ay
+ */
+ colname = figureColname(expr, res->val);
+ }
+ if (res->indirection)
+ {
+ List *ilist = res->indirection;
+
+ while (ilist != NIL)
+ {
+ A_Indices *ind = lfirst(ilist);
+
+ ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
+ ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
+ ilist = lnext(ilist);
+ }
+ }
+ res->name = colname;
+ tent = make_targetlist_expr(pstate, res->name, expr,
+ res->indirection);
+ }
+ break;
+ }
+ case T_Attr:
+ {
+ Oid type_id;
+ int type_len;
+ Attr *att = (Attr *) res->val;
+ Node *result;
+ char *attrname;
+ char *resname;
+ Resdom *resnode;
+ List *attrs = att->attrs;
+
+ /*
+ * Target item is a single '*', expand all tables (eg.
+ * SELECT * FROM emp)
+ */
+ if (att->relname != NULL && !strcmp(att->relname, "*"))
+ {
+ if (tail_p_target == NIL)
+ p_target = tail_p_target = expandAllTables(pstate);
+ else
+ lnext(tail_p_target) = expandAllTables(pstate);
+
+ while (lnext(tail_p_target) != NIL)
+ /* make sure we point to the last target entry */
+ tail_p_target = lnext(tail_p_target);
+
+ /*
+ * skip rest of while loop
+ */
+ targetlist = lnext(targetlist);
+ continue;
+ }
+
+ /*
+ * Target item is relation.*, expand the table (eg. SELECT
+ * emp.*, dname FROM emp, dept)
+ */
+ attrname = strVal(lfirst(att->attrs));
+ if (att->attrs != NIL && !strcmp(attrname, "*"))
+ {
+
+ /*
+ * tail_p_target is the target list we're building in
+ * the while loop. Make sure we fix it after appending
+ * more nodes.
+ */
+ if (tail_p_target == NIL)
+ p_target = tail_p_target = expandAll(pstate, att->relname,
+ att->relname, &pstate->p_last_resno);
+ else
+ lnext(tail_p_target) =
+ expandAll(pstate, att->relname, att->relname,
+ &pstate->p_last_resno);
+ while (lnext(tail_p_target) != NIL)
+ /* make sure we point to the last target entry */
+ tail_p_target = lnext(tail_p_target);
+
+ /*
+ * skip the rest of the while loop
+ */
+ targetlist = lnext(targetlist);
+ continue;
+ }
+
+
+ /*
+ * Target item is fully specified: ie. relation.attribute
+ */
+ result = handleNestedDots(pstate, att, &pstate->p_last_resno);
+ handleTargetColname(pstate, &res->name, att->relname, attrname);
+ if (att->indirection != NIL)
+ {
+ List *ilist = att->indirection;
+
+ while (ilist != NIL)
+ {
+ A_Indices *ind = lfirst(ilist);
+
+ ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
+ ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
+ ilist = lnext(ilist);
+ }
+ result = (Node *) make_array_ref(result, att->indirection);
+ }
+ type_id = exprType(result);
+ type_len = tlen(get_id_type(type_id));
+ /* move to last entry */
+ while (lnext(attrs) != NIL)
+ attrs = lnext(attrs);
+ resname = (res->name) ? res->name : strVal(lfirst(attrs));
+ resnode = makeResdom((AttrNumber) pstate->p_last_resno++,
+ (Oid) type_id,
+ (Size) type_len,
+ resname,
+ (Index) 0,
+ (Oid) 0,
+ 0);
+ tent->resdom = resnode;
+ tent->expr = result;
+ break;
+ }
+ default:
+ /* internal error */
elog(WARN,
- "Array Index for Append should be a constant");
- uindx[i] = ((Const *)aind->uidx)->constvalue;
- if (aind->lidx!=NULL) {
- aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
- if (!IsA(aind->lidx,Const))
- elog(WARN,
- "Array Index for Append should be a constant");
- lindx[i] = ((Const*)aind->lidx)->constvalue;
- }else {
- lindx[i] = 1;
- }
- if (lindx[i] > uindx[i])
- elog(WARN, "yyparse: lower index cannot be greater than upper index");
- sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
- str += strlen(str);
- i++;
- }
- sprintf(str, "=%s", val);
- rd = pstate->p_target_relation;
- Assert(rd != NULL);
- resdomno = varattno(rd, res->name);
- ndims = att_attnelems(rd, resdomno);
- if (i != ndims)
- elog(WARN, "yyparse: array dimensions do not match");
- constval = makeNode(Value);
- constval->type = T_String;
- constval->val.str = save_str;
- tent = make_targetlist_expr(pstate, res->name,
- (Node*)make_const(constval),
- NULL);
- pfree(save_str);
- } else {
- char *colname= res->name;
- /* this is not an array assignment */
- if (colname==NULL) {
- /* if you're wondering why this is here, look at
- * the yacc grammar for why a name can be missing. -ay
- */
- colname = figureColname(expr, res->val);
- }
- if (res->indirection) {
- List *ilist = res->indirection;
- while (ilist!=NIL) {
- A_Indices *ind = lfirst(ilist);
- ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
- ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
- ilist = lnext(ilist);
- }
+ "internal error: do not know how to transform targetlist");
+ break;
}
- res->name = colname;
- tent = make_targetlist_expr(pstate, res->name, expr,
- res->indirection);
- }
- break;
- }
- case T_Attr: {
- Oid type_id;
- int type_len;
- Attr *att = (Attr *)res->val;
- Node *result;
- char *attrname;
- char *resname;
- Resdom *resnode;
- List *attrs = att->attrs;
-
- /*
- * Target item is a single '*', expand all tables
- * (eg. SELECT * FROM emp)
- */
- if (att->relname!=NULL && !strcmp(att->relname, "*")) {
- if (tail_p_target == NIL)
- p_target = tail_p_target = expandAllTables(pstate);
- else
- lnext(tail_p_target) = expandAllTables(pstate);
- while(lnext(tail_p_target)!=NIL)
- /* make sure we point to the last target entry */
- tail_p_target = lnext(tail_p_target);
- /*
- * skip rest of while loop
- */
- targetlist = lnext(targetlist);
- continue;
- }
-
- /*
- * Target item is relation.*, expand the table
- * (eg. SELECT emp.*, dname FROM emp, dept)
- */
- attrname = strVal(lfirst(att->attrs));
- if (att->attrs!=NIL && !strcmp(attrname,"*")) {
- /* tail_p_target is the target list we're building in the while
- * loop. Make sure we fix it after appending more nodes.
- */
- if (tail_p_target == NIL)
- p_target = tail_p_target = expandAll(pstate, att->relname,
- att->relname, &pstate->p_last_resno);
+ if (p_target == NIL)
+ {
+ p_target = tail_p_target = lcons(tent, NIL);
+ }
else
- lnext(tail_p_target) =
- expandAll(pstate, att->relname, att->relname,
- &pstate->p_last_resno);
- while(lnext(tail_p_target)!=NIL)
- /* make sure we point to the last target entry */
- tail_p_target = lnext(tail_p_target);
- /*
- * skip the rest of the while loop
- */
- targetlist = lnext(targetlist);
- continue;
- }
-
-
- /*
- * Target item is fully specified: ie. relation.attribute
- */
- result = handleNestedDots(pstate, att, &pstate->p_last_resno);
- handleTargetColname(pstate, &res->name, att->relname, attrname);
- if (att->indirection != NIL) {
- List *ilist = att->indirection;
- while (ilist!=NIL) {
- A_Indices *ind = lfirst(ilist);
- ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
- ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
- ilist = lnext(ilist);
+ {
+ lnext(tail_p_target) = lcons(tent, NIL);
+ tail_p_target = lnext(tail_p_target);
}
- result = (Node*)make_array_ref(result, att->indirection);
- }
- type_id = exprType(result);
- type_len = tlen(get_id_type(type_id));
- /* move to last entry */
- while(lnext(attrs)!=NIL)
- attrs=lnext(attrs);
- resname = (res->name) ? res->name : strVal(lfirst(attrs));
- resnode = makeResdom((AttrNumber)pstate->p_last_resno++,
- (Oid)type_id,
- (Size)type_len,
- resname,
- (Index)0,
- (Oid)0,
- 0);
- tent->resdom = resnode;
- tent->expr = result;
- break;
- }
- default:
- /* internal error */
- elog(WARN,
- "internal error: do not know how to transform targetlist");
- break;
- }
-
- if (p_target == NIL) {
- p_target = tail_p_target = lcons(tent, NIL);
- }else {
- lnext(tail_p_target) = lcons(tent, NIL);
- tail_p_target = lnext(tail_p_target);
+ targetlist = lnext(targetlist);
}
- targetlist = lnext(targetlist);
- }
- return p_target;
+ return p_target;
}
/*
* make_targetlist_expr -
- * make a TargetEntry from an expression
+ * make a TargetEntry from an expression
*
* arrayRef is a list of transformed A_Indices
*/
static TargetEntry *
-make_targetlist_expr(ParseState *pstate,
- char *colname,
- Node *expr,
- List *arrayRef)
+make_targetlist_expr(ParseState * pstate,
+ char *colname,
+ Node * expr,
+ List * arrayRef)
{
- Oid type_id, attrtype;
- int type_len, attrlen;
- int resdomno;
- Relation rd;
- bool attrisset;
- TargetEntry *tent;
- Resdom *resnode;
-
- if (expr == NULL)
- elog(WARN, "make_targetlist_expr: invalid use of NULL expression");
-
- type_id = exprType(expr);
- if (type_id == InvalidOid) {
- type_len = 0;
- } else
- type_len = tlen(get_id_type(type_id));
-
- /* I have no idea what the following does! */
- /* It appears to process target columns that will be receiving results */
- if (pstate->p_is_insert||pstate->p_is_update) {
- /*
- * append or replace query --
- * append, replace work only on one relation,
- * so multiple occurence of same resdomno is bogus
- */
- rd = pstate->p_target_relation;
- Assert(rd != NULL);
- resdomno = varattno(rd,colname);
- attrisset = varisset(rd,colname);
- attrtype = att_typeid(rd,resdomno);
- if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
- attrtype = GetArrayElementType(attrtype);
- if (attrtype==BPCHAROID || attrtype==VARCHAROID) {
- attrlen = rd->rd_att->attrs[resdomno-1]->attlen;
- } else {
- attrlen = tlen(get_id_type(attrtype));
- }
+ Oid type_id,
+ attrtype;
+ int type_len,
+ attrlen;
+ int resdomno;
+ Relation rd;
+ bool attrisset;
+ TargetEntry *tent;
+ Resdom *resnode;
+
+ if (expr == NULL)
+ elog(WARN, "make_targetlist_expr: invalid use of NULL expression");
+
+ type_id = exprType(expr);
+ if (type_id == InvalidOid)
+ {
+ type_len = 0;
+ }
+ else
+ type_len = tlen(get_id_type(type_id));
+
+ /* I have no idea what the following does! */
+ /* It appears to process target columns that will be receiving results */
+ if (pstate->p_is_insert || pstate->p_is_update)
+ {
+
+ /*
+ * append or replace query -- append, replace work only on one
+ * relation, so multiple occurence of same resdomno is bogus
+ */
+ rd = pstate->p_target_relation;
+ Assert(rd != NULL);
+ resdomno = varattno(rd, colname);
+ attrisset = varisset(rd, colname);
+ attrtype = att_typeid(rd, resdomno);
+ if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
+ attrtype = GetArrayElementType(attrtype);
+ if (attrtype == BPCHAROID || attrtype == VARCHAROID)
+ {
+ attrlen = rd->rd_att->attrs[resdomno - 1]->attlen;
+ }
+ else
+ {
+ attrlen = tlen(get_id_type(attrtype));
+ }
#if 0
- if(Input_is_string && Typecast_ok){
- Datum val;
- if (type_id == typeid(type("unknown"))){
- val = (Datum)textout((struct varlena *)
- ((Const)lnext(expr))->constvalue);
- }else{
- val = ((Const)lnext(expr))->constvalue;
- }
- if (attrisset) {
- lnext(expr) = makeConst(attrtype,
- attrlen,
- val,
- false,
- true,
- true, /* is set */
- false);
- } else {
- lnext(expr) =
- makeConst(attrtype,
- attrlen,
- (Datum)fmgr(typeid_get_retinfunc(attrtype),
- val,get_typelem(attrtype),-1),
- false,
- true /* Maybe correct-- 80% chance */,
- false, /* is not a set */
- false);
- }
- } else if((Typecast_ok) && (attrtype != type_id)){
- lnext(expr) =
- parser_typecast2(expr, get_id_type(attrtype));
- } else
- if (attrtype != type_id) {
- if ((attrtype == INT2OID) && (type_id == INT4OID))
- lfirst(expr) = lispInteger (INT2OID); /* handle CASHOID too*/
- else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
- lfirst(expr) = lispInteger (FLOAT4OID);
- else
- elog(WARN, "unequal type in tlist : %s \n", colname);
- }
-
- Input_is_string = false;
- Input_is_integer = false;
- Typecast_ok = true;
+ if (Input_is_string && Typecast_ok)
+ {
+ Datum val;
+
+ if (type_id == typeid(type("unknown")))
+ {
+ val = (Datum) textout((struct varlena *)
+ ((Const) lnext(expr))->constvalue);
+ }
+ else
+ {
+ val = ((Const) lnext(expr))->constvalue;
+ }
+ if (attrisset)
+ {
+ lnext(expr) = makeConst(attrtype,
+ attrlen,
+ val,
+ false,
+ true,
+ true, /* is set */
+ false);
+ }
+ else
+ {
+ lnext(expr) =
+ makeConst(attrtype,
+ attrlen,
+ (Datum) fmgr(typeid_get_retinfunc(attrtype),
+ val, get_typelem(attrtype), -1),
+ false,
+ true /* Maybe correct-- 80% chance */ ,
+ false, /* is not a set */
+ false);
+ }
+ }
+ else if ((Typecast_ok) && (attrtype != type_id))
+ {
+ lnext(expr) =
+ parser_typecast2(expr, get_id_type(attrtype));
+ }
+ else if (attrtype != type_id)
+ {
+ if ((attrtype == INT2OID) && (type_id == INT4OID))
+ lfirst(expr) = lispInteger(INT2OID); /* handle CASHOID too */
+ else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
+ lfirst(expr) = lispInteger(FLOAT4OID);
+ else
+ elog(WARN, "unequal type in tlist : %s \n", colname);
+ }
+
+ Input_is_string = false;
+ Input_is_integer = false;
+ Typecast_ok = true;
#endif
- if (attrtype != type_id) {
- if (IsA(expr,Const)) {
- /* try to cast the constant */
- if (arrayRef && !(((A_Indices *)lfirst(arrayRef))->lidx)) {
- /* updating a single item */
- Oid typelem = get_typelem(attrtype);
- expr = (Node*)parser_typecast2(expr,
- type_id,
- get_id_type(typelem),
- attrlen);
- } else
- expr = (Node*)parser_typecast2(expr,
- type_id,
- get_id_type(attrtype),
- attrlen);
- } else {
- /* currently, we can't handle casting of expressions */
- elog(WARN, "parser: attribute '%s' is of type '%s' but expression is of type '%s'",
- colname,
- get_id_typname(attrtype),
- get_id_typname(type_id));
- }
- }
-
- if (arrayRef != NIL) {
- Expr *target_expr;
- Attr *att = makeNode(Attr);
- List *ar = arrayRef;
- List *upperIndexpr = NIL;
- List *lowerIndexpr = NIL;
-
- att->relname = pstrdup(RelationGetRelationName(rd)->data);
- att->attrs = lcons(makeString(colname), NIL);
- target_expr = (Expr*)handleNestedDots(pstate, att,
- &pstate->p_last_resno);
- while(ar!=NIL) {
- A_Indices *ind = lfirst(ar);
- if (lowerIndexpr || (!upperIndexpr && ind->lidx)) {
- /* XXX assume all lowerIndexpr is non-null in
- * this case
- */
- lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
- }
- upperIndexpr = lappend(upperIndexpr, ind->uidx);
- ar = lnext(ar);
- }
-
- expr = (Node*)make_array_set(target_expr,
- upperIndexpr,
- lowerIndexpr,
- (Expr*)expr);
- attrtype = att_typeid(rd,resdomno);
- attrlen = tlen(get_id_type(attrtype));
- }
- } else {
- resdomno = pstate->p_last_resno++;
- attrtype = type_id;
- attrlen = type_len;
- }
- tent = makeNode(TargetEntry);
-
- resnode = makeResdom((AttrNumber)resdomno,
- (Oid) attrtype,
- (Size) attrlen,
- colname,
- (Index)0,
- (Oid)0,
- 0);
-
- tent->resdom = resnode;
- tent->expr = expr;
-
- return tent;
+ if (attrtype != type_id)
+ {
+ if (IsA(expr, Const))
+ {
+ /* try to cast the constant */
+ if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
+ {
+ /* updating a single item */
+ Oid typelem = get_typelem(attrtype);
+
+ expr = (Node *) parser_typecast2(expr,
+ type_id,
+ get_id_type(typelem),
+ attrlen);
+ }
+ else
+ expr = (Node *) parser_typecast2(expr,
+ type_id,
+ get_id_type(attrtype),
+ attrlen);
+ }
+ else
+ {
+ /* currently, we can't handle casting of expressions */
+ elog(WARN, "parser: attribute '%s' is of type '%s' but expression is of type '%s'",
+ colname,
+ get_id_typname(attrtype),
+ get_id_typname(type_id));
+ }
+ }
+
+ if (arrayRef != NIL)
+ {
+ Expr *target_expr;
+ Attr *att = makeNode(Attr);
+ List *ar = arrayRef;
+ List *upperIndexpr = NIL;
+ List *lowerIndexpr = NIL;
+
+ att->relname = pstrdup(RelationGetRelationName(rd)->data);
+ att->attrs = lcons(makeString(colname), NIL);
+ target_expr = (Expr *) handleNestedDots(pstate, att,
+ &pstate->p_last_resno);
+ while (ar != NIL)
+ {
+ A_Indices *ind = lfirst(ar);
+
+ if (lowerIndexpr || (!upperIndexpr && ind->lidx))
+ {
+
+ /*
+ * XXX assume all lowerIndexpr is non-null in this
+ * case
+ */
+ lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
+ }
+ upperIndexpr = lappend(upperIndexpr, ind->uidx);
+ ar = lnext(ar);
+ }
+
+ expr = (Node *) make_array_set(target_expr,
+ upperIndexpr,
+ lowerIndexpr,
+ (Expr *) expr);
+ attrtype = att_typeid(rd, resdomno);
+ attrlen = tlen(get_id_type(attrtype));
+ }
+ }
+ else
+ {
+ resdomno = pstate->p_last_resno++;
+ attrtype = type_id;
+ attrlen = type_len;
+ }
+ tent = makeNode(TargetEntry);
+
+ resnode = makeResdom((AttrNumber) resdomno,
+ (Oid) attrtype,
+ (Size) attrlen,
+ colname,
+ (Index) 0,
+ (Oid) 0,
+ 0);
+
+ tent->resdom = resnode;
+ tent->expr = expr;
+
+ return tent;
}
@@ -1449,26 +1596,27 @@ make_targetlist_expr(ParseState *pstate,
/*
* transformWhereClause -
- * transforms the qualification and make sure it is of type Boolean
+ * transforms the qualification and make sure it is of type Boolean
*
*/
-static Node *
-transformWhereClause(ParseState *pstate, Node *a_expr)
+static Node *
+transformWhereClause(ParseState * pstate, Node * a_expr)
{
- Node *qual;
-
- if (a_expr == NULL)
- return (Node *)NULL; /* no qualifiers */
-
- inWhereClause = true;
- qual = transformExpr(pstate, a_expr, EXPR_COLUMN_FIRST);
- inWhereClause = false;
- if (exprType(qual) != BOOLOID) {
- elog(WARN,
- "where clause must return type bool, not %s",
- tname(get_id_type(exprType(qual))));
- }
- return qual;
+ Node *qual;
+
+ if (a_expr == NULL)
+ return (Node *) NULL; /* no qualifiers */
+
+ inWhereClause = true;
+ qual = transformExpr(pstate, a_expr, EXPR_COLUMN_FIRST);
+ inWhereClause = false;
+ if (exprType(qual) != BOOLOID)
+ {
+ elog(WARN,
+ "where clause must return type bool, not %s",
+ tname(get_id_type(exprType(qual))));
+ }
+ return qual;
}
/*****************************************************************************
@@ -1478,203 +1626,237 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
*****************************************************************************/
/*
- * find_targetlist_entry -
- * returns the Resdom in the target list matching the specified varname
- * and range
+ * find_targetlist_entry -
+ * returns the Resdom in the target list matching the specified varname
+ * and range
*
*/
static TargetEntry *
-find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
+find_targetlist_entry(ParseState * pstate, SortGroupBy * sortgroupby, List * tlist)
{
- List *i;
- int real_rtable_pos = 0, target_pos = 0;
- TargetEntry *target_result = NULL;
-
- if(sortgroupby->range)
- real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable,
- sortgroupby->range);
-
- foreach(i, tlist) {
- TargetEntry *target = (TargetEntry *)lfirst(i);
- Resdom *resnode = target->resdom;
- Var *var = (Var *)target->expr;
- char *resname = resnode->resname;
- int test_rtable_pos = var->varno;
+ List *i;
+ int real_rtable_pos = 0,
+ target_pos = 0;
+ TargetEntry *target_result = NULL;
+
+ if (sortgroupby->range)
+ real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable,
+ sortgroupby->range);
+
+ foreach(i, tlist)
+ {
+ TargetEntry *target = (TargetEntry *) lfirst(i);
+ Resdom *resnode = target->resdom;
+ Var *var = (Var *) target->expr;
+ char *resname = resnode->resname;
+ int test_rtable_pos = var->varno;
#ifdef PARSEDEBUG
-printf("find_targetlist_entry- target name is %s, position %d, resno %d\n",
- (sortgroupby->name? sortgroupby->name: "(null)"), target_pos+1, sortgroupby->resno);
+ printf("find_targetlist_entry- target name is %s, position %d, resno %d\n",
+ (sortgroupby->name ? sortgroupby->name : "(null)"), target_pos + 1, sortgroupby->resno);
#endif
- if (!sortgroupby->name) {
- if (sortgroupby->resno == ++target_pos) {
- target_result = target;
- break;
- }
- }
- else {
- if (!strcmp(resname, sortgroupby->name)) {
- if(sortgroupby->range) {
- if(real_rtable_pos == test_rtable_pos) {
- if (target_result != NULL)
- elog(WARN, "Order/Group By %s is ambiguous", sortgroupby->name);
- else target_result = target;
- }
- }
- else {
- if (target_result != NULL)
- elog(WARN, "Order/Group By %s is ambiguous", sortgroupby->name);
- else target_result = target;
- }
- }
+ if (!sortgroupby->name)
+ {
+ if (sortgroupby->resno == ++target_pos)
+ {
+ target_result = target;
+ break;
+ }
+ }
+ else
+ {
+ if (!strcmp(resname, sortgroupby->name))
+ {
+ if (sortgroupby->range)
+ {
+ if (real_rtable_pos == test_rtable_pos)
+ {
+ if (target_result != NULL)
+ elog(WARN, "Order/Group By %s is ambiguous", sortgroupby->name);
+ else
+ target_result = target;
+ }
+ }
+ else
+ {
+ if (target_result != NULL)
+ elog(WARN, "Order/Group By %s is ambiguous", sortgroupby->name);
+ else
+ target_result = target;
+ }
+ }
+ }
}
- }
- return target_result;
+ return target_result;
}
-static Oid
+static Oid
any_ordering_op(int restype)
{
- Operator order_op;
- Oid order_opid;
-
- order_op = oper("<",restype,restype,false);
- order_opid = oprid(order_op);
-
- return order_opid;
+ Operator order_op;
+ Oid order_opid;
+
+ order_op = oper("<", restype, restype, false);
+ order_opid = oprid(order_op);
+
+ return order_opid;
}
/*
* transformGroupClause -
- * transform a Group By clause
+ * transform a Group By clause
*
*/
-static List *
-transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
+static List *
+transformGroupClause(ParseState * pstate, List * grouplist, List * targetlist)
{
- List *glist = NIL, *gl = NIL;
-
- while (grouplist != NIL) {
- GroupClause *grpcl = makeNode(GroupClause);
- TargetEntry *restarget;
- Resdom *resdom;
-
- restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
-
- if (restarget == NULL)
- elog(WARN,"The field being grouped by must appear in the target list");
-
- grpcl->entry = restarget;
- resdom = restarget->resdom;
- grpcl->grpOpoid = oprid(oper("<",
- resdom->restype,
- resdom->restype,false));
- if (glist == NIL)
- gl = glist = lcons(grpcl, NIL);
- else {
- lnext(gl) = lcons(grpcl, NIL);
- gl = lnext(gl);
+ List *glist = NIL,
+ *gl = NIL;
+
+ while (grouplist != NIL)
+ {
+ GroupClause *grpcl = makeNode(GroupClause);
+ TargetEntry *restarget;
+ Resdom *resdom;
+
+ restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
+
+ if (restarget == NULL)
+ elog(WARN, "The field being grouped by must appear in the target list");
+
+ grpcl->entry = restarget;
+ resdom = restarget->resdom;
+ grpcl->grpOpoid = oprid(oper("<",
+ resdom->restype,
+ resdom->restype, false));
+ if (glist == NIL)
+ gl = glist = lcons(grpcl, NIL);
+ else
+ {
+ lnext(gl) = lcons(grpcl, NIL);
+ gl = lnext(gl);
+ }
+ grouplist = lnext(grouplist);
}
- grouplist = lnext(grouplist);
- }
- return glist;
+ return glist;
}
/*
* transformSortClause -
- * transform an Order By clause
+ * transform an Order By clause
*
*/
-static List *
-transformSortClause(ParseState *pstate,
- List *orderlist, List *targetlist,
- char* uniqueFlag)
+static List *
+transformSortClause(ParseState * pstate,
+ List * orderlist, List * targetlist,
+ char *uniqueFlag)
{
- List *sortlist = NIL;
- List *s = NIL, *i;
-
- while(orderlist != NIL) {
- SortGroupBy *sortby = lfirst(orderlist);
- SortClause *sortcl = makeNode(SortClause);
- TargetEntry *restarget;
- Resdom *resdom;
-
- restarget = find_targetlist_entry(pstate, sortby, targetlist);
- if (restarget == NULL)
- elog(WARN,"The field being ordered by must appear in the target list");
-
- sortcl->resdom = resdom = restarget->resdom;
- sortcl->opoid = oprid(oper(sortby->useOp,
- resdom->restype,
- resdom->restype,false));
- if (sortlist == NIL) {
- s = sortlist = lcons(sortcl, NIL);
- }else {
- lnext(s) = lcons(sortcl, NIL);
- s = lnext(s);
+ List *sortlist = NIL;
+ List *s = NIL,
+ *i;
+
+ while (orderlist != NIL)
+ {
+ SortGroupBy *sortby = lfirst(orderlist);
+ SortClause *sortcl = makeNode(SortClause);
+ TargetEntry *restarget;
+ Resdom *resdom;
+
+ restarget = find_targetlist_entry(pstate, sortby, targetlist);
+ if (restarget == NULL)
+ elog(WARN, "The field being ordered by must appear in the target list");
+
+ sortcl->resdom = resdom = restarget->resdom;
+ sortcl->opoid = oprid(oper(sortby->useOp,
+ resdom->restype,
+ resdom->restype, false));
+ if (sortlist == NIL)
+ {
+ s = sortlist = lcons(sortcl, NIL);
+ }
+ else
+ {
+ lnext(s) = lcons(sortcl, NIL);
+ s = lnext(s);
+ }
+ orderlist = lnext(orderlist);
}
- orderlist = lnext(orderlist);
- }
-
- if (uniqueFlag) {
- if (uniqueFlag[0] == '*') {
- /* concatenate all elements from target list
- that are not already in the sortby list */
- foreach (i,targetlist) {
- TargetEntry *tlelt = (TargetEntry *)lfirst(i);
-
- s = sortlist;
- while(s != NIL) {
- SortClause *sortcl = lfirst(s);
- if (sortcl->resdom==tlelt->resdom)
- break;
- s = lnext(s);
- }
- if (s == NIL) {
- /* not a member of the sortclauses yet */
- SortClause *sortcl = makeNode(SortClause);
-
- sortcl->resdom = tlelt->resdom;
- sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
-
- sortlist = lappend(sortlist, sortcl);
- }
- }
- }
- else {
- TargetEntry *tlelt = NULL;
- char* uniqueAttrName = uniqueFlag;
-
- /* only create sort clause with the specified unique attribute */
- foreach (i, targetlist) {
- tlelt = (TargetEntry*)lfirst(i);
- if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0)
- break;
- }
- if (i == NIL) {
- elog(WARN, "The field specified in the UNIQUE ON clause is not in the targetlist");
- }
- s = sortlist;
- foreach (s, sortlist) {
- SortClause *sortcl = lfirst(s);
- if (sortcl->resdom == tlelt->resdom)
- break;
- }
- if (s == NIL) {
- /* not a member of the sortclauses yet */
- SortClause *sortcl = makeNode(SortClause);
-
- sortcl->resdom = tlelt->resdom;
- sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
-
- sortlist = lappend(sortlist, sortcl);
- }
+
+ if (uniqueFlag)
+ {
+ if (uniqueFlag[0] == '*')
+ {
+
+ /*
+ * concatenate all elements from target list that are not
+ * already in the sortby list
+ */
+ foreach(i, targetlist)
+ {
+ TargetEntry *tlelt = (TargetEntry *) lfirst(i);
+
+ s = sortlist;
+ while (s != NIL)
+ {
+ SortClause *sortcl = lfirst(s);
+
+ if (sortcl->resdom == tlelt->resdom)
+ break;
+ s = lnext(s);
+ }
+ if (s == NIL)
+ {
+ /* not a member of the sortclauses yet */
+ SortClause *sortcl = makeNode(SortClause);
+
+ sortcl->resdom = tlelt->resdom;
+ sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
+
+ sortlist = lappend(sortlist, sortcl);
+ }
+ }
+ }
+ else
+ {
+ TargetEntry *tlelt = NULL;
+ char *uniqueAttrName = uniqueFlag;
+
+ /* only create sort clause with the specified unique attribute */
+ foreach(i, targetlist)
+ {
+ tlelt = (TargetEntry *) lfirst(i);
+ if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0)
+ break;
+ }
+ if (i == NIL)
+ {
+ elog(WARN, "The field specified in the UNIQUE ON clause is not in the targetlist");
+ }
+ s = sortlist;
+ foreach(s, sortlist)
+ {
+ SortClause *sortcl = lfirst(s);
+
+ if (sortcl->resdom == tlelt->resdom)
+ break;
+ }
+ if (s == NIL)
+ {
+ /* not a member of the sortclauses yet */
+ SortClause *sortcl = makeNode(SortClause);
+
+ sortcl->resdom = tlelt->resdom;
+ sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
+
+ sortlist = lappend(sortlist, sortcl);
+ }
+ }
+
}
- }
-
- return sortlist;
+ return sortlist;
}
/*
@@ -1682,578 +1864,645 @@ transformSortClause(ParseState *pstate,
** Given a nested dot expression (i.e. (relation func ... attr), build up
** a tree with of Iter and Func nodes.
*/
-static Node*
-handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno)
+static Node *
+handleNestedDots(ParseState * pstate, Attr * attr, int *curr_resno)
{
- List *mutator_iter;
- Node *retval = NULL;
-
- if (attr->paramNo != NULL) {
- Param *param = (Param *)transformExpr(pstate, (Node*)attr->paramNo, EXPR_RELATION_FIRST);
-
- retval =
- ParseFunc(pstate, strVal(lfirst(attr->attrs)),
- lcons(param, NIL),
- curr_resno);
- } else {
- Ident *ident = makeNode(Ident);
-
- ident->name = attr->relname;
- ident->isRel = TRUE;
- retval =
- ParseFunc(pstate, strVal(lfirst(attr->attrs)),
- lcons(ident, NIL),
- curr_resno);
- }
-
- foreach (mutator_iter, lnext(attr->attrs)) {
- retval = ParseFunc(pstate,strVal(lfirst(mutator_iter)),
- lcons(retval, NIL),
- curr_resno);
- }
-
- return(retval);
+ List *mutator_iter;
+ Node *retval = NULL;
+
+ if (attr->paramNo != NULL)
+ {
+ Param *param = (Param *) transformExpr(pstate, (Node *) attr->paramNo, EXPR_RELATION_FIRST);
+
+ retval =
+ ParseFunc(pstate, strVal(lfirst(attr->attrs)),
+ lcons(param, NIL),
+ curr_resno);
+ }
+ else
+ {
+ Ident *ident = makeNode(Ident);
+
+ ident->name = attr->relname;
+ ident->isRel = TRUE;
+ retval =
+ ParseFunc(pstate, strVal(lfirst(attr->attrs)),
+ lcons(ident, NIL),
+ curr_resno);
+ }
+
+ foreach(mutator_iter, lnext(attr->attrs))
+ {
+ retval = ParseFunc(pstate, strVal(lfirst(mutator_iter)),
+ lcons(retval, NIL),
+ curr_resno);
+ }
+
+ return (retval);
}
/*
** make_arguments --
- ** Given the number and types of arguments to a function, and the
+ ** Given the number and types of arguments to a function, and the
** actual arguments and argument types, do the necessary typecasting.
*/
static void
make_arguments(int nargs,
- List *fargs,
- Oid *input_typeids,
- Oid *function_typeids)
+ List * fargs,
+ Oid * input_typeids,
+ Oid * function_typeids)
{
- /*
- * there are two ways an input typeid can differ from a function typeid :
- * either the input type inherits the function type, so no typecasting is
- * necessary, or the input type can be typecast into the function type.
- * right now, we only typecast unknowns, and that is all we check for.
- */
-
- List *current_fargs;
- int i;
-
- for (i=0, current_fargs = fargs;
- i<nargs;
- i++, current_fargs = lnext(current_fargs)) {
-
- if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid) {
- lfirst(current_fargs) =
- parser_typecast2(lfirst(current_fargs),
- input_typeids[i],
- get_id_type(function_typeids[i]),
- -1);
+
+ /*
+ * there are two ways an input typeid can differ from a function
+ * typeid : either the input type inherits the function type, so no
+ * typecasting is necessary, or the input type can be typecast into
+ * the function type. right now, we only typecast unknowns, and that
+ * is all we check for.
+ */
+
+ List *current_fargs;
+ int i;
+
+ for (i = 0, current_fargs = fargs;
+ i < nargs;
+ i++, current_fargs = lnext(current_fargs))
+ {
+
+ if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid)
+ {
+ lfirst(current_fargs) =
+ parser_typecast2(lfirst(current_fargs),
+ input_typeids[i],
+ get_id_type(function_typeids[i]),
+ -1);
+ }
}
- }
}
/*
** setup_tlist --
- ** Build a tlist that says which attribute to project to.
- ** This routine is called by ParseFunc() to set up a target list
- ** on a tuple parameter or return value. Due to a bug in 4.0,
- ** it's not possible to refer to system attributes in this case.
+ ** Build a tlist that says which attribute to project to.
+ ** This routine is called by ParseFunc() to set up a target list
+ ** on a tuple parameter or return value. Due to a bug in 4.0,
+ ** it's not possible to refer to system attributes in this case.
*/
-static List *
+static List *
setup_tlist(char *attname, Oid relid)
{
- TargetEntry *tle;
- Resdom *resnode;
- Var *varnode;
- Oid typeid;
- int attno;
-
- attno = get_attnum(relid, attname);
- if (attno < 0)
- elog(WARN, "cannot reference attribute %s of tuple params/return values for functions", attname);
-
- typeid = find_atttype(relid, attname);
- resnode = makeResdom(1,
- typeid,
- tlen(get_id_type(typeid)),
- get_attname(relid, attno),
- 0,
- (Oid)0,
- 0);
- varnode = makeVar(-1, attno, typeid, -1, attno);
-
- tle = makeNode(TargetEntry);
- tle->resdom = resnode;
- tle->expr = (Node*)varnode;
- return (lcons(tle, NIL));
+ TargetEntry *tle;
+ Resdom *resnode;
+ Var *varnode;
+ Oid typeid;
+ int attno;
+
+ attno = get_attnum(relid, attname);
+ if (attno < 0)
+ elog(WARN, "cannot reference attribute %s of tuple params/return values for functions", attname);
+
+ typeid = find_atttype(relid, attname);
+ resnode = makeResdom(1,
+ typeid,
+ tlen(get_id_type(typeid)),
+ get_attname(relid, attno),
+ 0,
+ (Oid) 0,
+ 0);
+ varnode = makeVar(-1, attno, typeid, -1, attno);
+
+ tle = makeNode(TargetEntry);
+ tle->resdom = resnode;
+ tle->expr = (Node *) varnode;
+ return (lcons(tle, NIL));
}
/*
** setup_base_tlist --
- ** Build a tlist that extracts a base type from the tuple
- ** returned by the executor.
+ ** Build a tlist that extracts a base type from the tuple
+ ** returned by the executor.
*/
-static List *
+static List *
setup_base_tlist(Oid typeid)
{
- TargetEntry *tle;
- Resdom *resnode;
- Var *varnode;
-
- resnode = makeResdom(1,
- typeid,
- tlen(get_id_type(typeid)),
- "<noname>",
- 0,
- (Oid)0,
- 0);
- varnode = makeVar(-1, 1, typeid, -1, 1);
- tle = makeNode(TargetEntry);
- tle->resdom = resnode;
- tle->expr = (Node*)varnode;
-
- return (lcons(tle, NIL));
+ TargetEntry *tle;
+ Resdom *resnode;
+ Var *varnode;
+
+ resnode = makeResdom(1,
+ typeid,
+ tlen(get_id_type(typeid)),
+ "<noname>",
+ 0,
+ (Oid) 0,
+ 0);
+ varnode = makeVar(-1, 1, typeid, -1, 1);
+ tle = makeNode(TargetEntry);
+ tle->resdom = resnode;
+ tle->expr = (Node *) varnode;
+
+ return (lcons(tle, NIL));
}
/*
* ParseComplexProjection -
- * handles function calls with a single argument that is of complex type.
- * This routine returns NULL if it can't handle the projection (eg. sets).
+ * handles function calls with a single argument that is of complex type.
+ * This routine returns NULL if it can't handle the projection (eg. sets).
*/
-static Node *
-ParseComplexProjection(ParseState *pstate,
- char *funcname,
- Node *first_arg,
- bool *attisset)
+static Node *
+ParseComplexProjection(ParseState * pstate,
+ char *funcname,
+ Node * first_arg,
+ bool * attisset)
{
- Oid argtype;
- Oid argrelid;
- Name relname;
- Relation rd;
- Oid relid;
- int attnum;
-
- switch (nodeTag(first_arg)) {
- case T_Iter:
+ Oid argtype;
+ Oid argrelid;
+ Name relname;
+ Relation rd;
+ Oid relid;
+ int attnum;
+
+ switch (nodeTag(first_arg))
{
- Func *func;
- Iter *iter;
-
- iter = (Iter*)first_arg;
- func = (Func *)((Expr*)iter->iterexpr)->oper;
- argtype = funcid_get_rettype(func->funcid);
- argrelid = typeid_get_relid(argtype);
- if (argrelid &&
- ((attnum = get_attnum(argrelid, funcname))
- != InvalidAttrNumber)) {
-
- /* the argument is a function returning a tuple, so funcname
- may be a projection */
-
- /* add a tlist to the func node and return the Iter */
- rd = heap_openr(tname(get_id_type(argtype)));
- if (RelationIsValid(rd)) {
- relid = RelationGetRelationId(rd);
- relname = RelationGetRelationName(rd);
- heap_close(rd);
+ case T_Iter:
+ {
+ Func *func;
+ Iter *iter;
+
+ iter = (Iter *) first_arg;
+ func = (Func *) ((Expr *) iter->iterexpr)->oper;
+ argtype = funcid_get_rettype(func->funcid);
+ argrelid = typeid_get_relid(argtype);
+ if (argrelid &&
+ ((attnum = get_attnum(argrelid, funcname))
+ != InvalidAttrNumber))
+ {
+
+ /*
+ * the argument is a function returning a tuple, so
+ * funcname may be a projection
+ */
+
+ /* add a tlist to the func node and return the Iter */
+ rd = heap_openr(tname(get_id_type(argtype)));
+ if (RelationIsValid(rd))
+ {
+ relid = RelationGetRelationId(rd);
+ relname = RelationGetRelationName(rd);
+ heap_close(rd);
+ }
+ if (RelationIsValid(rd))
+ {
+ func->func_tlist =
+ setup_tlist(funcname, argrelid);
+ iter->itertype = att_typeid(rd, attnum);
+ return ((Node *) iter);
+ }
+ else
+ {
+ elog(WARN,
+ "Function %s has bad returntype %d",
+ funcname, argtype);
+ }
+ }
+ else
+ {
+ /* drop through */
+ ;
+ }
+ break;
}
- if (RelationIsValid(rd)) {
- func->func_tlist =
- setup_tlist(funcname, argrelid);
- iter->itertype = att_typeid(rd,attnum);
- return ((Node*)iter);
- }else {
- elog(WARN,
- "Function %s has bad returntype %d",
- funcname, argtype);
+ case T_Var:
+ {
+
+ /*
+ * The argument is a set, so this is either a projection or a
+ * function call on this set.
+ */
+ *attisset = true;
+ break;
}
- }else {
- /* drop through */
- ;
- }
- break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) first_arg;
+ Func *funcnode;
+
+ if (expr->opType != FUNC_EXPR)
+ break;
+
+ funcnode = (Func *) expr->oper;
+ argtype = funcid_get_rettype(funcnode->funcid);
+ argrelid = typeid_get_relid(argtype);
+
+ /*
+ * the argument is a function returning a tuple, so funcname
+ * may be a projection
+ */
+ if (argrelid &&
+ (attnum = get_attnum(argrelid, funcname))
+ != InvalidAttrNumber)
+ {
+
+ /* add a tlist to the func node */
+ rd = heap_openr(tname(get_id_type(argtype)));
+ if (RelationIsValid(rd))
+ {
+ relid = RelationGetRelationId(rd);
+ relname = RelationGetRelationName(rd);
+ heap_close(rd);
+ }
+ if (RelationIsValid(rd))
+ {
+ Expr *newexpr;
+
+ funcnode->func_tlist =
+ setup_tlist(funcname, argrelid);
+ funcnode->functype = att_typeid(rd, attnum);
+
+ newexpr = makeNode(Expr);
+ newexpr->typeOid = funcnode->functype;
+ newexpr->opType = FUNC_EXPR;
+ newexpr->oper = (Node *) funcnode;
+ newexpr->args = lcons(first_arg, NIL);
+
+ return ((Node *) newexpr);
+ }
+
+ }
+
+ elog(WARN, "Function %s has bad returntype %d",
+ funcname, argtype);
+ break;
+ }
+ case T_Param:
+ {
+ Param *param = (Param *) first_arg;
+
+ /*
+ * If the Param is a complex type, this could be a projection
+ */
+ rd = heap_openr(tname(get_id_type(param->paramtype)));
+ if (RelationIsValid(rd))
+ {
+ relid = RelationGetRelationId(rd);
+ relname = RelationGetRelationName(rd);
+ heap_close(rd);
+ }
+ if (RelationIsValid(rd) &&
+ (attnum = get_attnum(relid, funcname))
+ != InvalidAttrNumber)
+ {
+
+ param->paramtype = att_typeid(rd, attnum);
+ param->param_tlist = setup_tlist(funcname, relid);
+ return ((Node *) param);
+ }
+ break;
+ }
+ default:
+ break;
}
- case T_Var:
+
+ return NULL;
+}
+
+static Node *
+ParseFunc(ParseState * pstate, char *funcname, List * fargs, int *curr_resno)
+{
+ Oid rettype = (Oid) 0;
+ Oid argrelid = (Oid) 0;
+ Oid funcid = (Oid) 0;
+ List *i = NIL;
+ Node *first_arg = NULL;
+ char *relname = NULL;
+ char *refname = NULL;
+ Relation rd;
+ Oid relid;
+ int nargs;
+ Func *funcnode;
+ Oid oid_array[8];
+ Oid *true_oid_array;
+ Node *retval;
+ bool retset;
+ bool exists;
+ bool attisset = false;
+ Oid toid = (Oid) 0;
+ Expr *expr;
+
+ if (fargs)
{
- /*
- * The argument is a set, so this is either a projection
- * or a function call on this set.
- */
- *attisset = true;
- break;
+ first_arg = lfirst(fargs);
+ if (first_arg == NULL)
+ elog(WARN, "function %s does not allow NULL input", funcname);
}
- case T_Expr:
+
+ /*
+ * * check for projection methods: if function takes one argument, and *
+ * that argument is a relation, param, or PQ function returning a
+ * complex * type, then the function could be a projection.
+ */
+ if (length(fargs) == 1)
{
- Expr *expr = (Expr*)first_arg;
- Func *funcnode;
- if (expr->opType != FUNC_EXPR)
- break;
+ if (nodeTag(first_arg) == T_Ident && ((Ident *) first_arg)->isRel)
+ {
+ RangeTblEntry *rte;
+ Ident *ident = (Ident *) first_arg;
+
+ /*
+ * first arg is a relation. This could be a projection.
+ */
+ refname = ident->name;
+
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE, NULL);
+
+ relname = rte->relname;
+ relid = rte->relid;
+
+ /*
+ * If the attr isn't a set, just make a var for it. If it is
+ * a set, treat it like a function and drop through.
+ */
+ if (get_attnum(relid, funcname) != InvalidAttrNumber)
+ {
+ Oid dummyTypeId;
+
+ return
+ ((Node *) make_var(pstate,
+ refname,
+ funcname,
+ &dummyTypeId));
+ }
+ else
+ {
+ /* drop through - attr is a set */
+ ;
+ }
+ }
+ else if (ISCOMPLEX(exprType(first_arg)))
+ {
+
+ /*
+ * Attempt to handle projection of a complex argument. If
+ * ParseComplexProjection can't handle the projection, we have
+ * to keep going.
+ */
+ retval = ParseComplexProjection(pstate,
+ funcname,
+ first_arg,
+ &attisset);
+ if (attisset)
+ {
+ toid = exprType(first_arg);
+ rd = heap_openr(tname(get_id_type(toid)));
+ if (RelationIsValid(rd))
+ {
+ relname = RelationGetRelationName(rd)->data;
+ heap_close(rd);
+ }
+ else
+ elog(WARN,
+ "Type %s is not a relation type",
+ tname(get_id_type(toid)));
+ argrelid = typeid_get_relid(toid);
+
+ /*
+ * A projection contains either an attribute name or the
+ * "*".
+ */
+ if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
+ && strcmp(funcname, "*"))
+ {
+ elog(WARN, "Functions on sets are not yet supported");
+ }
+ }
+
+ if (retval)
+ return retval;
+ }
+ else
+ {
+
+ /*
+ * Parsing aggregates.
+ */
+ Oid basetype;
+
+ /*
+ * the aggregate count is a special case, ignore its base
+ * type. Treat it as zero
+ */
+ if (strcmp(funcname, "count") == 0)
+ basetype = 0;
+ else
+ basetype = exprType(lfirst(fargs));
+ if (SearchSysCacheTuple(AGGNAME,
+ PointerGetDatum(funcname),
+ ObjectIdGetDatum(basetype),
+ 0, 0))
+ {
+ Aggreg *aggreg = ParseAgg(funcname, basetype, lfirst(fargs));
+
+ AddAggToParseState(pstate, aggreg);
+ return (Node *) aggreg;
+ }
+ }
+ }
- funcnode= (Func *) expr->oper;
- argtype = funcid_get_rettype(funcnode->funcid);
- argrelid = typeid_get_relid(argtype);
- /*
- * the argument is a function returning a tuple, so funcname
- * may be a projection
- */
- if (argrelid &&
- (attnum = get_attnum(argrelid, funcname))
- != InvalidAttrNumber) {
-
- /* add a tlist to the func node */
- rd = heap_openr(tname(get_id_type(argtype)));
- if (RelationIsValid(rd)) {
- relid = RelationGetRelationId(rd);
- relname = RelationGetRelationName(rd);
- heap_close(rd);
+
+ /*
+ * * If we dropped through to here it's really a function (or a set,
+ * which * is implemented as a function.) * extract arg type info and
+ * transform relation name arguments into * varnodes of the
+ * appropriate form.
+ */
+ memset(&oid_array[0], 0, 8 * sizeof(Oid));
+
+ nargs = 0;
+ foreach(i, fargs)
+ {
+ int vnum;
+ RangeTblEntry *rte;
+ Node *pair = lfirst(i);
+
+ if (nodeTag(pair) == T_Ident && ((Ident *) pair)->isRel)
+ {
+
+ /*
+ * a relation
+ */
+ refname = ((Ident *) pair)->name;
+
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, refname, refname,
+ FALSE, FALSE, NULL);
+ relname = rte->relname;
+
+ vnum = refnameRangeTablePosn(pstate->p_rtable, rte->refname);
+
+ /*
+ * for func(relname), the param to the function is the tuple
+ * under consideration. we build a special VarNode to reflect
+ * this -- it has varno set to the correct range table entry,
+ * but has varattno == 0 to signal that the whole tuple is the
+ * argument.
+ */
+ toid = typeid(type(relname));
+ /* replace it in the arg list */
+ lfirst(fargs) =
+ makeVar(vnum, 0, toid, vnum, 0);
}
- if (RelationIsValid(rd)) {
- Expr *newexpr;
-
- funcnode->func_tlist =
- setup_tlist(funcname, argrelid);
- funcnode->functype = att_typeid(rd,attnum);
-
- newexpr = makeNode(Expr);
- newexpr->typeOid = funcnode->functype;
- newexpr->opType = FUNC_EXPR;
- newexpr->oper = (Node *)funcnode;
- newexpr->args = lcons(first_arg, NIL);
-
- return ((Node*)newexpr);
+ else if (!attisset)
+ { /* set functions don't have parameters */
+
+ /*
+ * any functiona args which are typed "unknown", but aren't
+ * constants, we don't know what to do with, because we can't
+ * cast them - jolly
+ */
+ if (exprType(pair) == UNKNOWNOID &&
+ !IsA(pair, Const))
+ {
+ elog(WARN, "ParseFunc: no function named %s that takes in an unknown type as argument #%d", funcname, nargs);
+ }
+ else
+ toid = exprType(pair);
}
-
- }
- elog(WARN, "Function %s has bad returntype %d",
- funcname, argtype);
- break;
+ oid_array[nargs++] = toid;
+ }
+
+ /*
+ * func_get_detail looks up the function in the catalogs, does
+ * disambiguation for polymorphic functions, handles inheritance, and
+ * returns the funcid and type and set or singleton status of the
+ * function's return value. it also returns the true argument types
+ * to the function. if func_get_detail returns true, the function
+ * exists. otherwise, there was an error.
+ */
+ if (attisset)
+ { /* we know all of these fields already */
+
+ /*
+ * We create a funcnode with a placeholder function SetEval.
+ * SetEval() never actually gets executed. When the function
+ * evaluation routines see it, they use the funcid projected out
+ * from the relation as the actual function to call. Example:
+ * retrieve (emp.mgr.name) The plan for this will scan the emp
+ * relation, projecting out the mgr attribute, which is a funcid.
+ * This function is then called (instead of SetEval) and "name" is
+ * projected from its result.
+ */
+ funcid = SetEvalRegProcedure;
+ rettype = toid;
+ retset = true;
+ true_oid_array = oid_array;
+ exists = true;
}
- case T_Param:
+ else
{
- Param *param = (Param*)first_arg;
- /*
- * If the Param is a complex type, this could be a projection
- */
- rd = heap_openr(tname(get_id_type(param->paramtype)));
- if (RelationIsValid(rd)) {
- relid = RelationGetRelationId(rd);
- relname = RelationGetRelationName(rd);
- heap_close(rd);
- }
- if (RelationIsValid(rd) &&
- (attnum = get_attnum(relid, funcname))
- != InvalidAttrNumber) {
-
- param->paramtype = att_typeid(rd, attnum);
- param->param_tlist = setup_tlist(funcname, relid);
- return ((Node*)param);
- }
- break;
+ exists = func_get_detail(funcname, nargs, oid_array, &funcid,
+ &rettype, &retset, &true_oid_array);
}
- default:
- break;
- }
- return NULL;
-}
-
-static Node *
-ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
-{
- Oid rettype = (Oid)0;
- Oid argrelid = (Oid)0;
- Oid funcid = (Oid)0;
- List *i = NIL;
- Node *first_arg= NULL;
- char *relname = NULL;
- char *refname = NULL;
- Relation rd;
- Oid relid;
- int nargs;
- Func *funcnode;
- Oid oid_array[8];
- Oid *true_oid_array;
- Node *retval;
- bool retset;
- bool exists;
- bool attisset = false;
- Oid toid = (Oid)0;
- Expr *expr;
-
- if (fargs) {
- first_arg = lfirst(fargs);
- if (first_arg == NULL)
- elog (WARN,"function %s does not allow NULL input",funcname);
- }
-
- /*
- ** check for projection methods: if function takes one argument, and
- ** that argument is a relation, param, or PQ function returning a complex
- ** type, then the function could be a projection.
- */
- if (length(fargs) == 1) {
-
- if (nodeTag(first_arg)==T_Ident && ((Ident*)first_arg)->isRel) {
- RangeTblEntry *rte;
- Ident *ident = (Ident*)first_arg;
-
- /*
- * first arg is a relation. This could be a projection.
- */
- refname = ident->name;
-
- rte = refnameRangeTableEntry(pstate->p_rtable, refname);
- if (rte == NULL)
- rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE,NULL);
-
- relname = rte->relname;
- relid = rte->relid;
-
- /* If the attr isn't a set, just make a var for it. If
- * it is a set, treat it like a function and drop through.
- */
- if (get_attnum(relid, funcname) != InvalidAttrNumber) {
- Oid dummyTypeId;
-
- return
- ((Node*)make_var(pstate,
- refname,
- funcname,
- &dummyTypeId));
- } else {
- /* drop through - attr is a set */
- ;
- }
- } else if (ISCOMPLEX(exprType(first_arg))) {
- /*
- * Attempt to handle projection of a complex argument. If
- * ParseComplexProjection can't handle the projection, we
- * have to keep going.
- */
- retval = ParseComplexProjection(pstate,
- funcname,
- first_arg,
- &attisset);
- if (attisset) {
- toid = exprType(first_arg);
- rd = heap_openr(tname(get_id_type(toid)));
- if (RelationIsValid(rd)) {
- relname = RelationGetRelationName(rd)->data;
- heap_close(rd);
- } else
- elog(WARN,
- "Type %s is not a relation type",
- tname(get_id_type(toid)));
- argrelid = typeid_get_relid(toid);
- /* A projection contains either an attribute name or the
- * "*".
- */
- if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
- && strcmp(funcname, "*")) {
- elog(WARN, "Functions on sets are not yet supported");
+ if (!exists)
+ elog(WARN, "no such attribute or function %s", funcname);
+
+ /* got it */
+ funcnode = makeNode(Func);
+ funcnode->funcid = funcid;
+ funcnode->functype = rettype;
+ funcnode->funcisindex = false;
+ funcnode->funcsize = 0;
+ funcnode->func_fcache = NULL;
+ funcnode->func_tlist = NIL;
+ funcnode->func_planlist = NIL;
+
+ /* perform the necessary typecasting */
+ make_arguments(nargs, fargs, oid_array, true_oid_array);
+
+ /*
+ * for functions returning base types, we want to project out the
+ * return value. set up a target list to do that. the executor will
+ * ignore these for c functions, and do the right thing for postquel
+ * functions.
+ */
+
+ if (typeid_get_relid(rettype) == InvalidOid)
+ funcnode->func_tlist = setup_base_tlist(rettype);
+
+ /*
+ * For sets, we want to make a targetlist to project out this
+ * attribute of the set tuples.
+ */
+ if (attisset)
+ {
+ if (!strcmp(funcname, "*"))
+ {
+ funcnode->func_tlist =
+ expandAll(pstate, relname, refname, curr_resno);
+ }
+ else
+ {
+ funcnode->func_tlist = setup_tlist(funcname, argrelid);
+ rettype = find_atttype(argrelid, funcname);
}
- }
-
- if (retval)
- return retval;
- } else {
- /*
- * Parsing aggregates.
- */
- Oid basetype;
- /* the aggregate count is a special case,
- ignore its base type. Treat it as zero */
- if (strcmp(funcname, "count") == 0)
- basetype = 0;
- else
- basetype = exprType(lfirst(fargs));
- if (SearchSysCacheTuple(AGGNAME,
- PointerGetDatum(funcname),
- ObjectIdGetDatum(basetype),
- 0, 0)) {
- Aggreg *aggreg = ParseAgg(funcname, basetype, lfirst(fargs));
-
- AddAggToParseState(pstate, aggreg);
- return (Node*)aggreg;
- }
}
- }
-
-
- /*
- ** If we dropped through to here it's really a function (or a set, which
- ** is implemented as a function.)
- ** extract arg type info and transform relation name arguments into
- ** varnodes of the appropriate form.
- */
- memset(&oid_array[0], 0, 8 * sizeof(Oid));
-
- nargs=0;
- foreach ( i , fargs ) {
- int vnum;
- RangeTblEntry *rte;
- Node *pair = lfirst(i);
-
- if (nodeTag(pair)==T_Ident && ((Ident*)pair)->isRel) {
- /*
- * a relation
- */
- refname = ((Ident*)pair)->name;
-
- rte = refnameRangeTableEntry(pstate->p_rtable, refname);
- if (rte == NULL)
- rte = addRangeTableEntry(pstate, refname, refname,
- FALSE, FALSE, NULL);
- relname = rte->relname;
-
- vnum = refnameRangeTablePosn (pstate->p_rtable, rte->refname);
-
- /*
- * for func(relname), the param to the function
- * is the tuple under consideration. we build a special
- * VarNode to reflect this -- it has varno set to the
- * correct range table entry, but has varattno == 0 to
- * signal that the whole tuple is the argument.
- */
- toid = typeid(type(relname));
- /* replace it in the arg list */
- lfirst(fargs) =
- makeVar(vnum, 0, toid, vnum, 0);
- }else if (!attisset) { /* set functions don't have parameters */
-
- /* any functiona args which are typed "unknown", but aren't
- constants, we don't know what to do with, because we
- can't cast them - jolly*/
- if (exprType(pair) == UNKNOWNOID &&
- !IsA(pair, Const))
- {
- elog(WARN, "ParseFunc: no function named %s that takes in an unknown type as argument #%d", funcname, nargs);
- }
- else
- toid = exprType(pair);
+
+ /*
+ * Sequence handling.
+ */
+ if (funcid == SeqNextValueRegProcedure ||
+ funcid == SeqCurrValueRegProcedure)
+ {
+ Const *seq;
+ char *seqrel;
+ int32 aclcheck_result = -1;
+
+ Assert(length(fargs) == 1);
+ seq = (Const *) lfirst(fargs);
+ if (!IsA((Node *) seq, Const))
+ elog(WARN, "%s: only constant sequence names are acceptable", funcname);
+ seqrel = textout((struct varlena *) (seq->constvalue));
+
+ if ((aclcheck_result = pg_aclcheck(seqrel, GetPgUserName(),
+ ((funcid == SeqNextValueRegProcedure) ? ACL_WR : ACL_RD)))
+ != ACLCHECK_OK)
+ elog(WARN, "%s.%s: %s",
+ seqrel, funcname, aclcheck_error_strings[aclcheck_result]);
+
+ pfree(seqrel);
+
+ if (funcid == SeqNextValueRegProcedure && inWhereClause)
+ elog(WARN, "nextval of a sequence in WHERE disallowed");
}
-
- oid_array[nargs++] = toid;
- }
-
- /*
- * func_get_detail looks up the function in the catalogs, does
- * disambiguation for polymorphic functions, handles inheritance,
- * and returns the funcid and type and set or singleton status of
- * the function's return value. it also returns the true argument
- * types to the function. if func_get_detail returns true,
- * the function exists. otherwise, there was an error.
- */
- if (attisset) { /* we know all of these fields already */
- /* We create a funcnode with a placeholder function SetEval.
- * SetEval() never actually gets executed. When the function
- * evaluation routines see it, they use the funcid projected
- * out from the relation as the actual function to call.
- * Example: retrieve (emp.mgr.name)
- * The plan for this will scan the emp relation, projecting
- * out the mgr attribute, which is a funcid. This function
- * is then called (instead of SetEval) and "name" is projected
- * from its result.
+
+ expr = makeNode(Expr);
+ expr->typeOid = rettype;
+ expr->opType = FUNC_EXPR;
+ expr->oper = (Node *) funcnode;
+ expr->args = fargs;
+ retval = (Node *) expr;
+
+ /*
+ * if the function returns a set of values, then we need to iterate
+ * over all the returned values in the executor, so we stick an iter
+ * node here. if it returns a singleton, then we don't need the iter
+ * node.
*/
- funcid = SetEvalRegProcedure;
- rettype = toid;
- retset = true;
- true_oid_array = oid_array;
- exists = true;
- } else {
- exists = func_get_detail(funcname, nargs, oid_array, &funcid,
- &rettype, &retset, &true_oid_array);
- }
-
- if (!exists)
- elog(WARN, "no such attribute or function %s", funcname);
-
- /* got it */
- funcnode = makeNode(Func);
- funcnode->funcid = funcid;
- funcnode->functype = rettype;
- funcnode->funcisindex = false;
- funcnode->funcsize = 0;
- funcnode->func_fcache = NULL;
- funcnode->func_tlist = NIL;
- funcnode->func_planlist = NIL;
-
- /* perform the necessary typecasting */
- make_arguments(nargs, fargs, oid_array, true_oid_array);
-
- /*
- * for functions returning base types, we want to project out the
- * return value. set up a target list to do that. the executor
- * will ignore these for c functions, and do the right thing for
- * postquel functions.
- */
-
- if (typeid_get_relid(rettype) == InvalidOid)
- funcnode->func_tlist = setup_base_tlist(rettype);
-
- /* For sets, we want to make a targetlist to project out this
- * attribute of the set tuples.
- */
- if (attisset) {
- if (!strcmp(funcname, "*")) {
- funcnode->func_tlist =
- expandAll(pstate, relname, refname, curr_resno);
- } else {
- funcnode->func_tlist = setup_tlist(funcname,argrelid);
- rettype = find_atttype(argrelid, funcname);
+
+ if (retset)
+ {
+ Iter *iter = makeNode(Iter);
+
+ iter->itertype = rettype;
+ iter->iterexpr = retval;
+ retval = (Node *) iter;
}
- }
-
- /*
- * Sequence handling.
- */
- if ( funcid == SeqNextValueRegProcedure ||
- funcid == SeqCurrValueRegProcedure )
- {
- Const *seq;
- char *seqrel;
- int32 aclcheck_result = -1;
-
- Assert ( length(fargs) == 1 );
- seq = (Const*)lfirst(fargs);
- if ( ! IsA ((Node*)seq, Const) )
- elog (WARN, "%s: only constant sequence names are acceptable", funcname);
- seqrel = textout ((struct varlena *) (seq->constvalue));
-
- if ( ( aclcheck_result = pg_aclcheck (seqrel, GetPgUserName(),
- ((funcid == SeqNextValueRegProcedure) ? ACL_WR : ACL_RD)) )
- != ACLCHECK_OK )
- elog (WARN, "%s.%s: %s",
- seqrel, funcname, aclcheck_error_strings[aclcheck_result]);
-
- pfree (seqrel);
-
- if ( funcid == SeqNextValueRegProcedure && inWhereClause )
- elog (WARN, "nextval of a sequence in WHERE disallowed");
- }
-
- expr = makeNode(Expr);
- expr->typeOid = rettype;
- expr->opType = FUNC_EXPR;
- expr->oper = (Node *)funcnode;
- expr->args = fargs;
- retval = (Node*)expr;
-
- /*
- * if the function returns a set of values, then we need to iterate
- * over all the returned values in the executor, so we stick an
- * iter node here. if it returns a singleton, then we don't need
- * the iter node.
- */
-
- if (retset) {
- Iter *iter = makeNode(Iter);
- iter->itertype = rettype;
- iter->iterexpr = retval;
- retval = (Node*)iter;
- }
-
- return(retval);
+
+ return (retval);
}
/*****************************************************************************
@@ -2262,232 +2511,243 @@ ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
/*
* AddAggToParseState -
- * add the aggregate to the list of unique aggregates in pstate.
+ * add the aggregate to the list of unique aggregates in pstate.
*
* SIDE EFFECT: aggno in target list entry will be modified
*/
static void
-AddAggToParseState(ParseState *pstate, Aggreg *aggreg)
+AddAggToParseState(ParseState * pstate, Aggreg * aggreg)
{
- List *ag;
- int i;
-
- /*
- * see if we have the aggregate already (we only need to record
- * the aggregate once)
- */
- i = 0;
- foreach(ag, pstate->p_aggs) {
- Aggreg *a = lfirst(ag);
-
- if (!strcmp(a->aggname, aggreg->aggname) &&
- equal(a->target, aggreg->target)) {
-
- /* fill in the aggno and we're done */
- aggreg->aggno = i;
- return;
+ List *ag;
+ int i;
+
+ /*
+ * see if we have the aggregate already (we only need to record the
+ * aggregate once)
+ */
+ i = 0;
+ foreach(ag, pstate->p_aggs)
+ {
+ Aggreg *a = lfirst(ag);
+
+ if (!strcmp(a->aggname, aggreg->aggname) &&
+ equal(a->target, aggreg->target))
+ {
+
+ /* fill in the aggno and we're done */
+ aggreg->aggno = i;
+ return;
+ }
+ i++;
}
- i++;
- }
-
- /* not found, new aggregate */
- aggreg->aggno = i;
- pstate->p_numAgg++;
- pstate->p_aggs = lappend(pstate->p_aggs, aggreg);
- return;
+
+ /* not found, new aggregate */
+ aggreg->aggno = i;
+ pstate->p_numAgg++;
+ pstate->p_aggs = lappend(pstate->p_aggs, aggreg);
+ return;
}
/*
* finalizeAggregates -
- * fill in qry_aggs from pstate. Also checks to make sure that aggregates
- * are used in the proper place.
+ * fill in qry_aggs from pstate. Also checks to make sure that aggregates
+ * are used in the proper place.
*/
static void
-finalizeAggregates(ParseState *pstate, Query *qry)
-{
- List *l;
- int i;
-
- parseCheckAggregates(pstate, qry);
-
- qry->qry_numAgg = pstate->p_numAgg;
- qry->qry_aggs =
- (Aggreg **)palloc(sizeof(Aggreg *) * qry->qry_numAgg);
- i = 0;
- foreach(l, pstate->p_aggs)
- qry->qry_aggs[i++] = (Aggreg*)lfirst(l);
+finalizeAggregates(ParseState * pstate, Query * qry)
+{
+ List *l;
+ int i;
+
+ parseCheckAggregates(pstate, qry);
+
+ qry->qry_numAgg = pstate->p_numAgg;
+ qry->qry_aggs =
+ (Aggreg **) palloc(sizeof(Aggreg *) * qry->qry_numAgg);
+ i = 0;
+ foreach(l, pstate->p_aggs)
+ qry->qry_aggs[i++] = (Aggreg *) lfirst(l);
}
-/*
+/*
* contain_agg_clause--
- * Recursively find aggreg nodes from a clause.
- *
- * Returns true if any aggregate found.
+ * Recursively find aggreg nodes from a clause.
+ *
+ * Returns true if any aggregate found.
*/
-static bool
-contain_agg_clause(Node *clause)
+static bool
+contain_agg_clause(Node * clause)
{
- if (clause==NULL)
- return FALSE;
- else if (IsA(clause,Aggreg))
- return TRUE;
- else if (IsA(clause,Iter))
- return contain_agg_clause(((Iter*)clause)->iterexpr);
- else if (single_node(clause))
- return FALSE;
- else if (or_clause(clause)) {
- List *temp;
-
- foreach (temp, ((Expr*)clause)->args)
- if (contain_agg_clause(lfirst(temp)))
+ if (clause == NULL)
+ return FALSE;
+ else if (IsA(clause, Aggreg))
return TRUE;
- return FALSE;
- } else if (is_funcclause (clause)) {
- List *temp;
+ else if (IsA(clause, Iter))
+ return contain_agg_clause(((Iter *) clause)->iterexpr);
+ else if (single_node(clause))
+ return FALSE;
+ else if (or_clause(clause))
+ {
+ List *temp;
- foreach(temp, ((Expr *)clause)->args)
- if (contain_agg_clause(lfirst(temp)))
- return TRUE;
- return FALSE;
- } else if (IsA(clause,ArrayRef)) {
- List *temp;
+ foreach(temp, ((Expr *) clause)->args)
+ if (contain_agg_clause(lfirst(temp)))
+ return TRUE;
+ return FALSE;
+ }
+ else if (is_funcclause(clause))
+ {
+ List *temp;
- foreach(temp, ((ArrayRef*)clause)->refupperindexpr)
- if (contain_agg_clause(lfirst(temp)))
- return TRUE;
- foreach(temp, ((ArrayRef*)clause)->reflowerindexpr)
- if (contain_agg_clause(lfirst(temp)))
- return TRUE;
- if (contain_agg_clause(((ArrayRef*)clause)->refexpr))
- return TRUE;
- if (contain_agg_clause(((ArrayRef*)clause)->refassgnexpr))
- return TRUE;
- return FALSE;
- } else if (not_clause(clause))
- return contain_agg_clause((Node*)get_notclausearg((Expr*)clause));
- else if (is_opclause(clause))
- return (contain_agg_clause((Node*)get_leftop((Expr*)clause)) ||
- contain_agg_clause((Node*)get_rightop((Expr*)clause)));
+ foreach(temp, ((Expr *) clause)->args)
+ if (contain_agg_clause(lfirst(temp)))
+ return TRUE;
+ return FALSE;
+ }
+ else if (IsA(clause, ArrayRef))
+ {
+ List *temp;
+
+ foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
+ if (contain_agg_clause(lfirst(temp)))
+ return TRUE;
+ foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
+ if (contain_agg_clause(lfirst(temp)))
+ return TRUE;
+ if (contain_agg_clause(((ArrayRef *) clause)->refexpr))
+ return TRUE;
+ if (contain_agg_clause(((ArrayRef *) clause)->refassgnexpr))
+ return TRUE;
+ return FALSE;
+ }
+ else if (not_clause(clause))
+ return contain_agg_clause((Node *) get_notclausearg((Expr *) clause));
+ else if (is_opclause(clause))
+ return (contain_agg_clause((Node *) get_leftop((Expr *) clause)) ||
+ contain_agg_clause((Node *) get_rightop((Expr *) clause)));
- return FALSE;
+ return FALSE;
}
/*
* exprIsAggOrGroupCol -
- * returns true if the expression does not contain non-group columns.
+ * returns true if the expression does not contain non-group columns.
*/
-static bool
-exprIsAggOrGroupCol(Node *expr, List *groupClause)
+static bool
+exprIsAggOrGroupCol(Node * expr, List * groupClause)
{
- List *gl;
-
- if ( expr == NULL || IsA (expr, Const) ||
- IsA (expr, Param) || IsA (expr, Aggreg) )
- return TRUE;
-
- foreach (gl, groupClause)
- {
- GroupClause *grpcl = lfirst(gl);
-
- if ( equal (expr, grpcl->entry->expr) )
+ List *gl;
+
+ if (expr == NULL || IsA(expr, Const) ||
+ IsA(expr, Param) || IsA(expr, Aggreg))
return TRUE;
- }
- if ( IsA (expr, Expr) )
- {
- List *temp;
+ foreach(gl, groupClause)
+ {
+ GroupClause *grpcl = lfirst(gl);
- foreach (temp, ((Expr*)expr)->args)
- if (!exprIsAggOrGroupCol(lfirst(temp),groupClause))
- return FALSE;
- return TRUE;
- }
+ if (equal(expr, grpcl->entry->expr))
+ return TRUE;
+ }
+
+ if (IsA(expr, Expr))
+ {
+ List *temp;
+
+ foreach(temp, ((Expr *) expr)->args)
+ if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
+ return FALSE;
+ return TRUE;
+ }
- return FALSE;
+ return FALSE;
}
/*
* tleIsAggOrGroupCol -
- * returns true if the TargetEntry is Agg or GroupCol.
+ * returns true if the TargetEntry is Agg or GroupCol.
*/
-static bool
-tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause)
+static bool
+tleIsAggOrGroupCol(TargetEntry * tle, List * groupClause)
{
- Node *expr = tle->expr;
- List *gl;
-
- if ( expr == NULL || IsA (expr, Const) || IsA (expr, Param) )
- return TRUE;
-
- foreach (gl, groupClause)
- {
- GroupClause *grpcl = lfirst(gl);
-
- if ( tle->resdom->resno == grpcl->entry->resdom->resno )
- {
- if ( contain_agg_clause ((Node*) expr) )
- elog (WARN, "parser: aggregates not allowed in GROUP BY clause");
- return TRUE;
+ Node *expr = tle->expr;
+ List *gl;
+
+ if (expr == NULL || IsA(expr, Const) || IsA(expr, Param))
+ return TRUE;
+
+ foreach(gl, groupClause)
+ {
+ GroupClause *grpcl = lfirst(gl);
+
+ if (tle->resdom->resno == grpcl->entry->resdom->resno)
+ {
+ if (contain_agg_clause((Node *) expr))
+ elog(WARN, "parser: aggregates not allowed in GROUP BY clause");
+ return TRUE;
+ }
}
- }
- if ( IsA (expr, Aggreg) )
- return TRUE;
+ if (IsA(expr, Aggreg))
+ return TRUE;
- if ( IsA (expr, Expr) )
- {
- List *temp;
+ if (IsA(expr, Expr))
+ {
+ List *temp;
- foreach (temp, ((Expr*)expr)->args)
- if (!exprIsAggOrGroupCol(lfirst(temp),groupClause))
- return FALSE;
- return TRUE;
- }
+ foreach(temp, ((Expr *) expr)->args)
+ if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
+ return FALSE;
+ return TRUE;
+ }
- return FALSE;
+ return FALSE;
}
/*
* parseCheckAggregates -
- * this should really be done earlier but the current grammar
- * cannot differentiate functions from aggregates. So we have do check
- * here when the target list and the qualifications are finalized.
+ * this should really be done earlier but the current grammar
+ * cannot differentiate functions from aggregates. So we have do check
+ * here when the target list and the qualifications are finalized.
*/
static void
-parseCheckAggregates(ParseState *pstate, Query *qry)
+parseCheckAggregates(ParseState * pstate, Query * qry)
{
- List *tl;
- Assert(pstate->p_numAgg > 0);
-
- /*
- * aggregates never appear in WHERE clauses. (we have to check where
- * clause first because if there is an aggregate, the check for
- * non-group column in target list may fail.)
- */
- if (contain_agg_clause(qry->qual))
- elog(WARN, "parser: aggregates not allowed in WHERE clause");
-
- /*
- * the target list can only contain aggregates, group columns and
- * functions thereof.
- */
- foreach (tl, qry->targetList) {
- TargetEntry *tle = lfirst(tl);
- if (!tleIsAggOrGroupCol(tle, qry->groupClause))
- elog(WARN,
- "parser: illegal use of aggregates or non-group column in target list");
- }
-
- /*
- * the expression specified in the HAVING clause has the same restriction
- * as those in the target list.
- */
+ List *tl;
+
+ Assert(pstate->p_numAgg > 0);
+
+ /*
+ * aggregates never appear in WHERE clauses. (we have to check where
+ * clause first because if there is an aggregate, the check for
+ * non-group column in target list may fail.)
+ */
+ if (contain_agg_clause(qry->qual))
+ elog(WARN, "parser: aggregates not allowed in WHERE clause");
+
+ /*
+ * the target list can only contain aggregates, group columns and
+ * functions thereof.
+ */
+ foreach(tl, qry->targetList)
+ {
+ TargetEntry *tle = lfirst(tl);
+
+ if (!tleIsAggOrGroupCol(tle, qry->groupClause))
+ elog(WARN,
+ "parser: illegal use of aggregates or non-group column in target list");
+ }
+
+ /*
+ * the expression specified in the HAVING clause has the same
+ * restriction as those in the target list.
+ */
/*
- * Need to change here when we get HAVING works. Currently
- * qry->havingQual is NULL. - vadim 04/05/97
- if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
- elog(WARN,
- "parser: illegal use of aggregates or non-group column in HAVING clause");
- */
- return;
+ * Need to change here when we get HAVING works. Currently
+ * qry->havingQual is NULL. - vadim 04/05/97
+ if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
+ elog(WARN,
+ "parser: illegal use of aggregates or non-group column in HAVING clause");
+ */
+ return;
}
diff --git a/src/backend/parser/catalog_utils.c b/src/backend/parser/catalog_utils.c
index 043c2865060..41e6fffac9b 100644
--- a/src/backend/parser/catalog_utils.c
+++ b/src/backend/parser/catalog_utils.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.22 1997/08/22 00:02:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.23 1997/09/07 04:44:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -48,83 +48,110 @@
#include "utils/lsyscache.h"
#include "storage/lmgr.h"
-#include "port-protos.h" /* strdup() */
-
-struct {
- char *field;
- int code;
-} special_attr[] = {
- { "ctid", SelfItemPointerAttributeNumber },
- { "oid", ObjectIdAttributeNumber },
- { "xmin", MinTransactionIdAttributeNumber },
- { "cmin", MinCommandIdAttributeNumber },
- { "xmax", MaxTransactionIdAttributeNumber },
- { "cmax", MaxCommandIdAttributeNumber },
- { "chain", ChainItemPointerAttributeNumber },
- { "anchor", AnchorItemPointerAttributeNumber },
- { "tmin", MinAbsoluteTimeAttributeNumber },
- { "tmax", MaxAbsoluteTimeAttributeNumber },
- { "vtype", VersionTypeAttributeNumber }
+#include "port-protos.h" /* strdup() */
+
+struct
+{
+ char *field;
+ int code;
+} special_attr[] =
+
+{
+ {
+ "ctid", SelfItemPointerAttributeNumber
+ },
+ {
+ "oid", ObjectIdAttributeNumber
+ },
+ {
+ "xmin", MinTransactionIdAttributeNumber
+ },
+ {
+ "cmin", MinCommandIdAttributeNumber
+ },
+ {
+ "xmax", MaxTransactionIdAttributeNumber
+ },
+ {
+ "cmax", MaxCommandIdAttributeNumber
+ },
+ {
+ "chain", ChainItemPointerAttributeNumber
+ },
+ {
+ "anchor", AnchorItemPointerAttributeNumber
+ },
+ {
+ "tmin", MinAbsoluteTimeAttributeNumber
+ },
+ {
+ "tmax", MaxAbsoluteTimeAttributeNumber
+ },
+ {
+ "vtype", VersionTypeAttributeNumber
+ }
};
#define SPECIALS (sizeof(special_attr)/sizeof(*special_attr))
-
-static char *attnum_type[SPECIALS] = {
- "tid",
- "oid",
- "xid",
- "cid",
- "xid",
- "cid",
- "tid",
- "tid",
- "abstime",
- "abstime",
- "char"
- };
-
-#define MAXFARGS 8 /* max # args to a c or postquel function */
+
+static char *attnum_type[SPECIALS] = {
+ "tid",
+ "oid",
+ "xid",
+ "cid",
+ "xid",
+ "cid",
+ "tid",
+ "tid",
+ "abstime",
+ "abstime",
+ "char"
+};
+
+#define MAXFARGS 8 /* max # args to a c or postquel function */
/*
- * This structure is used to explore the inheritance hierarchy above
- * nodes in the type tree in order to disambiguate among polymorphic
- * functions.
+ * This structure is used to explore the inheritance hierarchy above
+ * nodes in the type tree in order to disambiguate among polymorphic
+ * functions.
*/
-typedef struct _InhPaths {
- int nsupers; /* number of superclasses */
- Oid self; /* this class */
- Oid *supervec; /* vector of superclasses */
-} InhPaths;
+typedef struct _InhPaths
+{
+ int nsupers; /* number of superclasses */
+ Oid self; /* this class */
+ Oid *supervec; /* vector of superclasses */
+} InhPaths;
/*
- * This structure holds a list of possible functions or operators that
- * agree with the known name and argument types of the function/operator.
+ * This structure holds a list of possible functions or operators that
+ * agree with the known name and argument types of the function/operator.
*/
-typedef struct _CandidateList {
- Oid *args;
- struct _CandidateList *next;
-} *CandidateList;
-
-static Oid **argtype_inherit(int nargs, Oid *oid_array);
-static Oid **genxprod(InhPaths *arginh, int nargs);
-static int findsupers(Oid relid, Oid **supervec);
-static bool check_typeid(Oid id);
-static char *instr1(TypeTupleForm tp, char *string, int typlen);
-static void op_error(char *op, Oid arg1, Oid arg2);
+typedef struct _CandidateList
+{
+ Oid *args;
+ struct _CandidateList *next;
+} *CandidateList;
+
+static Oid **argtype_inherit(int nargs, Oid * oid_array);
+static Oid **genxprod(InhPaths * arginh, int nargs);
+static int findsupers(Oid relid, Oid ** supervec);
+static bool check_typeid(Oid id);
+static char *instr1(TypeTupleForm tp, char *string, int typlen);
+static void op_error(char *op, Oid arg1, Oid arg2);
/* check to see if a type id is valid,
- * returns true if it is. By using this call before calling
+ * returns true if it is. By using this call before calling
* get_id_type or get_id_typname, more meaningful error messages
* can be produced because the caller typically has more context of
- * what's going on - jolly
+ * what's going on - jolly
*/
-static bool
+static bool
check_typeid(Oid id)
{
- return (SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(id),
- 0,0,0) != NULL);
+ return (SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(id),
+ 0, 0, 0) != NULL);
}
@@ -132,46 +159,50 @@ check_typeid(Oid id)
Type
get_id_type(Oid id)
{
- HeapTuple tup;
-
- if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
- 0,0,0))) {
- elog ( WARN, "type id lookup of %ud failed", id);
- return(NULL);
- }
- return((Type) tup);
+ HeapTuple tup;
+
+ if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
+ 0, 0, 0)))
+ {
+ elog(WARN, "type id lookup of %ud failed", id);
+ return (NULL);
+ }
+ return ((Type) tup);
}
/* return a type name, given a typeid */
-char*
+char *
get_id_typname(Oid id)
{
- HeapTuple tup;
- TypeTupleForm typetuple;
-
- if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
- 0,0,0))) {
- elog ( WARN, "type id lookup of %ud failed", id);
- return(NULL);
- }
- typetuple = (TypeTupleForm)GETSTRUCT(tup);
- return (typetuple->typname).data;
+ HeapTuple tup;
+ TypeTupleForm typetuple;
+
+ if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id),
+ 0, 0, 0)))
+ {
+ elog(WARN, "type id lookup of %ud failed", id);
+ return (NULL);
+ }
+ typetuple = (TypeTupleForm) GETSTRUCT(tup);
+ return (typetuple->typname).data;
}
/* return a Type structure, given type name */
Type
type(char *s)
{
- HeapTuple tup;
-
- if (s == NULL) {
- elog ( WARN , "type(): Null type" );
- }
-
- if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0,0,0))) {
- elog (WARN , "type name lookup of %s failed", s);
- }
- return((Type) tup);
+ HeapTuple tup;
+
+ if (s == NULL)
+ {
+ elog(WARN, "type(): Null type");
+ }
+
+ if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0, 0, 0)))
+ {
+ elog(WARN, "type name lookup of %s failed", s);
+ }
+ return ((Type) tup);
}
/* given attribute id, return type of that attribute */
@@ -179,297 +210,327 @@ type(char *s)
Oid
att_typeid(Relation rd, int attid)
{
-
- if (attid < 0) {
- return(typeid(type(attnum_type[-attid-1])));
- }
- /* -1 because varattno (where attid comes from) returns one
- more than index */
- return(rd->rd_att->attrs[attid-1]->atttypid);
+
+ if (attid < 0)
+ {
+ return (typeid(type(attnum_type[-attid - 1])));
+ }
+
+ /*
+ * -1 because varattno (where attid comes from) returns one more than
+ * index
+ */
+ return (rd->rd_att->attrs[attid - 1]->atttypid);
}
int
att_attnelems(Relation rd, int attid)
{
- return(rd->rd_att->attrs[attid-1]->attnelems);
+ return (rd->rd_att->attrs[attid - 1]->attnelems);
}
/* given type, return the type OID */
Oid
typeid(Type tp)
{
- if (tp == NULL) {
- elog ( WARN , "typeid() called with NULL type struct");
- }
- return(tp->t_oid);
+ if (tp == NULL)
+ {
+ elog(WARN, "typeid() called with NULL type struct");
+ }
+ return (tp->t_oid);
}
/* given type (as type struct), return the length of type */
int16
tlen(Type t)
{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm)GETSTRUCT(t);
- return(typ->typlen);
+ TypeTupleForm typ;
+
+ typ = (TypeTupleForm) GETSTRUCT(t);
+ return (typ->typlen);
}
/* given type (as type struct), return the value of its 'byval' attribute.*/
bool
tbyval(Type t)
{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm)GETSTRUCT(t);
- return(typ->typbyval);
+ TypeTupleForm typ;
+
+ typ = (TypeTupleForm) GETSTRUCT(t);
+ return (typ->typbyval);
}
/* given type (as type struct), return the name of type */
-char*
+char *
tname(Type t)
{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm)GETSTRUCT(t);
- return (typ->typname).data;
+ TypeTupleForm typ;
+
+ typ = (TypeTupleForm) GETSTRUCT(t);
+ return (typ->typname).data;
}
/* given type (as type struct), return wether type is passed by value */
int
tbyvalue(Type t)
{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm) GETSTRUCT(t);
- return(typ->typbyval);
+ TypeTupleForm typ;
+
+ typ = (TypeTupleForm) GETSTRUCT(t);
+ return (typ->typbyval);
}
/* given a type, return its typetype ('c' for 'c'atalog types) */
static char
typetypetype(Type t)
{
- TypeTupleForm typ;
-
- typ = (TypeTupleForm) GETSTRUCT(t);
- return(typ->typtype);
+ TypeTupleForm typ;
+
+ typ = (TypeTupleForm) GETSTRUCT(t);
+ return (typ->typtype);
}
/* given operator, return the operator OID */
Oid
oprid(Operator op)
{
- return(op->t_oid);
+ return (op->t_oid);
}
/*
- * given opname, leftTypeId and rightTypeId,
- * find all possible (arg1, arg2) pairs for which an operator named
- * opname exists, such that leftTypeId can be coerced to arg1 and
- * rightTypeId can be coerced to arg2
+ * given opname, leftTypeId and rightTypeId,
+ * find all possible (arg1, arg2) pairs for which an operator named
+ * opname exists, such that leftTypeId can be coerced to arg1 and
+ * rightTypeId can be coerced to arg2
*/
static int
binary_oper_get_candidates(char *opname,
- Oid leftTypeId,
- Oid rightTypeId,
- CandidateList *candidates)
+ Oid leftTypeId,
+ Oid rightTypeId,
+ CandidateList * candidates)
{
- CandidateList current_candidate;
- Relation pg_operator_desc;
- HeapScanDesc pg_operator_scan;
- HeapTuple tup;
- OperatorTupleForm oper;
- Buffer buffer;
- int nkeys;
- int ncandidates = 0;
- ScanKeyData opKey[3];
-
- *candidates = NULL;
-
- ScanKeyEntryInitialize(&opKey[0], 0,
- Anum_pg_operator_oprname,
- NameEqualRegProcedure,
- NameGetDatum(opname));
-
- ScanKeyEntryInitialize(&opKey[1], 0,
- Anum_pg_operator_oprkind,
- CharacterEqualRegProcedure,
- CharGetDatum('b'));
-
-
- if (leftTypeId == UNKNOWNOID) {
- if (rightTypeId == UNKNOWNOID) {
- nkeys = 2;
- } else {
- nkeys = 3;
-
- ScanKeyEntryInitialize(&opKey[2], 0,
- Anum_pg_operator_oprright,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(rightTypeId));
- }
- } else if (rightTypeId == UNKNOWNOID) {
- nkeys = 3;
-
- ScanKeyEntryInitialize(&opKey[2], 0,
- Anum_pg_operator_oprleft,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(leftTypeId));
- } else {
- /* currently only "unknown" can be coerced */
- return 0;
- }
-
- pg_operator_desc = heap_openr(OperatorRelationName);
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- SelfTimeQual,
- nkeys,
- opKey);
-
- do {
- tup = heap_getnext(pg_operator_scan, 0, &buffer);
- if (HeapTupleIsValid(tup)) {
- current_candidate = (CandidateList)palloc(sizeof(struct _CandidateList));
- current_candidate->args = (Oid *)palloc(2 * sizeof(Oid));
-
- oper = (OperatorTupleForm)GETSTRUCT(tup);
- current_candidate->args[0] = oper->oprleft;
- current_candidate->args[1] = oper->oprright;
- current_candidate->next = *candidates;
- *candidates = current_candidate;
- ncandidates++;
- ReleaseBuffer(buffer);
+ CandidateList current_candidate;
+ Relation pg_operator_desc;
+ HeapScanDesc pg_operator_scan;
+ HeapTuple tup;
+ OperatorTupleForm oper;
+ Buffer buffer;
+ int nkeys;
+ int ncandidates = 0;
+ ScanKeyData opKey[3];
+
+ *candidates = NULL;
+
+ ScanKeyEntryInitialize(&opKey[0], 0,
+ Anum_pg_operator_oprname,
+ NameEqualRegProcedure,
+ NameGetDatum(opname));
+
+ ScanKeyEntryInitialize(&opKey[1], 0,
+ Anum_pg_operator_oprkind,
+ CharacterEqualRegProcedure,
+ CharGetDatum('b'));
+
+
+ if (leftTypeId == UNKNOWNOID)
+ {
+ if (rightTypeId == UNKNOWNOID)
+ {
+ nkeys = 2;
+ }
+ else
+ {
+ nkeys = 3;
+
+ ScanKeyEntryInitialize(&opKey[2], 0,
+ Anum_pg_operator_oprright,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(rightTypeId));
+ }
+ }
+ else if (rightTypeId == UNKNOWNOID)
+ {
+ nkeys = 3;
+
+ ScanKeyEntryInitialize(&opKey[2], 0,
+ Anum_pg_operator_oprleft,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(leftTypeId));
}
- } while(HeapTupleIsValid(tup));
-
- heap_endscan(pg_operator_scan);
- heap_close(pg_operator_desc);
-
- return ncandidates;
+ else
+ {
+ /* currently only "unknown" can be coerced */
+ return 0;
+ }
+
+ pg_operator_desc = heap_openr(OperatorRelationName);
+ pg_operator_scan = heap_beginscan(pg_operator_desc,
+ 0,
+ SelfTimeQual,
+ nkeys,
+ opKey);
+
+ do
+ {
+ tup = heap_getnext(pg_operator_scan, 0, &buffer);
+ if (HeapTupleIsValid(tup))
+ {
+ current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
+ current_candidate->args = (Oid *) palloc(2 * sizeof(Oid));
+
+ oper = (OperatorTupleForm) GETSTRUCT(tup);
+ current_candidate->args[0] = oper->oprleft;
+ current_candidate->args[1] = oper->oprright;
+ current_candidate->next = *candidates;
+ *candidates = current_candidate;
+ ncandidates++;
+ ReleaseBuffer(buffer);
+ }
+ } while (HeapTupleIsValid(tup));
+
+ heap_endscan(pg_operator_scan);
+ heap_close(pg_operator_desc);
+
+ return ncandidates;
}
/*
* equivalentOpersAfterPromotion -
- * checks if a list of candidate operators obtained from
- * binary_oper_get_candidates() contain equivalent operators. If
- * this routine is called, we have more than 1 candidate and need to
- * decided whether to pick one of them. This routine returns true if
- * the all the candidates operate on the same data types after
- * promotion (int2, int4, float4 -> float8).
+ * checks if a list of candidate operators obtained from
+ * binary_oper_get_candidates() contain equivalent operators. If
+ * this routine is called, we have more than 1 candidate and need to
+ * decided whether to pick one of them. This routine returns true if
+ * the all the candidates operate on the same data types after
+ * promotion (int2, int4, float4 -> float8).
*/
-static bool
+static bool
equivalentOpersAfterPromotion(CandidateList candidates)
{
- CandidateList result;
- CandidateList promotedCandidates = NULL;
- Oid leftarg, rightarg;
-
- for (result = candidates; result != NULL; result = result->next) {
- CandidateList c;
- c = (CandidateList)palloc(sizeof(*c));
- c->args = (Oid *)palloc(2 * sizeof(Oid));
- switch (result->args[0]) {
- case FLOAT4OID:
- case INT4OID:
- case INT2OID:
- case CASHOID:
- c->args[0] = FLOAT8OID;
- break;
- default:
- c->args[0] = result->args[0];
- break;
+ CandidateList result;
+ CandidateList promotedCandidates = NULL;
+ Oid leftarg,
+ rightarg;
+
+ for (result = candidates; result != NULL; result = result->next)
+ {
+ CandidateList c;
+
+ c = (CandidateList) palloc(sizeof(*c));
+ c->args = (Oid *) palloc(2 * sizeof(Oid));
+ switch (result->args[0])
+ {
+ case FLOAT4OID:
+ case INT4OID:
+ case INT2OID:
+ case CASHOID:
+ c->args[0] = FLOAT8OID;
+ break;
+ default:
+ c->args[0] = result->args[0];
+ break;
+ }
+ switch (result->args[1])
+ {
+ case FLOAT4OID:
+ case INT4OID:
+ case INT2OID:
+ case CASHOID:
+ c->args[1] = FLOAT8OID;
+ break;
+ default:
+ c->args[1] = result->args[1];
+ break;
+ }
+ c->next = promotedCandidates;
+ promotedCandidates = c;
}
- switch (result->args[1]) {
- case FLOAT4OID:
- case INT4OID:
- case INT2OID:
- case CASHOID:
- c->args[1] = FLOAT8OID;
- break;
- default:
- c->args[1] = result->args[1];
- break;
+
+ /*
+ * if we get called, we have more than 1 candidates so we can do the
+ * following safely
+ */
+ leftarg = promotedCandidates->args[0];
+ rightarg = promotedCandidates->args[1];
+
+ for (result = promotedCandidates->next; result != NULL; result = result->next)
+ {
+ if (result->args[0] != leftarg || result->args[1] != rightarg)
+
+ /*
+ * this list contains operators that operate on different data
+ * types even after promotion. Hence we can't decide on which
+ * one to pick. The user must do explicit type casting.
+ */
+ return FALSE;
}
- c->next = promotedCandidates;
- promotedCandidates = c;
- }
-
- /* if we get called, we have more than 1 candidates so we can do the
- following safely */
- leftarg = promotedCandidates->args[0];
- rightarg = promotedCandidates->args[1];
-
- for (result=promotedCandidates->next; result!=NULL; result=result->next) {
- if (result->args[0]!=leftarg || result->args[1]!=rightarg)
- /*
- * this list contains operators that operate on different
- * data types even after promotion. Hence we can't decide on
- * which one to pick. The user must do explicit type casting.
- */
- return FALSE;
- }
-
- /* all the candidates are equivalent in the following sense: they operate
- on equivalent data types and picking any one of them is as good. */
- return TRUE;
+
+ /*
+ * all the candidates are equivalent in the following sense: they
+ * operate on equivalent data types and picking any one of them is as
+ * good.
+ */
+ return TRUE;
}
-
+
/*
- * given a choice of argument type pairs for a binary operator,
- * try to choose a default pair
+ * given a choice of argument type pairs for a binary operator,
+ * try to choose a default pair
*/
-static CandidateList
+static CandidateList
binary_oper_select_candidate(Oid arg1,
- Oid arg2,
- CandidateList candidates)
+ Oid arg2,
+ CandidateList candidates)
{
- CandidateList result;
-
- /*
- * if both are "unknown", there is no way to select a candidate
- *
- * current wisdom holds that the default operator should be one
- * in which both operands have the same type (there will only
- * be one such operator)
- *
- * 7.27.93 - I have decided not to do this; it's too hard to
- * justify, and it's easy enough to typecast explicitly -avi
- * [the rest of this routine were commented out since then -ay]
- */
-
- if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID)
- return (NULL);
+ CandidateList result;
+
+ /*
+ * if both are "unknown", there is no way to select a candidate
+ *
+ * current wisdom holds that the default operator should be one in which
+ * both operands have the same type (there will only be one such
+ * operator)
+ *
+ * 7.27.93 - I have decided not to do this; it's too hard to justify, and
+ * it's easy enough to typecast explicitly -avi [the rest of this
+ * routine were commented out since then -ay]
+ */
+
+ if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID)
+ return (NULL);
+
+ /*
+ * 6/23/95 - I don't complete agree with avi. In particular, casting
+ * floats is a pain for users. Whatever the rationale behind not doing
+ * this is, I need the following special case to work.
+ *
+ * In the WHERE clause of a query, if a float is specified without
+ * quotes, we treat it as float8. I added the float48* operators so
+ * that we can operate on float4 and float8. But now we have more than
+ * one matching operator if the right arg is unknown (eg. float
+ * specified with quotes). This break some stuff in the regression
+ * test where there are floats in quotes not properly casted. Below is
+ * the solution. In addition to requiring the operator operates on the
+ * same type for both operands [as in the code Avi originally
+ * commented out], we also require that the operators be equivalent in
+ * some sense. (see equivalentOpersAfterPromotion for details.) - ay
+ * 6/95
+ */
+ if (!equivalentOpersAfterPromotion(candidates))
+ return NULL;
+
+ /*
+ * if we get here, any one will do but we're more picky and require
+ * both operands be the same.
+ */
+ for (result = candidates; result != NULL; result = result->next)
+ {
+ if (result->args[0] == result->args[1])
+ return result;
+ }
- /*
- * 6/23/95 - I don't complete agree with avi. In particular, casting
- * floats is a pain for users. Whatever the rationale behind not doing
- * this is, I need the following special case to work.
- *
- * In the WHERE clause of a query, if a float is specified without
- * quotes, we treat it as float8. I added the float48* operators so
- * that we can operate on float4 and float8. But now we have more
- * than one matching operator if the right arg is unknown (eg. float
- * specified with quotes). This break some stuff in the regression
- * test where there are floats in quotes not properly casted. Below
- * is the solution. In addition to requiring the operator operates
- * on the same type for both operands [as in the code Avi originally
- * commented out], we also require that the operators be equivalent
- * in some sense. (see equivalentOpersAfterPromotion for details.)
- * - ay 6/95
- */
- if (!equivalentOpersAfterPromotion(candidates))
- return NULL;
-
- /* if we get here, any one will do but we're more picky and require
- both operands be the same. */
- for (result = candidates; result != NULL; result = result->next) {
- if (result->args[0] == result->args[1])
- return result;
- }
-
- return (NULL);
+ return (NULL);
}
/* Given operator, types of arg1, and arg2, return oper struct */
@@ -477,135 +538,158 @@ binary_oper_select_candidate(Oid arg1,
Operator
oper(char *op, Oid arg1, Oid arg2, bool noWarnings)
{
- HeapTuple tup;
- CandidateList candidates;
- int ncandidates;
-
- if (!arg2) arg2=arg1;
- if (!arg1) arg1=arg2;
-
- if (!(tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(arg1),
- ObjectIdGetDatum(arg2),
- Int8GetDatum('b')))) {
- ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates);
- if (ncandidates == 0) {
- /*
- * no operators of the desired types found
- */
- if (!noWarnings)
- op_error(op, arg1, arg2);
- return(NULL);
- } else if (ncandidates == 1) {
- /*
- * exactly one operator of the desired types found
- */
- tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(candidates->args[0]),
- ObjectIdGetDatum(candidates->args[1]),
- Int8GetDatum('b'));
- Assert(HeapTupleIsValid(tup));
- } else {
- /*
- * multiple operators of the desired types found
- */
- candidates = binary_oper_select_candidate(arg1, arg2, candidates);
- if (candidates != NULL) {
- /* we chose one of them */
- tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(candidates->args[0]),
- ObjectIdGetDatum(candidates->args[1]),
- Int8GetDatum('b'));
- Assert(HeapTupleIsValid(tup));
- } else {
- Type tp1, tp2;
-
- /* we chose none of them */
- tp1 = get_id_type(arg1);
- tp2 = get_id_type(arg2);
- if (!noWarnings) {
- elog(NOTICE, "there is more than one operator %s for types", op);
- elog(NOTICE, "%s and %s. You will have to retype this query",
- tname(tp1), tname(tp2));
- elog(WARN, "using an explicit cast");
+ HeapTuple tup;
+ CandidateList candidates;
+ int ncandidates;
+
+ if (!arg2)
+ arg2 = arg1;
+ if (!arg1)
+ arg1 = arg2;
+
+ if (!(tup = SearchSysCacheTuple(OPRNAME,
+ PointerGetDatum(op),
+ ObjectIdGetDatum(arg1),
+ ObjectIdGetDatum(arg2),
+ Int8GetDatum('b'))))
+ {
+ ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates);
+ if (ncandidates == 0)
+ {
+
+ /*
+ * no operators of the desired types found
+ */
+ if (!noWarnings)
+ op_error(op, arg1, arg2);
+ return (NULL);
+ }
+ else if (ncandidates == 1)
+ {
+
+ /*
+ * exactly one operator of the desired types found
+ */
+ tup = SearchSysCacheTuple(OPRNAME,
+ PointerGetDatum(op),
+ ObjectIdGetDatum(candidates->args[0]),
+ ObjectIdGetDatum(candidates->args[1]),
+ Int8GetDatum('b'));
+ Assert(HeapTupleIsValid(tup));
+ }
+ else
+ {
+
+ /*
+ * multiple operators of the desired types found
+ */
+ candidates = binary_oper_select_candidate(arg1, arg2, candidates);
+ if (candidates != NULL)
+ {
+ /* we chose one of them */
+ tup = SearchSysCacheTuple(OPRNAME,
+ PointerGetDatum(op),
+ ObjectIdGetDatum(candidates->args[0]),
+ ObjectIdGetDatum(candidates->args[1]),
+ Int8GetDatum('b'));
+ Assert(HeapTupleIsValid(tup));
+ }
+ else
+ {
+ Type tp1,
+ tp2;
+
+ /* we chose none of them */
+ tp1 = get_id_type(arg1);
+ tp2 = get_id_type(arg2);
+ if (!noWarnings)
+ {
+ elog(NOTICE, "there is more than one operator %s for types", op);
+ elog(NOTICE, "%s and %s. You will have to retype this query",
+ tname(tp1), tname(tp2));
+ elog(WARN, "using an explicit cast");
+ }
+ return (NULL);
+ }
}
- return(NULL);
- }
}
- }
- return((Operator) tup);
+ return ((Operator) tup);
}
/*
- * given opname and typeId, find all possible types for which
- * a right/left unary operator named opname exists,
- * such that typeId can be coerced to it
+ * given opname and typeId, find all possible types for which
+ * a right/left unary operator named opname exists,
+ * such that typeId can be coerced to it
*/
static int
unary_oper_get_candidates(char *op,
- Oid typeId,
- CandidateList *candidates,
- char rightleft)
+ Oid typeId,
+ CandidateList * candidates,
+ char rightleft)
{
- CandidateList current_candidate;
- Relation pg_operator_desc;
- HeapScanDesc pg_operator_scan;
- HeapTuple tup;
- OperatorTupleForm oper;
- Buffer buffer;
- int ncandidates = 0;
-
- static ScanKeyData opKey[2] = {
- { 0, Anum_pg_operator_oprname, NameEqualRegProcedure },
- { 0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure } };
-
- *candidates = NULL;
-
- fmgr_info(NameEqualRegProcedure, (func_ptr *) &opKey[0].sk_func,
- &opKey[0].sk_nargs);
- opKey[0].sk_argument = NameGetDatum(op);
- fmgr_info(CharacterEqualRegProcedure, (func_ptr *) &opKey[1].sk_func,
- &opKey[1].sk_nargs);
- opKey[1].sk_argument = CharGetDatum(rightleft);
-
- /* currently, only "unknown" can be coerced */
- /* but we should allow types that are internally the same to be "coerced" */
- if (typeId != UNKNOWNOID) {
- return 0;
- }
-
- pg_operator_desc = heap_openr(OperatorRelationName);
- pg_operator_scan = heap_beginscan(pg_operator_desc,
- 0,
- SelfTimeQual,
- 2,
- opKey);
-
- do {
- tup = heap_getnext(pg_operator_scan, 0, &buffer);
- if (HeapTupleIsValid(tup)) {
- current_candidate = (CandidateList)palloc(sizeof(struct _CandidateList));
- current_candidate->args = (Oid *)palloc(sizeof(Oid));
-
- oper = (OperatorTupleForm)GETSTRUCT(tup);
- if (rightleft == 'r')
- current_candidate->args[0] = oper->oprleft;
- else
- current_candidate->args[0] = oper->oprright;
- current_candidate->next = *candidates;
- *candidates = current_candidate;
- ncandidates++;
- ReleaseBuffer(buffer);
+ CandidateList current_candidate;
+ Relation pg_operator_desc;
+ HeapScanDesc pg_operator_scan;
+ HeapTuple tup;
+ OperatorTupleForm oper;
+ Buffer buffer;
+ int ncandidates = 0;
+
+ static ScanKeyData opKey[2] = {
+ {0, Anum_pg_operator_oprname, NameEqualRegProcedure},
+ {0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure}};
+
+ *candidates = NULL;
+
+ fmgr_info(NameEqualRegProcedure, (func_ptr *) & opKey[0].sk_func,
+ &opKey[0].sk_nargs);
+ opKey[0].sk_argument = NameGetDatum(op);
+ fmgr_info(CharacterEqualRegProcedure, (func_ptr *) & opKey[1].sk_func,
+ &opKey[1].sk_nargs);
+ opKey[1].sk_argument = CharGetDatum(rightleft);
+
+ /* currently, only "unknown" can be coerced */
+
+ /*
+ * but we should allow types that are internally the same to be
+ * "coerced"
+ */
+ if (typeId != UNKNOWNOID)
+ {
+ return 0;
}
- } while(HeapTupleIsValid(tup));
-
- heap_endscan(pg_operator_scan);
- heap_close(pg_operator_desc);
-
- return ncandidates;
+
+ pg_operator_desc = heap_openr(OperatorRelationName);
+ pg_operator_scan = heap_beginscan(pg_operator_desc,
+ 0,
+ SelfTimeQual,
+ 2,
+ opKey);
+
+ do
+ {
+ tup = heap_getnext(pg_operator_scan, 0, &buffer);
+ if (HeapTupleIsValid(tup))
+ {
+ current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList));
+ current_candidate->args = (Oid *) palloc(sizeof(Oid));
+
+ oper = (OperatorTupleForm) GETSTRUCT(tup);
+ if (rightleft == 'r')
+ current_candidate->args[0] = oper->oprleft;
+ else
+ current_candidate->args[0] = oper->oprright;
+ current_candidate->next = *candidates;
+ *candidates = current_candidate;
+ ncandidates++;
+ ReleaseBuffer(buffer);
+ }
+ } while (HeapTupleIsValid(tup));
+
+ heap_endscan(pg_operator_scan);
+ heap_close(pg_operator_desc);
+
+ return ncandidates;
}
/* Given unary right-side operator (operator on right), return oper struct */
@@ -613,42 +697,44 @@ unary_oper_get_candidates(char *op,
Operator
right_oper(char *op, Oid arg)
{
- HeapTuple tup;
- CandidateList candidates;
- int ncandidates;
-
- /*
- if (!OpCache) {
- init_op_cache();
- }
- */
- if (!(tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(arg),
- ObjectIdGetDatum(InvalidOid),
- Int8GetDatum('r')))) {
- ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r');
- if (ncandidates == 0) {
- elog ( WARN ,
- "Can't find right op: %s for type %d", op, arg );
- return(NULL);
- }
- else if (ncandidates == 1) {
- tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(candidates->args[0]),
- ObjectIdGetDatum(InvalidOid),
- Int8GetDatum('r'));
- Assert(HeapTupleIsValid(tup));
- }
- else {
- elog(NOTICE, "there is more than one right operator %s", op);
- elog(NOTICE, "you will have to retype this query");
- elog(WARN, "using an explicit cast");
- return(NULL);
+ HeapTuple tup;
+ CandidateList candidates;
+ int ncandidates;
+
+ /*
+ * if (!OpCache) { init_op_cache(); }
+ */
+ if (!(tup = SearchSysCacheTuple(OPRNAME,
+ PointerGetDatum(op),
+ ObjectIdGetDatum(arg),
+ ObjectIdGetDatum(InvalidOid),
+ Int8GetDatum('r'))))
+ {
+ ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r');
+ if (ncandidates == 0)
+ {
+ elog(WARN,
+ "Can't find right op: %s for type %d", op, arg);
+ return (NULL);
+ }
+ else if (ncandidates == 1)
+ {
+ tup = SearchSysCacheTuple(OPRNAME,
+ PointerGetDatum(op),
+ ObjectIdGetDatum(candidates->args[0]),
+ ObjectIdGetDatum(InvalidOid),
+ Int8GetDatum('r'));
+ Assert(HeapTupleIsValid(tup));
+ }
+ else
+ {
+ elog(NOTICE, "there is more than one right operator %s", op);
+ elog(NOTICE, "you will have to retype this query");
+ elog(WARN, "using an explicit cast");
+ return (NULL);
+ }
}
- }
- return((Operator) tup);
+ return ((Operator) tup);
}
/* Given unary left-side operator (operator on left), return oper struct */
@@ -656,42 +742,44 @@ right_oper(char *op, Oid arg)
Operator
left_oper(char *op, Oid arg)
{
- HeapTuple tup;
- CandidateList candidates;
- int ncandidates;
-
- /*
- if (!OpCache) {
- init_op_cache();
- }
- */
- if (!(tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(InvalidOid),
- ObjectIdGetDatum(arg),
- Int8GetDatum('l')))) {
- ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l');
- if (ncandidates == 0) {
- elog ( WARN ,
- "Can't find left op: %s for type %d", op, arg );
- return(NULL);
- }
- else if (ncandidates == 1) {
- tup = SearchSysCacheTuple(OPRNAME,
- PointerGetDatum(op),
- ObjectIdGetDatum(InvalidOid),
- ObjectIdGetDatum(candidates->args[0]),
- Int8GetDatum('l'));
- Assert(HeapTupleIsValid(tup));
- }
- else {
- elog(NOTICE, "there is more than one left operator %s", op);
- elog(NOTICE, "you will have to retype this query");
- elog(WARN, "using an explicit cast");
- return(NULL);
+ HeapTuple tup;
+ CandidateList candidates;
+ int ncandidates;
+
+ /*
+ * if (!OpCache) { init_op_cache(); }
+ */
+ if (!(tup = SearchSysCacheTuple(OPRNAME,
+ PointerGetDatum(op),
+ ObjectIdGetDatum(InvalidOid),
+ ObjectIdGetDatum(arg),
+ Int8GetDatum('l'))))
+ {
+ ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l');
+ if (ncandidates == 0)
+ {
+ elog(WARN,
+ "Can't find left op: %s for type %d", op, arg);
+ return (NULL);
+ }
+ else if (ncandidates == 1)
+ {
+ tup = SearchSysCacheTuple(OPRNAME,
+ PointerGetDatum(op),
+ ObjectIdGetDatum(InvalidOid),
+ ObjectIdGetDatum(candidates->args[0]),
+ Int8GetDatum('l'));
+ Assert(HeapTupleIsValid(tup));
+ }
+ else
+ {
+ elog(NOTICE, "there is more than one left operator %s", op);
+ elog(NOTICE, "you will have to retype this query");
+ elog(WARN, "using an explicit cast");
+ return (NULL);
+ }
}
- }
- return((Operator) tup);
+ return ((Operator) tup);
}
/* given range variable, return id of variable */
@@ -699,22 +787,26 @@ left_oper(char *op, Oid arg)
int
varattno(Relation rd, char *a)
{
- int i;
-
- for (i = 0; i < rd->rd_rel->relnatts; i++) {
- if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) {
- return(i+1);
+ int i;
+
+ for (i = 0; i < rd->rd_rel->relnatts; i++)
+ {
+ if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
+ {
+ return (i + 1);
+ }
}
- }
- for (i = 0; i < SPECIALS; i++) {
- if (!strcmp(special_attr[i].field, a)) {
- return(special_attr[i].code);
+ for (i = 0; i < SPECIALS; i++)
+ {
+ if (!strcmp(special_attr[i].field, a))
+ {
+ return (special_attr[i].code);
+ }
}
- }
-
- elog(WARN,"Relation %s does not have attribute %s\n",
- RelationGetRelationName(rd), a );
- return(-1);
+
+ elog(WARN, "Relation %s does not have attribute %s\n",
+ RelationGetRelationName(rd), a);
+ return (-1);
}
/* Given range variable, return whether attribute of this name
@@ -725,104 +817,118 @@ varattno(Relation rd, char *a)
bool
varisset(Relation rd, char *name)
{
- int i;
-
- /* First check if this is a system attribute */
- for (i = 0; i < SPECIALS; i++) {
- if (! strcmp(special_attr[i].field, name)) {
- return(false); /* no sys attr is a set */
+ int i;
+
+ /* First check if this is a system attribute */
+ for (i = 0; i < SPECIALS; i++)
+ {
+ if (!strcmp(special_attr[i].field, name))
+ {
+ return (false); /* no sys attr is a set */
+ }
}
- }
- return (get_attisset(rd->rd_id, name));
+ return (get_attisset(rd->rd_id, name));
}
/* given range variable, return id of variable */
int
nf_varattno(Relation rd, char *a)
{
- int i;
-
- for (i = 0; i < rd->rd_rel->relnatts; i++) {
- if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) {
- return(i+1);
+ int i;
+
+ for (i = 0; i < rd->rd_rel->relnatts; i++)
+ {
+ if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
+ {
+ return (i + 1);
+ }
}
- }
- for (i = 0; i < SPECIALS; i++) {
- if (!strcmp(special_attr[i].field, a)) {
- return(special_attr[i].code);
+ for (i = 0; i < SPECIALS; i++)
+ {
+ if (!strcmp(special_attr[i].field, a))
+ {
+ return (special_attr[i].code);
+ }
}
- }
- return InvalidAttrNumber;
+ return InvalidAttrNumber;
}
/*-------------
* given an attribute number and a relation, return its relation name
*/
-char*
+char *
getAttrName(Relation rd, int attrno)
{
- char *name;
- int i;
-
- if (attrno<0) {
- for (i = 0; i < SPECIALS; i++) {
- if (special_attr[i].code == attrno) {
- name = special_attr[i].field;
- return(name);
- }
+ char *name;
+ int i;
+
+ if (attrno < 0)
+ {
+ for (i = 0; i < SPECIALS; i++)
+ {
+ if (special_attr[i].code == attrno)
+ {
+ name = special_attr[i].field;
+ return (name);
+ }
+ }
+ elog(WARN, "Illegal attr no %d for relation %s\n",
+ attrno, RelationGetRelationName(rd));
+ }
+ else if (attrno >= 1 && attrno <= RelationGetNumberOfAttributes(rd))
+ {
+ name = (rd->rd_att->attrs[attrno - 1]->attname).data;
+ return (name);
+ }
+ else
+ {
+ elog(WARN, "Illegal attr no %d for relation %s\n",
+ attrno, RelationGetRelationName(rd));
}
- elog(WARN, "Illegal attr no %d for relation %s\n",
- attrno, RelationGetRelationName(rd));
- } else if (attrno >=1 && attrno<= RelationGetNumberOfAttributes(rd)) {
- name = (rd->rd_att->attrs[attrno-1]->attname).data;
- return(name);
- } else {
- elog(WARN, "Illegal attr no %d for relation %s\n",
- attrno, RelationGetRelationName(rd));
- }
-
- /*
- * Shouldn't get here, but we want lint to be happy...
- */
-
- return(NULL);
+
+ /*
+ * Shouldn't get here, but we want lint to be happy...
+ */
+
+ return (NULL);
}
/* Given a typename and value, returns the ascii form of the value */
#ifdef NOT_USED
-char *
-outstr(char *typename, /* Name of type of value */
- char *value) /* Could be of any type */
+char *
+outstr(char *typename, /* Name of type of value */
+ char *value) /* Could be of any type */
{
- TypeTupleForm tp;
- Oid op;
-
- tp = (TypeTupleForm ) GETSTRUCT(type(typename));
- op = tp->typoutput;
- return((char *) fmgr(op, value));
+ TypeTupleForm tp;
+ Oid op;
+
+ tp = (TypeTupleForm) GETSTRUCT(type(typename));
+ op = tp->typoutput;
+ return ((char *) fmgr(op, value));
}
+
#endif
/* Given a Type and a string, return the internal form of that string */
-char *
+char *
instr2(Type tp, char *string, int typlen)
{
- return(instr1((TypeTupleForm ) GETSTRUCT(tp), string, typlen));
+ return (instr1((TypeTupleForm) GETSTRUCT(tp), string, typlen));
}
/* Given a type structure and a string, returns the internal form of
that string */
-static char *
+static char *
instr1(TypeTupleForm tp, char *string, int typlen)
{
- Oid op;
- Oid typelem;
-
- op = tp->typinput;
- typelem = tp->typelem; /* XXX - used for array_in */
- /* typlen is for bpcharin() and varcharin() */
- return((char *) fmgr(op, string, typelem, typlen));
+ Oid op;
+ Oid typelem;
+
+ op = tp->typinput;
+ typelem = tp->typelem; /* XXX - used for array_in */
+ /* typlen is for bpcharin() and varcharin() */
+ return ((char *) fmgr(op, string, typelem, typlen));
}
/* Given the attribute type of an array return the arrtribute type of
@@ -831,151 +937,160 @@ instr1(TypeTupleForm tp, char *string, int typlen)
Oid
GetArrayElementType(Oid typearray)
{
- HeapTuple type_tuple;
- TypeTupleForm type_struct_array;
-
- type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(typearray),
- 0,0,0);
-
- if (!HeapTupleIsValid(type_tuple))
- elog(WARN, "GetArrayElementType: Cache lookup failed for type %d\n",
- typearray);
-
- /* get the array type struct from the type tuple */
- type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
-
- if (type_struct_array->typelem == InvalidOid) {
- elog(WARN, "GetArrayElementType: type %s is not an array",
- (Name)&(type_struct_array->typname.data[0]));
- }
-
- return(type_struct_array->typelem);
+ HeapTuple type_tuple;
+ TypeTupleForm type_struct_array;
+
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(typearray),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "GetArrayElementType: Cache lookup failed for type %d\n",
+ typearray);
+
+ /* get the array type struct from the type tuple */
+ type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ if (type_struct_array->typelem == InvalidOid)
+ {
+ elog(WARN, "GetArrayElementType: type %s is not an array",
+ (Name) & (type_struct_array->typname.data[0]));
+ }
+
+ return (type_struct_array->typelem);
}
Oid
funcid_get_rettype(Oid funcid)
{
- HeapTuple func_tuple = NULL;
- Oid funcrettype = (Oid)0;
-
- func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),
- 0,0,0);
-
- if ( !HeapTupleIsValid ( func_tuple ))
- elog (WARN, "function %d does not exist", funcid);
-
- funcrettype = (Oid)
- ((Form_pg_proc)GETSTRUCT(func_tuple))->prorettype ;
-
- return (funcrettype);
+ HeapTuple func_tuple = NULL;
+ Oid funcrettype = (Oid) 0;
+
+ func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(func_tuple))
+ elog(WARN, "function %d does not exist", funcid);
+
+ funcrettype = (Oid)
+ ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype;
+
+ return (funcrettype);
}
/*
* get a list of all argument type vectors for which a function named
* funcname taking nargs arguments exists
*/
-static CandidateList
+static CandidateList
func_get_candidates(char *funcname, int nargs)
{
- Relation heapRelation;
- Relation idesc;
- ScanKeyData skey;
- HeapTuple tuple;
- IndexScanDesc sd;
- RetrieveIndexResult indexRes;
- Buffer buffer;
- Form_pg_proc pgProcP;
- bool bufferUsed = FALSE;
- CandidateList candidates = NULL;
- CandidateList current_candidate;
- int i;
-
- heapRelation = heap_openr(ProcedureRelationName);
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)NameEqualRegProcedure,
- (Datum)funcname);
-
- idesc = index_openr(ProcedureNameIndex);
-
- sd = index_beginscan(idesc, false, 1, &skey);
-
- do {
- tuple = (HeapTuple)NULL;
- if (bufferUsed) {
- ReleaseBuffer(buffer);
- bufferUsed = FALSE;
- }
-
- 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)) {
- pgProcP = (Form_pg_proc)GETSTRUCT(tuple);
- bufferUsed = TRUE;
- if (pgProcP->pronargs == nargs) {
- current_candidate = (CandidateList)
- palloc(sizeof(struct _CandidateList));
- current_candidate->args = (Oid *)
- palloc(8 * sizeof(Oid));
- memset(current_candidate->args, 0, 8 * sizeof(Oid));
- for (i=0; i<nargs; i++) {
- current_candidate->args[i] =
- pgProcP->proargtypes[i];
- }
-
- current_candidate->next = candidates;
- candidates = current_candidate;
+ Relation heapRelation;
+ Relation idesc;
+ ScanKeyData skey;
+ HeapTuple tuple;
+ IndexScanDesc sd;
+ RetrieveIndexResult indexRes;
+ Buffer buffer;
+ Form_pg_proc pgProcP;
+ bool bufferUsed = FALSE;
+ CandidateList candidates = NULL;
+ CandidateList current_candidate;
+ int i;
+
+ heapRelation = heap_openr(ProcedureRelationName);
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) NameEqualRegProcedure,
+ (Datum) funcname);
+
+ idesc = index_openr(ProcedureNameIndex);
+
+ sd = index_beginscan(idesc, false, 1, &skey);
+
+ do
+ {
+ tuple = (HeapTuple) NULL;
+ if (bufferUsed)
+ {
+ ReleaseBuffer(buffer);
+ bufferUsed = FALSE;
}
- }
- }
- } while (indexRes);
-
- index_endscan(sd);
- index_close(idesc);
- heap_close(heapRelation);
-
- return candidates;
+
+ 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))
+ {
+ pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
+ bufferUsed = TRUE;
+ if (pgProcP->pronargs == nargs)
+ {
+ current_candidate = (CandidateList)
+ palloc(sizeof(struct _CandidateList));
+ current_candidate->args = (Oid *)
+ palloc(8 * sizeof(Oid));
+ memset(current_candidate->args, 0, 8 * sizeof(Oid));
+ for (i = 0; i < nargs; i++)
+ {
+ current_candidate->args[i] =
+ pgProcP->proargtypes[i];
+ }
+
+ current_candidate->next = candidates;
+ candidates = current_candidate;
+ }
+ }
+ }
+ } while (indexRes);
+
+ index_endscan(sd);
+ index_close(idesc);
+ heap_close(heapRelation);
+
+ return candidates;
}
/*
* can input_typeids be coerced to func_typeids?
*/
-static bool
-can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
+static bool
+can_coerce(int nargs, Oid * input_typeids, Oid * func_typeids)
{
- int i;
- Type tp;
-
- /*
- * right now, we only coerce "unknown", and we cannot coerce it to a
- * relation type
- */
- for (i=0; i<nargs; i++) {
- if (input_typeids[i] != func_typeids[i]) {
- if ((input_typeids[i] == BPCHAROID && func_typeids[i] == TEXTOID) ||
- (input_typeids[i] == BPCHAROID && func_typeids[i] == VARCHAROID) ||
- (input_typeids[i] == VARCHAROID && func_typeids[i] == TEXTOID) ||
- (input_typeids[i] == VARCHAROID && func_typeids[i] == BPCHAROID) ||
- (input_typeids[i] == CASHOID && func_typeids[i] == INT4OID) ||
- (input_typeids[i] == INT4OID && func_typeids[i] == CASHOID))
- ; /* these are OK */
- else if (input_typeids[i] != UNKNOWNOID || func_typeids[i] == 0)
- return false;
-
- tp = get_id_type(input_typeids[i]);
- if (typetypetype(tp) == 'c' )
- return false;
+ int i;
+ Type tp;
+
+ /*
+ * right now, we only coerce "unknown", and we cannot coerce it to a
+ * relation type
+ */
+ for (i = 0; i < nargs; i++)
+ {
+ if (input_typeids[i] != func_typeids[i])
+ {
+ if ((input_typeids[i] == BPCHAROID && func_typeids[i] == TEXTOID) ||
+ (input_typeids[i] == BPCHAROID && func_typeids[i] == VARCHAROID) ||
+ (input_typeids[i] == VARCHAROID && func_typeids[i] == TEXTOID) ||
+ (input_typeids[i] == VARCHAROID && func_typeids[i] == BPCHAROID) ||
+ (input_typeids[i] == CASHOID && func_typeids[i] == INT4OID) ||
+ (input_typeids[i] == INT4OID && func_typeids[i] == CASHOID))
+ ; /* these are OK */
+ else if (input_typeids[i] != UNKNOWNOID || func_typeids[i] == 0)
+ return false;
+
+ tp = get_id_type(input_typeids[i]);
+ if (typetypetype(tp) == 'c')
+ return false;
+ }
}
- }
-
- return true;
+
+ return true;
}
/*
@@ -986,32 +1101,34 @@ can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids)
*/
static int
match_argtypes(int nargs,
- Oid *input_typeids,
- CandidateList function_typeids,
- CandidateList *candidates) /* return value */
+ Oid * input_typeids,
+ CandidateList function_typeids,
+ CandidateList * candidates) /* return value */
{
- CandidateList current_candidate;
- CandidateList matching_candidate;
- Oid *current_typeids;
- int ncandidates = 0;
-
- *candidates = NULL;
-
- for (current_candidate = function_typeids;
- current_candidate != NULL;
- current_candidate = current_candidate->next) {
- current_typeids = current_candidate->args;
- if (can_coerce(nargs, input_typeids, current_typeids)) {
- matching_candidate = (CandidateList)
- palloc(sizeof(struct _CandidateList));
- matching_candidate->args = current_typeids;
- matching_candidate->next = *candidates;
- *candidates = matching_candidate;
- ncandidates++;
+ CandidateList current_candidate;
+ CandidateList matching_candidate;
+ Oid *current_typeids;
+ int ncandidates = 0;
+
+ *candidates = NULL;
+
+ for (current_candidate = function_typeids;
+ current_candidate != NULL;
+ current_candidate = current_candidate->next)
+ {
+ current_typeids = current_candidate->args;
+ if (can_coerce(nargs, input_typeids, current_typeids))
+ {
+ matching_candidate = (CandidateList)
+ palloc(sizeof(struct _CandidateList));
+ matching_candidate->args = current_typeids;
+ matching_candidate->next = *candidates;
+ *candidates = matching_candidate;
+ ncandidates++;
+ }
}
- }
-
- return ncandidates;
+
+ return ncandidates;
}
/*
@@ -1020,442 +1137,483 @@ match_argtypes(int nargs,
* returns the selected argtype array if the conflict can be resolved,
* otherwise returns NULL
*/
-static Oid *
+static Oid *
func_select_candidate(int nargs,
- Oid *input_typeids,
- CandidateList candidates)
+ Oid * input_typeids,
+ CandidateList candidates)
{
- /* XXX no conflict resolution implemeneted yet */
- return (NULL);
+ /* XXX no conflict resolution implemeneted yet */
+ return (NULL);
}
bool
func_get_detail(char *funcname,
- int nargs,
- Oid *oid_array,
- Oid *funcid, /* return value */
- Oid *rettype, /* return value */
- bool *retset, /* return value */
- Oid **true_typeids) /* return value */
+ int nargs,
+ Oid * oid_array,
+ Oid * funcid, /* return value */
+ Oid * rettype, /* return value */
+ bool * retset, /* return value */
+ Oid ** true_typeids) /* return value */
{
- Oid **input_typeid_vector;
- Oid *current_input_typeids;
- CandidateList function_typeids;
- CandidateList current_function_typeids;
- HeapTuple ftup;
- Form_pg_proc pform;
-
- /*
- * attempt to find named function in the system catalogs
- * with arguments exactly as specified - so that the normal
- * case is just as quick as before
- */
- ftup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- Int32GetDatum(nargs),
- PointerGetDatum(oid_array),
- 0);
- *true_typeids = oid_array;
-
- /*
- * If an exact match isn't found :
- * 1) get a vector of all possible input arg type arrays constructed
- * from the superclasses of the original input arg types
- * 2) get a list of all possible argument type arrays to the
- * function with given name and number of arguments
- * 3) for each input arg type array from vector #1 :
- * a) find how many of the function arg type arrays from list #2
- * it can be coerced to
- * b) - if the answer is one, we have our function
- * - if the answer is more than one, attempt to resolve the
- * conflict
- * - if the answer is zero, try the next array from vector #1
- */
- if (!HeapTupleIsValid(ftup)) {
- function_typeids = func_get_candidates(funcname, nargs);
-
- if (function_typeids != NULL) {
- int ncandidates = 0;
-
- input_typeid_vector = argtype_inherit(nargs, oid_array);
- current_input_typeids = oid_array;
-
- do {
- ncandidates = match_argtypes(nargs, current_input_typeids,
- function_typeids,
- &current_function_typeids);
- if (ncandidates == 1) {
- *true_typeids = current_function_typeids->args;
- ftup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- Int32GetDatum(nargs),
- PointerGetDatum(*true_typeids),
- 0);
- Assert(HeapTupleIsValid(ftup));
+ Oid **input_typeid_vector;
+ Oid *current_input_typeids;
+ CandidateList function_typeids;
+ CandidateList current_function_typeids;
+ HeapTuple ftup;
+ Form_pg_proc pform;
+
+ /*
+ * attempt to find named function in the system catalogs with
+ * arguments exactly as specified - so that the normal case is just as
+ * quick as before
+ */
+ ftup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(funcname),
+ Int32GetDatum(nargs),
+ PointerGetDatum(oid_array),
+ 0);
+ *true_typeids = oid_array;
+
+ /*
+ * If an exact match isn't found : 1) get a vector of all possible
+ * input arg type arrays constructed from the superclasses of the
+ * original input arg types 2) get a list of all possible argument
+ * type arrays to the function with given name and number of arguments
+ * 3) for each input arg type array from vector #1 : a) find how many
+ * of the function arg type arrays from list #2 it can be coerced to
+ * b) - if the answer is one, we have our function - if the answer is
+ * more than one, attempt to resolve the conflict - if the answer is
+ * zero, try the next array from vector #1
+ */
+ if (!HeapTupleIsValid(ftup))
+ {
+ function_typeids = func_get_candidates(funcname, nargs);
+
+ if (function_typeids != NULL)
+ {
+ int ncandidates = 0;
+
+ input_typeid_vector = argtype_inherit(nargs, oid_array);
+ current_input_typeids = oid_array;
+
+ do
+ {
+ ncandidates = match_argtypes(nargs, current_input_typeids,
+ function_typeids,
+ &current_function_typeids);
+ if (ncandidates == 1)
+ {
+ *true_typeids = current_function_typeids->args;
+ ftup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(funcname),
+ Int32GetDatum(nargs),
+ PointerGetDatum(*true_typeids),
+ 0);
+ Assert(HeapTupleIsValid(ftup));
+ }
+ else if (ncandidates > 1)
+ {
+ *true_typeids =
+ func_select_candidate(nargs,
+ current_input_typeids,
+ current_function_typeids);
+ if (*true_typeids == NULL)
+ {
+ elog(NOTICE, "there is more than one function named \"%s\"",
+ funcname);
+ elog(NOTICE, "that satisfies the given argument types. you will have to");
+ elog(NOTICE, "retype your query using explicit typecasts.");
+ func_error("func_get_detail", funcname, nargs, oid_array);
+ }
+ else
+ {
+ ftup = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(funcname),
+ Int32GetDatum(nargs),
+ PointerGetDatum(*true_typeids),
+ 0);
+ Assert(HeapTupleIsValid(ftup));
+ }
+ }
+ current_input_typeids = *input_typeid_vector++;
+ }
+ while (current_input_typeids !=
+ InvalidOid && ncandidates == 0);
}
- else if (ncandidates > 1) {
- *true_typeids =
- func_select_candidate(nargs,
- current_input_typeids,
- current_function_typeids);
- if (*true_typeids == NULL) {
- elog(NOTICE, "there is more than one function named \"%s\"",
- funcname);
- elog(NOTICE, "that satisfies the given argument types. you will have to");
- elog(NOTICE, "retype your query using explicit typecasts.");
- func_error("func_get_detail", funcname, nargs, oid_array);
- }
- else {
- ftup = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- Int32GetDatum(nargs),
- PointerGetDatum(*true_typeids),
- 0);
- Assert(HeapTupleIsValid(ftup));
- }
+ }
+
+ if (!HeapTupleIsValid(ftup))
+ {
+ Type tp;
+
+ if (nargs == 1)
+ {
+ tp = get_id_type(oid_array[0]);
+ if (typetypetype(tp) == 'c')
+ elog(WARN, "no such attribute or function \"%s\"",
+ funcname);
}
- current_input_typeids = *input_typeid_vector++;
- }
- while (current_input_typeids !=
- InvalidOid && ncandidates == 0);
+ func_error("func_get_detail", funcname, nargs, oid_array);
}
- }
-
- if (!HeapTupleIsValid(ftup)) {
- Type tp;
-
- if (nargs == 1) {
- tp = get_id_type(oid_array[0]);
- if (typetypetype(tp) == 'c')
- elog(WARN, "no such attribute or function \"%s\"",
- funcname);
+ else
+ {
+ pform = (Form_pg_proc) GETSTRUCT(ftup);
+ *funcid = ftup->t_oid;
+ *rettype = pform->prorettype;
+ *retset = pform->proretset;
+
+ return (true);
}
- func_error("func_get_detail", funcname, nargs, oid_array);
- } else {
- pform = (Form_pg_proc) GETSTRUCT(ftup);
- *funcid = ftup->t_oid;
- *rettype = pform->prorettype;
- *retset = pform->proretset;
-
- return (true);
- }
/* shouldn't reach here */
- return (false);
+ return (false);
}
/*
- * argtype_inherit() -- Construct an argtype vector reflecting the
- * inheritance properties of the supplied argv.
+ * argtype_inherit() -- Construct an argtype vector reflecting the
+ * inheritance properties of the supplied argv.
*
- * This function is used to disambiguate among functions with the
- * same name but different signatures. It takes an array of eight
- * type ids. For each type id in the array that's a complex type
- * (a class), it walks up the inheritance tree, finding all
- * superclasses of that type. A vector of new Oid type arrays
- * is returned to the caller, reflecting the structure of the
- * inheritance tree above the supplied arguments.
+ * This function is used to disambiguate among functions with the
+ * same name but different signatures. It takes an array of eight
+ * type ids. For each type id in the array that's a complex type
+ * (a class), it walks up the inheritance tree, finding all
+ * superclasses of that type. A vector of new Oid type arrays
+ * is returned to the caller, reflecting the structure of the
+ * inheritance tree above the supplied arguments.
*
- * The order of this vector is as follows: all superclasses of the
- * rightmost complex class are explored first. The exploration
- * continues from right to left. This policy means that we favor
- * keeping the leftmost argument type as low in the inheritance tree
- * as possible. This is intentional; it is exactly what we need to
- * do for method dispatch. The last type array we return is all
- * zeroes. This will match any functions for which return types are
- * not defined. There are lots of these (mostly builtins) in the
- * catalogs.
+ * The order of this vector is as follows: all superclasses of the
+ * rightmost complex class are explored first. The exploration
+ * continues from right to left. This policy means that we favor
+ * keeping the leftmost argument type as low in the inheritance tree
+ * as possible. This is intentional; it is exactly what we need to
+ * do for method dispatch. The last type array we return is all
+ * zeroes. This will match any functions for which return types are
+ * not defined. There are lots of these (mostly builtins) in the
+ * catalogs.
*/
-static Oid **
-argtype_inherit(int nargs, Oid *oid_array)
+static Oid **
+argtype_inherit(int nargs, Oid * oid_array)
{
- Oid relid;
- int i;
- InhPaths arginh[MAXFARGS];
-
- for (i = 0; i < MAXFARGS; i++) {
- if (i < nargs) {
- arginh[i].self = oid_array[i];
- if ((relid = typeid_get_relid(oid_array[i])) != InvalidOid) {
- arginh[i].nsupers = findsupers(relid, &(arginh[i].supervec));
- } else {
- arginh[i].nsupers = 0;
- arginh[i].supervec = (Oid *) NULL;
- }
- } else {
- arginh[i].self = InvalidOid;
- arginh[i].nsupers = 0;
- arginh[i].supervec = (Oid *) NULL;
+ Oid relid;
+ int i;
+ InhPaths arginh[MAXFARGS];
+
+ for (i = 0; i < MAXFARGS; i++)
+ {
+ if (i < nargs)
+ {
+ arginh[i].self = oid_array[i];
+ if ((relid = typeid_get_relid(oid_array[i])) != InvalidOid)
+ {
+ arginh[i].nsupers = findsupers(relid, &(arginh[i].supervec));
+ }
+ else
+ {
+ arginh[i].nsupers = 0;
+ arginh[i].supervec = (Oid *) NULL;
+ }
+ }
+ else
+ {
+ arginh[i].self = InvalidOid;
+ arginh[i].nsupers = 0;
+ arginh[i].supervec = (Oid *) NULL;
+ }
}
- }
-
- /* return an ordered cross-product of the classes involved */
- return (genxprod(arginh, nargs));
+
+ /* return an ordered cross-product of the classes involved */
+ return (genxprod(arginh, nargs));
}
-typedef struct _SuperQE {
- Oid sqe_relid;
-} SuperQE;
+typedef struct _SuperQE
+{
+ Oid sqe_relid;
+} SuperQE;
static int
-findsupers(Oid relid, Oid **supervec)
+findsupers(Oid relid, Oid ** supervec)
{
- Oid *relidvec;
- Relation inhrel;
- HeapScanDesc inhscan;
- ScanKeyData skey;
- HeapTuple inhtup;
- TupleDesc inhtupdesc;
- int nvisited;
- SuperQE *qentry, *vnode;
- Dllist *visited, *queue;
- Dlelem *qe, *elt;
-
- Relation rd;
- Buffer buf;
- Datum d;
- bool newrelid;
- char isNull;
-
- nvisited = 0;
- queue = DLNewList();
- visited = DLNewList();
-
-
- inhrel = heap_openr(InheritsRelationName);
- RelationSetLockForRead(inhrel);
- inhtupdesc = RelationGetTupleDescriptor(inhrel);
-
- /*
- * Use queue to do a breadth-first traversal of the inheritance
- * graph from the relid supplied up to the root.
- */
- do {
- ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
-
- inhscan = heap_beginscan(inhrel, 0, NowTimeQual, 1, &skey);
-
- while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf))) {
- qentry = (SuperQE *) palloc(sizeof(SuperQE));
-
- d = (Datum) fastgetattr(inhtup, Anum_pg_inherits_inhparent,
- inhtupdesc, &isNull);
- qentry->sqe_relid = DatumGetObjectId(d);
-
- /* put this one on the queue */
- DLAddTail(queue, DLNewElem(qentry));
-
- ReleaseBuffer(buf);
+ Oid *relidvec;
+ Relation inhrel;
+ HeapScanDesc inhscan;
+ ScanKeyData skey;
+ HeapTuple inhtup;
+ TupleDesc inhtupdesc;
+ int nvisited;
+ SuperQE *qentry,
+ *vnode;
+ Dllist *visited,
+ *queue;
+ Dlelem *qe,
+ *elt;
+
+ Relation rd;
+ Buffer buf;
+ Datum d;
+ bool newrelid;
+ char isNull;
+
+ nvisited = 0;
+ queue = DLNewList();
+ visited = DLNewList();
+
+
+ inhrel = heap_openr(InheritsRelationName);
+ RelationSetLockForRead(inhrel);
+ inhtupdesc = RelationGetTupleDescriptor(inhrel);
+
+ /*
+ * Use queue to do a breadth-first traversal of the inheritance graph
+ * from the relid supplied up to the root.
+ */
+ do
+ {
+ ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+
+ inhscan = heap_beginscan(inhrel, 0, NowTimeQual, 1, &skey);
+
+ while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf)))
+ {
+ qentry = (SuperQE *) palloc(sizeof(SuperQE));
+
+ d = (Datum) fastgetattr(inhtup, Anum_pg_inherits_inhparent,
+ inhtupdesc, &isNull);
+ qentry->sqe_relid = DatumGetObjectId(d);
+
+ /* put this one on the queue */
+ DLAddTail(queue, DLNewElem(qentry));
+
+ ReleaseBuffer(buf);
+ }
+
+ heap_endscan(inhscan);
+
+ /* pull next unvisited relid off the queue */
+ do
+ {
+ qe = DLRemHead(queue);
+ qentry = qe ? (SuperQE *) DLE_VAL(qe) : NULL;
+
+ if (qentry == (SuperQE *) NULL)
+ break;
+
+ relid = qentry->sqe_relid;
+ newrelid = true;
+
+ for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))
+ {
+ vnode = (SuperQE *) DLE_VAL(elt);
+ if (vnode && (qentry->sqe_relid == vnode->sqe_relid))
+ {
+ newrelid = false;
+ break;
+ }
+ }
+ } while (!newrelid);
+
+ if (qentry != (SuperQE *) NULL)
+ {
+
+ /* save the type id, rather than the relation id */
+ if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)
+ elog(WARN, "relid %d does not exist", qentry->sqe_relid);
+ qentry->sqe_relid = typeid(type(RelationGetRelationName(rd)->data));
+ heap_close(rd);
+
+ DLAddTail(visited, qe);
+
+ nvisited++;
+ }
+ } while (qentry != (SuperQE *) NULL);
+
+ RelationUnsetLockForRead(inhrel);
+ heap_close(inhrel);
+
+ if (nvisited > 0)
+ {
+ relidvec = (Oid *) palloc(nvisited * sizeof(Oid));
+ *supervec = relidvec;
+
+ for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt))
+ {
+ vnode = (SuperQE *) DLE_VAL(elt);
+ *relidvec++ = vnode->sqe_relid;
+ }
+
}
-
- heap_endscan(inhscan);
-
- /* pull next unvisited relid off the queue */
- do {
- qe = DLRemHead(queue);
- qentry = qe ? (SuperQE*)DLE_VAL(qe) : NULL;
-
- if (qentry == (SuperQE *) NULL)
- break;
-
- relid = qentry->sqe_relid;
- newrelid = true;
-
- for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) {
- vnode = (SuperQE*)DLE_VAL(elt);
- if (vnode && (qentry->sqe_relid == vnode->sqe_relid)) {
- newrelid = false;
- break;
- }
- }
- } while (!newrelid);
-
- if (qentry != (SuperQE *) NULL) {
-
- /* save the type id, rather than the relation id */
- if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL)
- elog(WARN, "relid %d does not exist", qentry->sqe_relid);
- qentry->sqe_relid = typeid(type(RelationGetRelationName(rd)->data));
- heap_close(rd);
-
- DLAddTail(visited, qe);
-
- nvisited++;
+ else
+ {
+ *supervec = (Oid *) NULL;
}
- } while (qentry != (SuperQE *) NULL);
-
- RelationUnsetLockForRead(inhrel);
- heap_close(inhrel);
-
- if (nvisited > 0) {
- relidvec = (Oid *) palloc(nvisited * sizeof(Oid));
- *supervec = relidvec;
-
- for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) {
- vnode = (SuperQE*)DLE_VAL(elt);
- *relidvec++ = vnode->sqe_relid;
- }
-
- } else {
- *supervec = (Oid *) NULL;
- }
-
- return (nvisited);
+
+ return (nvisited);
}
-static Oid **
-genxprod(InhPaths *arginh, int nargs)
+static Oid **
+genxprod(InhPaths * arginh, int nargs)
{
- int nanswers;
- Oid **result, **iter;
- Oid *oneres;
- int i, j;
- int cur[MAXFARGS];
-
- nanswers = 1;
- for (i = 0; i < nargs; i++) {
- nanswers *= (arginh[i].nsupers + 2);
- cur[i] = 0;
- }
-
- iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
-
- /* compute the cross product from right to left */
- for (;;) {
- oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid));
- memset(oneres, 0, MAXFARGS * sizeof(Oid));
-
- for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
- continue;
-
- /* if we're done, terminate with NULL pointer */
- if (i < 0) {
- *iter = NULL;
- return (result);
+ int nanswers;
+ Oid **result,
+ **iter;
+ Oid *oneres;
+ int i,
+ j;
+ int cur[MAXFARGS];
+
+ nanswers = 1;
+ for (i = 0; i < nargs; i++)
+ {
+ nanswers *= (arginh[i].nsupers + 2);
+ cur[i] = 0;
}
-
- /* no, increment this column and zero the ones after it */
- cur[i] = cur[i] + 1;
- for (j = nargs - 1; j > i; j--)
- cur[j] = 0;
-
- for (i = 0; i < nargs; i++) {
- if (cur[i] == 0)
- oneres[i] = arginh[i].self;
- else if (cur[i] > arginh[i].nsupers)
- oneres[i] = 0; /* wild card */
- else
- oneres[i] = arginh[i].supervec[cur[i] - 1];
+
+ iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers);
+
+ /* compute the cross product from right to left */
+ for (;;)
+ {
+ oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid));
+ memset(oneres, 0, MAXFARGS * sizeof(Oid));
+
+ for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--)
+ continue;
+
+ /* if we're done, terminate with NULL pointer */
+ if (i < 0)
+ {
+ *iter = NULL;
+ return (result);
+ }
+
+ /* no, increment this column and zero the ones after it */
+ cur[i] = cur[i] + 1;
+ for (j = nargs - 1; j > i; j--)
+ cur[j] = 0;
+
+ for (i = 0; i < nargs; i++)
+ {
+ if (cur[i] == 0)
+ oneres[i] = arginh[i].self;
+ else if (cur[i] > arginh[i].nsupers)
+ oneres[i] = 0; /* wild card */
+ else
+ oneres[i] = arginh[i].supervec[cur[i] - 1];
+ }
+
+ *iter++ = oneres;
}
-
- *iter++ = oneres;
- }
}
/* Given a type id, returns the in-conversion function of the type */
Oid
typeid_get_retinfunc(Oid type_id)
{
- HeapTuple typeTuple;
- TypeTupleForm type;
- Oid infunc;
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_id),
- 0,0,0);
- if ( !HeapTupleIsValid ( typeTuple ))
- elog(WARN,
- "typeid_get_retinfunc: Invalid type - oid = %u",
- type_id);
-
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
- infunc = type->typinput;
- return(infunc);
+ HeapTuple typeTuple;
+ TypeTupleForm type;
+ Oid infunc;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type_id),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(WARN,
+ "typeid_get_retinfunc: Invalid type - oid = %u",
+ type_id);
+
+ type = (TypeTupleForm) GETSTRUCT(typeTuple);
+ infunc = type->typinput;
+ return (infunc);
}
/* Given a type id, returns the out-conversion function of the type */
Oid
typeid_get_retoutfunc(Oid type_id)
{
- HeapTuple typeTuple;
- TypeTupleForm type;
- Oid outfunc;
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_id),
- 0,0,0);
- if ( !HeapTupleIsValid ( typeTuple ))
- elog(WARN,
- "typeid_get_retoutfunc: Invalid type - oid = %u",
- type_id);
-
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
- outfunc = type->typoutput;
- return(outfunc);
+ HeapTuple typeTuple;
+ TypeTupleForm type;
+ Oid outfunc;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type_id),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(WARN,
+ "typeid_get_retoutfunc: Invalid type - oid = %u",
+ type_id);
+
+ type = (TypeTupleForm) GETSTRUCT(typeTuple);
+ outfunc = type->typoutput;
+ return (outfunc);
}
Oid
typeid_get_relid(Oid type_id)
{
- HeapTuple typeTuple;
- TypeTupleForm type;
- Oid infunc;
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_id),
- 0,0,0);
- if ( !HeapTupleIsValid ( typeTuple ))
- elog(WARN, "typeid_get_relid: Invalid type - oid = %u ", type_id);
-
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
- infunc = type->typrelid;
- return(infunc);
+ HeapTuple typeTuple;
+ TypeTupleForm type;
+ Oid infunc;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type_id),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(typeTuple))
+ elog(WARN, "typeid_get_relid: Invalid type - oid = %u ", type_id);
+
+ type = (TypeTupleForm) GETSTRUCT(typeTuple);
+ infunc = type->typrelid;
+ return (infunc);
}
Oid
get_typrelid(Type typ)
{
- TypeTupleForm typtup;
-
- typtup = (TypeTupleForm) GETSTRUCT(typ);
-
- return (typtup->typrelid);
+ TypeTupleForm typtup;
+
+ typtup = (TypeTupleForm) GETSTRUCT(typ);
+
+ return (typtup->typrelid);
}
Oid
get_typelem(Oid type_id)
{
- HeapTuple typeTuple;
- TypeTupleForm type;
-
- if (!(typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_id),
- 0,0,0))) {
- elog (WARN , "type id lookup of %u failed", type_id);
- }
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
-
- return (type->typelem);
+ HeapTuple typeTuple;
+ TypeTupleForm type;
+
+ if (!(typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type_id),
+ 0, 0, 0)))
+ {
+ elog(WARN, "type id lookup of %u failed", type_id);
+ }
+ type = (TypeTupleForm) GETSTRUCT(typeTuple);
+
+ return (type->typelem);
}
#ifdef NOT_USED
char
FindDelimiter(char *typename)
{
- char delim;
- HeapTuple typeTuple;
- TypeTupleForm type;
-
-
- if (!(typeTuple = SearchSysCacheTuple(TYPNAME,
- PointerGetDatum(typename),
- 0,0,0))) {
- elog (WARN , "type name lookup of %s failed", typename);
- }
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
-
- delim = type->typdelim;
- return (delim);
+ char delim;
+ HeapTuple typeTuple;
+ TypeTupleForm type;
+
+
+ if (!(typeTuple = SearchSysCacheTuple(TYPNAME,
+ PointerGetDatum(typename),
+ 0, 0, 0)))
+ {
+ elog(WARN, "type name lookup of %s failed", typename);
+ }
+ type = (TypeTupleForm) GETSTRUCT(typeTuple);
+
+ delim = type->typdelim;
+ return (delim);
}
+
#endif
/*
@@ -1465,26 +1623,33 @@ FindDelimiter(char *typename)
static void
op_error(char *op, Oid arg1, Oid arg2)
{
- Type tp1 = NULL, tp2 = NULL;
-
- if (check_typeid(arg1)) {
- tp1 = get_id_type(arg1);
- } else {
- elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op);
- }
-
- if (check_typeid(arg2)) {
- tp2 = get_id_type(arg2);
- } else {
- elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op);
- }
-
- elog(NOTICE, "there is no operator %s for types %s and %s",
- op, tname(tp1),tname(tp2));
- elog(NOTICE, "You will either have to retype this query using an");
- elog(NOTICE, "explicit cast, or you will have to define the operator");
- elog(WARN, "%s for %s and %s using CREATE OPERATOR",
- op, tname(tp1),tname(tp2));
+ Type tp1 = NULL,
+ tp2 = NULL;
+
+ if (check_typeid(arg1))
+ {
+ tp1 = get_id_type(arg1);
+ }
+ else
+ {
+ elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op);
+ }
+
+ if (check_typeid(arg2))
+ {
+ tp2 = get_id_type(arg2);
+ }
+ else
+ {
+ elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op);
+ }
+
+ elog(NOTICE, "there is no operator %s for types %s and %s",
+ op, tname(tp1), tname(tp2));
+ elog(NOTICE, "You will either have to retype this query using an");
+ elog(NOTICE, "explicit cast, or you will have to define the operator");
+ elog(WARN, "%s for %s and %s using CREATE OPERATOR",
+ op, tname(tp1), tname(tp2));
}
/*
@@ -1492,27 +1657,32 @@ op_error(char *op, Oid arg1, Oid arg2)
* argument types
*/
void
-func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
+func_error(char *caller, char *funcname, int nargs, Oid * argtypes)
{
- char p[(NAMEDATALEN+2)*MAXFMGRARGS], *ptr;
- int i;
-
- ptr = p;
- *ptr = '\0';
- for (i=0; i<nargs; i++) {
- if (i) {
- *ptr++ = ',';
- *ptr++ = ' ';
+ char p[(NAMEDATALEN + 2) * MAXFMGRARGS],
+ *ptr;
+ int i;
+
+ ptr = p;
+ *ptr = '\0';
+ for (i = 0; i < nargs; i++)
+ {
+ if (i)
+ {
+ *ptr++ = ',';
+ *ptr++ = ' ';
+ }
+ if (argtypes[i] != 0)
+ {
+ strcpy(ptr, tname(get_id_type(argtypes[i])));
+ *(ptr + NAMEDATALEN) = '\0';
+ }
+ else
+ strcpy(ptr, "opaque");
+ ptr += strlen(ptr);
}
- if (argtypes[i] != 0) {
- strcpy(ptr, tname(get_id_type(argtypes[i])));
- *(ptr + NAMEDATALEN) = '\0';
- } else
- strcpy(ptr, "opaque");
- ptr += strlen(ptr);
- }
-
- elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p);
+
+ elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p);
}
/*
@@ -1522,12 +1692,19 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes)
void
agg_error(char *caller, char *aggname, Oid basetypeID)
{
- /* basetypeID that is Invalid (zero) means aggregate over all types. (count) */
-
- if (basetypeID == InvalidOid) {
- elog(WARN, "%s: aggregate '%s' for all types does not exist", caller, aggname);
- } else {
- elog(WARN, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
- tname(get_id_type(basetypeID)));
- }
+
+ /*
+ * basetypeID that is Invalid (zero) means aggregate over all types.
+ * (count)
+ */
+
+ if (basetypeID == InvalidOid)
+ {
+ elog(WARN, "%s: aggregate '%s' for all types does not exist", caller, aggname);
+ }
+ else
+ {
+ elog(WARN, "%s: aggregate '%s' for '%s' does not exist", caller, aggname,
+ tname(get_id_type(basetypeID)));
+ }
}
diff --git a/src/backend/parser/dbcommands.c b/src/backend/parser/dbcommands.c
index f975937b5ad..158e033b6e7 100644
--- a/src/backend/parser/dbcommands.c
+++ b/src/backend/parser/dbcommands.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* dbcommands.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/Attic/dbcommands.c,v 1.6 1997/08/19 21:32:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/Attic/dbcommands.c,v 1.7 1997/09/07 04:44:45 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,7 +16,7 @@
#include <signal.h>
#include "postgres.h"
-#include "miscadmin.h" /* for DataDir */
+#include "miscadmin.h" /* for DataDir */
#include "access/heapam.h"
#include "access/htup.h"
#include "access/relscan.h"
@@ -35,228 +35,253 @@
/* non-export function prototypes */
-static void check_permissions(char *command, char *dbname,
- Oid *dbIdP, Oid *userIdP);
+static void
+check_permissions(char *command, char *dbname,
+ Oid * dbIdP, Oid * userIdP);
static HeapTuple get_pg_dbtup(char *command, char *dbname, Relation dbrel);
-static void stop_vacuum(char *dbname);
+static void stop_vacuum(char *dbname);
void
createdb(char *dbname)
{
- Oid db_id, user_id;
- char buf[512];
-
- /*
- * If this call returns, the database does not exist and we're allowed
- * to create databases.
- */
- check_permissions("createdb", dbname, &db_id, &user_id);
-
- /* close virtual file descriptors so we can do system() calls */
- closeAllVfds();
-
- sprintf(buf, "mkdir %s%cbase%c%s", DataDir, SEP_CHAR, SEP_CHAR, dbname);
- system(buf);
- sprintf(buf, "%s %s%cbase%ctemplate1%c* %s%cbase%c%s",
- COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, DataDir,
- SEP_CHAR, SEP_CHAR, dbname);
- system(buf);
-
-/* sprintf(buf, "insert into pg_database (datname, datdba, datpath) \
+ Oid db_id,
+ user_id;
+ char buf[512];
+
+ /*
+ * If this call returns, the database does not exist and we're allowed
+ * to create databases.
+ */
+ check_permissions("createdb", dbname, &db_id, &user_id);
+
+ /* close virtual file descriptors so we can do system() calls */
+ closeAllVfds();
+
+ sprintf(buf, "mkdir %s%cbase%c%s", DataDir, SEP_CHAR, SEP_CHAR, dbname);
+ system(buf);
+ sprintf(buf, "%s %s%cbase%ctemplate1%c* %s%cbase%c%s",
+ COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, DataDir,
+ SEP_CHAR, SEP_CHAR, dbname);
+ system(buf);
+
+/* sprintf(buf, "insert into pg_database (datname, datdba, datpath) \
values (\'%s\'::char16, \'%d\'::oid, \'%s\'::text);",
- dbname, user_id, dbname);
+ dbname, user_id, dbname);
*/
- sprintf(buf, "insert into pg_database (datname, datdba, datpath) \
+ sprintf(buf, "insert into pg_database (datname, datdba, datpath) \
values (\'%s\', \'%d\', \'%s\');",
- dbname, user_id, dbname);
+ dbname, user_id, dbname);
- pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
+ pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
}
void
destroydb(char *dbname)
{
- Oid user_id, db_id;
- char buf[512];
-
- /*
- * If this call returns, the database exists and we're allowed to
- * remove it.
- */
- check_permissions("destroydb", dbname, &db_id, &user_id);
-
- if (!OidIsValid(db_id)) {
- elog(FATAL, "impossible: pg_database instance with invalid OID.");
- }
-
- /* stop the vacuum daemon */
- stop_vacuum(dbname);
-
- /* remove the pg_database tuple FIRST,
- this may fail due to permissions problems*/
- sprintf(buf, "delete from pg_database where pg_database.oid = \'%d\'::oid",
- db_id);
- pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
-
- /* remove the data directory. If the DELETE above failed, this will
- not be reached */
- sprintf(buf, "rm -r %s/base/%s", DataDir, dbname);
- system(buf);
-
- /* drop pages for this database that are in the shared buffer cache */
- DropBuffers(db_id);
+ Oid user_id,
+ db_id;
+ char buf[512];
+
+ /*
+ * If this call returns, the database exists and we're allowed to
+ * remove it.
+ */
+ check_permissions("destroydb", dbname, &db_id, &user_id);
+
+ if (!OidIsValid(db_id))
+ {
+ elog(FATAL, "impossible: pg_database instance with invalid OID.");
+ }
+
+ /* stop the vacuum daemon */
+ stop_vacuum(dbname);
+
+ /*
+ * remove the pg_database tuple FIRST, this may fail due to
+ * permissions problems
+ */
+ sprintf(buf, "delete from pg_database where pg_database.oid = \'%d\'::oid",
+ db_id);
+ pg_eval(buf, (char **) NULL, (Oid *) NULL, 0);
+
+ /*
+ * remove the data directory. If the DELETE above failed, this will
+ * not be reached
+ */
+ sprintf(buf, "rm -r %s/base/%s", DataDir, dbname);
+ system(buf);
+
+ /* drop pages for this database that are in the shared buffer cache */
+ DropBuffers(db_id);
}
-static HeapTuple
+static HeapTuple
get_pg_dbtup(char *command, char *dbname, Relation dbrel)
{
- HeapTuple dbtup;
- HeapTuple tup;
- Buffer buf;
- HeapScanDesc scan;
- ScanKeyData scanKey;
-
- ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
- NameEqualRegProcedure, NameGetDatum(dbname));
-
- scan = heap_beginscan(dbrel, 0, NowTimeQual, 1, &scanKey);
- if (!HeapScanIsValid(scan))
- elog(WARN, "%s: cannot begin scan of pg_database.", command);
-
- /*
- * since we want to return the tuple out of this proc, and we're
- * going to close the relation, copy the tuple and return the copy.
- */
- tup = heap_getnext(scan, 0, &buf);
-
- if (HeapTupleIsValid(tup)) {
- dbtup = heap_copytuple(tup);
- ReleaseBuffer(buf);
- } else
- dbtup = tup;
-
- heap_endscan(scan);
- return (dbtup);
+ HeapTuple dbtup;
+ HeapTuple tup;
+ Buffer buf;
+ HeapScanDesc scan;
+ ScanKeyData scanKey;
+
+ ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname,
+ NameEqualRegProcedure, NameGetDatum(dbname));
+
+ scan = heap_beginscan(dbrel, 0, NowTimeQual, 1, &scanKey);
+ if (!HeapScanIsValid(scan))
+ elog(WARN, "%s: cannot begin scan of pg_database.", command);
+
+ /*
+ * since we want to return the tuple out of this proc, and we're going
+ * to close the relation, copy the tuple and return the copy.
+ */
+ tup = heap_getnext(scan, 0, &buf);
+
+ if (HeapTupleIsValid(tup))
+ {
+ dbtup = heap_copytuple(tup);
+ ReleaseBuffer(buf);
+ }
+ else
+ dbtup = tup;
+
+ heap_endscan(scan);
+ return (dbtup);
}
/*
- * check_permissions() -- verify that the user is permitted to do this.
+ * check_permissions() -- verify that the user is permitted to do this.
*
- * If the user is not allowed to carry out this operation, this routine
- * elog(WARN, ...)s, which will abort the xact. As a side effect, the
- * user's pg_user tuple OID is returned in userIdP and the target database's
- * OID is returned in dbIdP.
+ * If the user is not allowed to carry out this operation, this routine
+ * elog(WARN, ...)s, which will abort the xact. As a side effect, the
+ * user's pg_user tuple OID is returned in userIdP and the target database's
+ * OID is returned in dbIdP.
*/
static void
check_permissions(char *command,
- char *dbname,
- Oid *dbIdP,
- Oid *userIdP)
+ char *dbname,
+ Oid * dbIdP,
+ Oid * userIdP)
{
- Relation dbrel;
- HeapTuple dbtup, utup;
- Oid dbowner = (Oid)0;
- char use_createdb;
- bool dbfound;
- bool use_super;
- char *userName;
-
- userName = GetPgUserName();
- utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
- 0,0,0);
- *userIdP = ((Form_pg_user)GETSTRUCT(utup))->usesysid;
- use_super = ((Form_pg_user)GETSTRUCT(utup))->usesuper;
- use_createdb = ((Form_pg_user)GETSTRUCT(utup))->usecreatedb;
-
- /* Check to make sure user has permission to use createdb */
- if (!use_createdb) {
- elog(WARN, "user \"%s\" is not allowed to create/destroy databases",
- userName);
- }
-
- /* Make sure we are not mucking with the template database */
- if (!strcmp(dbname, "template1")) {
- elog(WARN, "%s cannot be executed on the template database.", command);
- }
-
- /* Check to make sure database is not the currently open database */
- if (!strcmp(dbname, GetDatabaseName())) {
- elog(WARN, "%s cannot be executed on an open database", command);
- }
-
- /* Check to make sure database is owned by this user */
-
- /*
- * need the reldesc to get the database owner out of dbtup
- * and to set a write lock on it.
- */
- dbrel = heap_openr(DatabaseRelationName);
-
- if (!RelationIsValid(dbrel))
- elog(FATAL, "%s: cannot open relation \"%-.*s\"",
- command, DatabaseRelationName);
-
- /*
- * Acquire a write lock on pg_database from the beginning to avoid
- * upgrading a read lock to a write lock. Upgrading causes long delays
- * when multiple 'createdb's or 'destroydb's are run simult. -mer 7/3/91
- */
- RelationSetLockForWrite(dbrel);
- dbtup = get_pg_dbtup(command, dbname, dbrel);
- dbfound = HeapTupleIsValid(dbtup);
-
- if (dbfound) {
- dbowner = (Oid) heap_getattr(dbtup, InvalidBuffer,
- Anum_pg_database_datdba,
- RelationGetTupleDescriptor(dbrel),
- (char *) NULL);
- *dbIdP = dbtup->t_oid;
- } else {
- *dbIdP = InvalidOid;
- }
-
- heap_close(dbrel);
-
- /*
- * Now be sure that the user is allowed to do this.
- */
-
- if (dbfound && !strcmp(command, "createdb")) {
-
- elog(WARN, "createdb: database %s already exists.", dbname);
-
- } else if (!dbfound && !strcmp(command, "destroydb")) {
-
- elog(WARN, "destroydb: database %s does not exist.", dbname);
-
- } else if (dbfound && !strcmp(command, "destroydb")
- && dbowner != *userIdP && use_super == false) {
-
- elog(WARN, "%s: database %s is not owned by you.", command, dbname);
-
- }
+ Relation dbrel;
+ HeapTuple dbtup,
+ utup;
+ Oid dbowner = (Oid) 0;
+ char use_createdb;
+ bool dbfound;
+ bool use_super;
+ char *userName;
+
+ userName = GetPgUserName();
+ utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
+ 0, 0, 0);
+ *userIdP = ((Form_pg_user) GETSTRUCT(utup))->usesysid;
+ use_super = ((Form_pg_user) GETSTRUCT(utup))->usesuper;
+ use_createdb = ((Form_pg_user) GETSTRUCT(utup))->usecreatedb;
+
+ /* Check to make sure user has permission to use createdb */
+ if (!use_createdb)
+ {
+ elog(WARN, "user \"%s\" is not allowed to create/destroy databases",
+ userName);
+ }
+
+ /* Make sure we are not mucking with the template database */
+ if (!strcmp(dbname, "template1"))
+ {
+ elog(WARN, "%s cannot be executed on the template database.", command);
+ }
+
+ /* Check to make sure database is not the currently open database */
+ if (!strcmp(dbname, GetDatabaseName()))
+ {
+ elog(WARN, "%s cannot be executed on an open database", command);
+ }
+
+ /* Check to make sure database is owned by this user */
+
+ /*
+ * need the reldesc to get the database owner out of dbtup and to set
+ * a write lock on it.
+ */
+ dbrel = heap_openr(DatabaseRelationName);
+
+ if (!RelationIsValid(dbrel))
+ elog(FATAL, "%s: cannot open relation \"%-.*s\"",
+ command, DatabaseRelationName);
+
+ /*
+ * Acquire a write lock on pg_database from the beginning to avoid
+ * upgrading a read lock to a write lock. Upgrading causes long
+ * delays when multiple 'createdb's or 'destroydb's are run simult.
+ * -mer 7/3/91
+ */
+ RelationSetLockForWrite(dbrel);
+ dbtup = get_pg_dbtup(command, dbname, dbrel);
+ dbfound = HeapTupleIsValid(dbtup);
+
+ if (dbfound)
+ {
+ dbowner = (Oid) heap_getattr(dbtup, InvalidBuffer,
+ Anum_pg_database_datdba,
+ RelationGetTupleDescriptor(dbrel),
+ (char *) NULL);
+ *dbIdP = dbtup->t_oid;
+ }
+ else
+ {
+ *dbIdP = InvalidOid;
+ }
+
+ heap_close(dbrel);
+
+ /*
+ * Now be sure that the user is allowed to do this.
+ */
+
+ if (dbfound && !strcmp(command, "createdb"))
+ {
+
+ elog(WARN, "createdb: database %s already exists.", dbname);
+
+ }
+ else if (!dbfound && !strcmp(command, "destroydb"))
+ {
+
+ elog(WARN, "destroydb: database %s does not exist.", dbname);
+
+ }
+ else if (dbfound && !strcmp(command, "destroydb")
+ && dbowner != *userIdP && use_super == false)
+ {
+
+ elog(WARN, "%s: database %s is not owned by you.", command, dbname);
+
+ }
}
/*
- * stop_vacuum() -- stop the vacuum daemon on the database, if one is
- * running.
+ * stop_vacuum() -- stop the vacuum daemon on the database, if one is
+ * running.
*/
static void
stop_vacuum(char *dbname)
{
- char filename[256];
- FILE *fp;
- int pid;
-
- sprintf(filename, "%s%cbase%c%s%c%s.vacuum", DataDir, SEP_CHAR, SEP_CHAR,
- dbname, SEP_CHAR, dbname);
- if ((fp = AllocateFile(filename, "r")) != NULL) {
- fscanf(fp, "%d", &pid);
- FreeFile(fp);
- if (kill(pid, SIGKILLDAEMON1) < 0) {
- elog(WARN, "can't kill vacuum daemon (pid %d) on %s",
- pid, dbname);
+ char filename[256];
+ FILE *fp;
+ int pid;
+
+ sprintf(filename, "%s%cbase%c%s%c%s.vacuum", DataDir, SEP_CHAR, SEP_CHAR,
+ dbname, SEP_CHAR, dbname);
+ if ((fp = AllocateFile(filename, "r")) != NULL)
+ {
+ fscanf(fp, "%d", &pid);
+ FreeFile(fp);
+ if (kill(pid, SIGKILLDAEMON1) < 0)
+ {
+ elog(WARN, "can't kill vacuum daemon (pid %d) on %s",
+ pid, dbname);
+ }
}
- }
}
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 9aa6da82ca6..b9f1a273398 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* keywords.c--
- * lexical token lookup for reserved words in postgres SQL
+ * lexical token lookup for reserved words in postgres SQL
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.14 1997/09/04 13:24:26 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.15 1997/09/07 04:44:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,202 +20,204 @@
#include "parse.h"
#include "utils/elog.h"
#include "parser/keywords.h"
-#include "parser/dbcommands.h" /* createdb, destroydb stop_vacuum */
+#include "parser/dbcommands.h" /* createdb, destroydb stop_vacuum */
/*
* List of (keyword-name, keyword-token-value) pairs.
*
* !!WARNING!!: This list must be sorted, because binary
- * search is used to locate entries.
+ * search is used to locate entries.
*/
static ScanKeyword ScanKeywords[] = {
- /* name value */
- { "abort", ABORT_TRANS },
- { "acl", ACL },
- { "add", ADD },
- { "after", AFTER },
- { "aggregate", AGGREGATE },
- { "all", ALL },
- { "alter", ALTER },
- { "analyze", ANALYZE },
- { "and", AND },
- { "append", APPEND },
- { "archIve", ARCHIVE }, /* XXX crooked: I < _ */
- { "arch_store", ARCH_STORE },
- { "archive", ARCHIVE }, /* XXX crooked: i > _ */
- { "as", AS },
- { "asc", ASC },
- { "backward", BACKWARD },
- { "before", BEFORE },
- { "begin", BEGIN_TRANS },
- { "between", BETWEEN },
- { "binary", BINARY },
- { "both", BOTH },
- { "by", BY },
- { "cast", CAST },
- { "change", CHANGE },
- { "check", CHECK },
- { "close", CLOSE },
- { "cluster", CLUSTER },
- { "column", COLUMN },
- { "commit", COMMIT },
- { "constraint", CONSTRAINT },
- { "copy", COPY },
- { "create", CREATE },
- { "cross", CROSS },
- { "current", CURRENT },
- { "cursor", CURSOR },
- { "database", DATABASE },
- { "day", DAYINTERVAL },
- { "declare", DECLARE },
- { "default", DEFAULT },
- { "delete", DELETE },
- { "delimiters", DELIMITERS },
- { "desc", DESC },
- { "distinct", DISTINCT },
- { "do", DO },
- { "drop", DROP },
- { "end", END_TRANS },
- { "execute", EXECUTE },
- { "exists", EXISTS },
- { "explain", EXPLAIN },
- { "extend", EXTEND },
- { "extract", EXTRACT },
- { "fetch", FETCH },
- { "for", FOR },
- { "forward", FORWARD },
- { "from", FROM },
- { "full", FULL },
- { "function", FUNCTION },
- { "grant", GRANT },
- { "group", GROUP },
- { "having", HAVING },
- { "heavy", HEAVY },
- { "hour", HOURINTERVAL },
- { "in", IN },
- { "index", INDEX },
- { "inherits", INHERITS },
- { "inner", INNERJOIN },
- { "insert", INSERT },
- { "instead", INSTEAD },
- { "interval", INTERVAL },
- { "into", INTO },
- { "is", IS },
- { "isnull", ISNULL },
- { "join", JOIN },
- { "language", LANGUAGE },
- { "leading", LEADING },
- { "left", LEFT },
- { "light", LIGHT },
- { "like", LIKE },
- { "listen", LISTEN },
- { "load", LOAD },
- { "local", LOCAL },
- { "merge", MERGE },
- { "minute", MINUTEINTERVAL },
- { "month", MONTHINTERVAL },
- { "move", MOVE },
- { "natural", NATURAL },
- { "new", NEW },
- { "none", NONE },
- { "not", NOT },
- { "nothing", NOTHING },
- { "notify", NOTIFY },
- { "notnull", NOTNULL },
- { "null", PNULL },
- { "oids", OIDS },
- { "on", ON },
- { "operator", OPERATOR },
- { "option", OPTION },
- { "or", OR },
- { "order", ORDER },
- { "outer", OUTERJOIN },
- { "position", POSITION },
- { "privileges", PRIVILEGES },
- { "procedure", PROCEDURE },
- { "public", PUBLIC },
- { "purge", PURGE },
- { "recipe", RECIPE },
- { "rename", RENAME },
- { "replace", REPLACE },
- { "reset", RESET },
- { "retrieve", RETRIEVE },
- { "returns", RETURNS },
- { "revoke", REVOKE },
- { "right", RIGHT },
- { "rollback", ROLLBACK },
- { "rule", RULE },
- { "second", SECONDINTERVAL },
- { "select", SELECT },
- { "sequence", SEQUENCE },
- { "set", SET },
- { "setof", SETOF },
- { "show", SHOW },
- { "stdin", STDIN },
- { "stdout", STDOUT },
- { "store", STORE },
- { "substring", SUBSTRING },
- { "table", TABLE },
- { "time", TIME },
- { "to", TO },
- { "transaction", TRANSACTION },
- { "trailing", TRAILING },
- { "trigger", TRIGGER },
- { "trim", TRIM },
- { "type", P_TYPE },
- { "union", UNION },
- { "unique", UNIQUE },
- { "update", UPDATE },
- { "using", USING },
- { "vacuum", VACUUM },
- { "values", VALUES },
- { "verbose", VERBOSE },
- { "version", VERSION },
- { "view", VIEW },
- { "where", WHERE },
- { "with", WITH },
- { "work", WORK },
- { "year", YEARINTERVAL },
- { "zone", ZONE },
+ /* name value */
+ {"abort", ABORT_TRANS},
+ {"acl", ACL},
+ {"add", ADD},
+ {"after", AFTER},
+ {"aggregate", AGGREGATE},
+ {"all", ALL},
+ {"alter", ALTER},
+ {"analyze", ANALYZE},
+ {"and", AND},
+ {"append", APPEND},
+ {"archIve", ARCHIVE}, /* XXX crooked: I < _ */
+ {"arch_store", ARCH_STORE},
+ {"archive", ARCHIVE}, /* XXX crooked: i > _ */
+ {"as", AS},
+ {"asc", ASC},
+ {"backward", BACKWARD},
+ {"before", BEFORE},
+ {"begin", BEGIN_TRANS},
+ {"between", BETWEEN},
+ {"binary", BINARY},
+ {"both", BOTH},
+ {"by", BY},
+ {"cast", CAST},
+ {"change", CHANGE},
+ {"check", CHECK},
+ {"close", CLOSE},
+ {"cluster", CLUSTER},
+ {"column", COLUMN},
+ {"commit", COMMIT},
+ {"constraint", CONSTRAINT},
+ {"copy", COPY},
+ {"create", CREATE},
+ {"cross", CROSS},
+ {"current", CURRENT},
+ {"cursor", CURSOR},
+ {"database", DATABASE},
+ {"day", DAYINTERVAL},
+ {"declare", DECLARE},
+ {"default", DEFAULT},
+ {"delete", DELETE},
+ {"delimiters", DELIMITERS},
+ {"desc", DESC},
+ {"distinct", DISTINCT},
+ {"do", DO},
+ {"drop", DROP},
+ {"end", END_TRANS},
+ {"execute", EXECUTE},
+ {"exists", EXISTS},
+ {"explain", EXPLAIN},
+ {"extend", EXTEND},
+ {"extract", EXTRACT},
+ {"fetch", FETCH},
+ {"for", FOR},
+ {"forward", FORWARD},
+ {"from", FROM},
+ {"full", FULL},
+ {"function", FUNCTION},
+ {"grant", GRANT},
+ {"group", GROUP},
+ {"having", HAVING},
+ {"heavy", HEAVY},
+ {"hour", HOURINTERVAL},
+ {"in", IN},
+ {"index", INDEX},
+ {"inherits", INHERITS},
+ {"inner", INNERJOIN},
+ {"insert", INSERT},
+ {"instead", INSTEAD},
+ {"interval", INTERVAL},
+ {"into", INTO},
+ {"is", IS},
+ {"isnull", ISNULL},
+ {"join", JOIN},
+ {"language", LANGUAGE},
+ {"leading", LEADING},
+ {"left", LEFT},
+ {"light", LIGHT},
+ {"like", LIKE},
+ {"listen", LISTEN},
+ {"load", LOAD},
+ {"local", LOCAL},
+ {"merge", MERGE},
+ {"minute", MINUTEINTERVAL},
+ {"month", MONTHINTERVAL},
+ {"move", MOVE},
+ {"natural", NATURAL},
+ {"new", NEW},
+ {"none", NONE},
+ {"not", NOT},
+ {"nothing", NOTHING},
+ {"notify", NOTIFY},
+ {"notnull", NOTNULL},
+ {"null", PNULL},
+ {"oids", OIDS},
+ {"on", ON},
+ {"operator", OPERATOR},
+ {"option", OPTION},
+ {"or", OR},
+ {"order", ORDER},
+ {"outer", OUTERJOIN},
+ {"position", POSITION},
+ {"privileges", PRIVILEGES},
+ {"procedure", PROCEDURE},
+ {"public", PUBLIC},
+ {"purge", PURGE},
+ {"recipe", RECIPE},
+ {"rename", RENAME},
+ {"replace", REPLACE},
+ {"reset", RESET},
+ {"retrieve", RETRIEVE},
+ {"returns", RETURNS},
+ {"revoke", REVOKE},
+ {"right", RIGHT},
+ {"rollback", ROLLBACK},
+ {"rule", RULE},
+ {"second", SECONDINTERVAL},
+ {"select", SELECT},
+ {"sequence", SEQUENCE},
+ {"set", SET},
+ {"setof", SETOF},
+ {"show", SHOW},
+ {"stdin", STDIN},
+ {"stdout", STDOUT},
+ {"store", STORE},
+ {"substring", SUBSTRING},
+ {"table", TABLE},
+ {"time", TIME},
+ {"to", TO},
+ {"transaction", TRANSACTION},
+ {"trailing", TRAILING},
+ {"trigger", TRIGGER},
+ {"trim", TRIM},
+ {"type", P_TYPE},
+ {"union", UNION},
+ {"unique", UNIQUE},
+ {"update", UPDATE},
+ {"using", USING},
+ {"vacuum", VACUUM},
+ {"values", VALUES},
+ {"verbose", VERBOSE},
+ {"version", VERSION},
+ {"view", VIEW},
+ {"where", WHERE},
+ {"with", WITH},
+ {"work", WORK},
+ {"year", YEARINTERVAL},
+ {"zone", ZONE},
};
-ScanKeyword *
+ScanKeyword *
ScanKeywordLookup(char *text)
{
- ScanKeyword *low = &ScanKeywords[0];
- ScanKeyword *high = endof(ScanKeywords) - 1;
- ScanKeyword *middle;
- int difference;
-
- while (low <= high) {
- middle = low + (high - low) / 2;
- difference = strcmp(middle->name, text);
- if (difference == 0)
- return (middle);
- else if (difference < 0)
- low = middle + 1;
- else
- high = middle - 1;
- }
-
- return (NULL);
+ ScanKeyword *low = &ScanKeywords[0];
+ ScanKeyword *high = endof(ScanKeywords) - 1;
+ ScanKeyword *middle;
+ int difference;
+
+ while (low <= high)
+ {
+ middle = low + (high - low) / 2;
+ difference = strcmp(middle->name, text);
+ if (difference == 0)
+ return (middle);
+ else if (difference < 0)
+ low = middle + 1;
+ else
+ high = middle - 1;
+ }
+
+ return (NULL);
}
#ifdef NOT_USED
-char*
+char *
AtomValueGetString(int atomval)
{
- ScanKeyword *low = &ScanKeywords[0];
- ScanKeyword *high = endof(ScanKeywords) - 1;
- int keyword_list_length = (high-low);
- int i;
-
- for (i=0; i < keyword_list_length ; i++ )
- if (ScanKeywords[i].value == atomval )
- return(ScanKeywords[i].name);
-
- elog(WARN,"AtomGetString called with bogus atom # : %d", atomval );
- return(NULL);
+ ScanKeyword *low = &ScanKeywords[0];
+ ScanKeyword *high = endof(ScanKeywords) - 1;
+ int keyword_list_length = (high - low);
+ int i;
+
+ for (i = 0; i < keyword_list_length; i++)
+ if (ScanKeywords[i].value == atomval)
+ return (ScanKeywords[i].name);
+
+ elog(WARN, "AtomGetString called with bogus atom # : %d", atomval);
+ return (NULL);
}
+
#endif
diff --git a/src/backend/parser/parse_query.c b/src/backend/parser/parse_query.c
index b19b291769f..5d144660a48 100644
--- a/src/backend/parser/parse_query.c
+++ b/src/backend/parser/parse_query.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* parse_query.c--
- * take an "optimizable" stmt and make the query tree that
- * the planner requires.
+ * take an "optimizable" stmt and make the query tree that
+ * the planner requires.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.18 1997/08/22 00:02:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.19 1997/09/07 04:44:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,8 +23,8 @@
#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/palloc.h"
-#include "utils/acl.h" /* for ACL_NO_PRIV_WARNING */
-#include "utils/rel.h" /* Relation stuff */
+#include "utils/acl.h" /* for ACL_NO_PRIV_WARNING */
+#include "utils/rel.h" /* Relation stuff */
#include "utils/syscache.h"
#include "catalog/pg_type.h"
@@ -38,680 +38,744 @@
#include "nodes/parsenodes.h"
#include "nodes/makefuncs.h"
-static void checkTargetTypes(ParseState *pstate, char *target_colname,
- char *refname, char *colname);
+static void
+checkTargetTypes(ParseState * pstate, char *target_colname,
+ char *refname, char *colname);
-Oid *param_type_info;
-int pfunc_num_args;
+Oid *param_type_info;
+int pfunc_num_args;
/* given refname, return a pointer to the range table entry */
-RangeTblEntry *
-refnameRangeTableEntry(List *rtable, char *refname)
+RangeTblEntry *
+refnameRangeTableEntry(List * rtable, char *refname)
{
- List *temp;
-
- foreach(temp, rtable) {
- RangeTblEntry *rte = lfirst(temp);
-
- if (!strcmp(rte->refname, refname))
- return rte;
- }
- return NULL;
+ List *temp;
+
+ foreach(temp, rtable)
+ {
+ RangeTblEntry *rte = lfirst(temp);
+
+ if (!strcmp(rte->refname, refname))
+ return rte;
+ }
+ return NULL;
}
/* given refname, return id of variable; position starts with 1 */
int
-refnameRangeTablePosn(List *rtable, char *refname)
+refnameRangeTablePosn(List * rtable, char *refname)
{
- int index;
- List *temp;
-
- index = 1;
- foreach(temp, rtable) {
- RangeTblEntry *rte = lfirst(temp);
-
- if (!strcmp(rte->refname, refname))
- return index;
- index++;
- }
- return(0);
+ int index;
+ List *temp;
+
+ index = 1;
+ foreach(temp, rtable)
+ {
+ RangeTblEntry *rte = lfirst(temp);
+
+ if (!strcmp(rte->refname, refname))
+ return index;
+ index++;
+ }
+ return (0);
}
/*
* returns range entry if found, else NULL
*/
-RangeTblEntry *
-colnameRangeTableEntry(ParseState *pstate, char *colname)
+RangeTblEntry *
+colnameRangeTableEntry(ParseState * pstate, char *colname)
{
- List *et;
- List *rtable;
- RangeTblEntry *rte_result;
+ List *et;
+ List *rtable;
+ RangeTblEntry *rte_result;
- if (pstate->p_is_rule)
- rtable = lnext(lnext(pstate->p_rtable));
- else
- rtable = pstate->p_rtable;
+ if (pstate->p_is_rule)
+ rtable = lnext(lnext(pstate->p_rtable));
+ else
+ rtable = pstate->p_rtable;
- rte_result = NULL;
- foreach(et, rtable) {
- RangeTblEntry *rte = lfirst(et);
+ rte_result = NULL;
+ foreach(et, rtable)
+ {
+ RangeTblEntry *rte = lfirst(et);
/* only entries on outer(non-function?) scope */
- if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
- continue;
-
- if (get_attnum(rte->relid, colname) != InvalidAttrNumber) {
- if (rte_result != NULL) {
- if (!pstate->p_is_insert ||
- rte != pstate->p_target_rangetblentry)
- elog(WARN, "Column %s is ambiguous", colname);
- }
- else rte_result = rte;
+ if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
+ continue;
+
+ if (get_attnum(rte->relid, colname) != InvalidAttrNumber)
+ {
+ if (rte_result != NULL)
+ {
+ if (!pstate->p_is_insert ||
+ rte != pstate->p_target_rangetblentry)
+ elog(WARN, "Column %s is ambiguous", colname);
+ }
+ else
+ rte_result = rte;
+ }
}
- }
- return rte_result;
+ return rte_result;
}
/*
* put new entry in pstate p_rtable structure, or return pointer
* if pstate null
*/
-RangeTblEntry *
-addRangeTableEntry(ParseState *pstate,
- char *relname,
- char *refname,
- bool inh, bool inFromCl,
- TimeRange *timeRange)
+RangeTblEntry *
+addRangeTableEntry(ParseState * pstate,
+ char *relname,
+ char *refname,
+ bool inh, bool inFromCl,
+ TimeRange * timeRange)
{
- Relation relation;
- RangeTblEntry *rte = makeNode(RangeTblEntry);
-
- if (pstate != NULL &&
- refnameRangeTableEntry(pstate->p_rtable, refname) != NULL)
- elog(WARN,"Table name %s specified more than once",refname);
-
- rte->relname = pstrdup(relname);
- rte->refname = pstrdup(refname);
-
- relation = heap_openr(relname);
- if (relation == NULL) {
- elog(WARN,"%s: %s",
- relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]);
- }
-
- /*
- * Flags - zero or more from archive,inheritance,union,version
- * or recursive (transitive closure)
- * [we don't support them all -- ay 9/94 ]
- */
- rte->inh = inh;
-
- rte->timeRange = timeRange;
-
- /* RelOID */
- rte->relid = RelationGetRelationId(relation);
-
- rte->archive = false;
-
- rte->inFromCl = inFromCl;
-
- /*
- * close the relation we're done with it for now.
- */
- if (pstate != NULL)
- pstate->p_rtable = lappend(pstate->p_rtable, rte);
-
- heap_close(relation);
-
- return rte;
+ Relation relation;
+ RangeTblEntry *rte = makeNode(RangeTblEntry);
+
+ if (pstate != NULL &&
+ refnameRangeTableEntry(pstate->p_rtable, refname) != NULL)
+ elog(WARN, "Table name %s specified more than once", refname);
+
+ rte->relname = pstrdup(relname);
+ rte->refname = pstrdup(refname);
+
+ relation = heap_openr(relname);
+ if (relation == NULL)
+ {
+ elog(WARN, "%s: %s",
+ relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]);
+ }
+
+ /*
+ * Flags - zero or more from archive,inheritance,union,version or
+ * recursive (transitive closure) [we don't support them all -- ay
+ * 9/94 ]
+ */
+ rte->inh = inh;
+
+ rte->timeRange = timeRange;
+
+ /* RelOID */
+ rte->relid = RelationGetRelationId(relation);
+
+ rte->archive = false;
+
+ rte->inFromCl = inFromCl;
+
+ /*
+ * close the relation we're done with it for now.
+ */
+ if (pstate != NULL)
+ pstate->p_rtable = lappend(pstate->p_rtable, rte);
+
+ heap_close(relation);
+
+ return rte;
}
/*
* expandAll -
- * makes a list of attributes
- * assumes reldesc caching works
+ * makes a list of attributes
+ * assumes reldesc caching works
*/
-List *
-expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
+List *
+expandAll(ParseState * pstate, char *relname, char *refname, int *this_resno)
{
- Relation rdesc;
- List *te_tail = NIL, *te_head = NIL;
- Var *varnode;
- int varattno, maxattrs;
- Oid type_id;
- int type_len;
- RangeTblEntry *rte;
-
- rte = refnameRangeTableEntry(pstate->p_rtable, refname);
- if (rte == NULL)
- rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE, NULL);
-
- rdesc = heap_open(rte->relid);
-
- if (rdesc == NULL ) {
- elog(WARN,"Unable to expand all -- heap_open failed on %s",
- rte->refname);
- return NIL;
- }
- maxattrs = RelationGetNumberOfAttributes(rdesc);
-
- for ( varattno = 0; varattno <= maxattrs-1 ; varattno++ ) {
- char *attrname;
- char *resname = NULL;
- TargetEntry *te = makeNode(TargetEntry);
-
- attrname = pstrdup ((rdesc->rd_att->attrs[varattno]->attname).data);
- varnode = (Var*)make_var(pstate, refname, attrname, &type_id);
- type_len = (int)tlen(get_id_type(type_id));
-
- handleTargetColname(pstate, &resname, refname, attrname);
- if (resname != NULL)
- attrname = resname;
-
- /* Even if the elements making up a set are complex, the
- * set itself is not. */
-
- te->resdom = makeResdom((AttrNumber) (*this_resno)++,
- type_id,
- (Size)type_len,
- attrname,
- (Index)0,
- (Oid)0,
- 0);
- te->expr = (Node *)varnode;
- if (te_head == NIL)
- te_head = te_tail = lcons(te, NIL);
- else te_tail = lappend(te_tail, te);
- }
-
- heap_close(rdesc);
- return(te_head);
+ Relation rdesc;
+ List *te_tail = NIL,
+ *te_head = NIL;
+ Var *varnode;
+ int varattno,
+ maxattrs;
+ Oid type_id;
+ int type_len;
+ RangeTblEntry *rte;
+
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE, NULL);
+
+ rdesc = heap_open(rte->relid);
+
+ if (rdesc == NULL)
+ {
+ elog(WARN, "Unable to expand all -- heap_open failed on %s",
+ rte->refname);
+ return NIL;
+ }
+ maxattrs = RelationGetNumberOfAttributes(rdesc);
+
+ for (varattno = 0; varattno <= maxattrs - 1; varattno++)
+ {
+ char *attrname;
+ char *resname = NULL;
+ TargetEntry *te = makeNode(TargetEntry);
+
+ attrname = pstrdup((rdesc->rd_att->attrs[varattno]->attname).data);
+ varnode = (Var *) make_var(pstate, refname, attrname, &type_id);
+ type_len = (int) tlen(get_id_type(type_id));
+
+ handleTargetColname(pstate, &resname, refname, attrname);
+ if (resname != NULL)
+ attrname = resname;
+
+ /*
+ * Even if the elements making up a set are complex, the set
+ * itself is not.
+ */
+
+ te->resdom = makeResdom((AttrNumber) (*this_resno)++,
+ type_id,
+ (Size) type_len,
+ attrname,
+ (Index) 0,
+ (Oid) 0,
+ 0);
+ te->expr = (Node *) varnode;
+ if (te_head == NIL)
+ te_head = te_tail = lcons(te, NIL);
+ else
+ te_tail = lappend(te_tail, te);
+ }
+
+ heap_close(rdesc);
+ return (te_head);
}
TimeQual
makeTimeRange(char *datestring1,
- char *datestring2,
- int timecode) /* 0 = snapshot , 1 = timerange */
+ char *datestring2,
+ int timecode) /* 0 = snapshot , 1 = timerange */
{
- TimeQual qual = NULL;
- AbsoluteTime t1,t2;
-
- switch (timecode) {
- case 0:
- if (datestring1 == NULL) {
- elog(WARN, "MakeTimeRange: bad snapshot arg");
- }
- t1 = nabstimein(datestring1);
- if (!AbsoluteTimeIsValid(t1)) {
- elog(WARN, "bad snapshot time: \"%s\"",
- datestring1);
- }
- qual = TimeFormSnapshotTimeQual(t1);
- break;
- case 1:
- if (datestring1 == NULL) {
- t1 = NOSTART_ABSTIME;
- } else {
- t1 = nabstimein(datestring1);
- if (!AbsoluteTimeIsValid(t1)) {
- elog(WARN,
- "bad range start time: \"%s\"",
- datestring1);
- }
- }
- if (datestring2 == NULL) {
- t2 = NOEND_ABSTIME;
- } else {
- t2 = nabstimein(datestring2);
- if (!AbsoluteTimeIsValid(t2)) {
- elog(WARN,
- "bad range end time: \"%s\"",
- datestring2);
- }
+ TimeQual qual = NULL;
+ AbsoluteTime t1,
+ t2;
+
+ switch (timecode)
+ {
+ case 0:
+ if (datestring1 == NULL)
+ {
+ elog(WARN, "MakeTimeRange: bad snapshot arg");
+ }
+ t1 = nabstimein(datestring1);
+ if (!AbsoluteTimeIsValid(t1))
+ {
+ elog(WARN, "bad snapshot time: \"%s\"",
+ datestring1);
+ }
+ qual = TimeFormSnapshotTimeQual(t1);
+ break;
+ case 1:
+ if (datestring1 == NULL)
+ {
+ t1 = NOSTART_ABSTIME;
+ }
+ else
+ {
+ t1 = nabstimein(datestring1);
+ if (!AbsoluteTimeIsValid(t1))
+ {
+ elog(WARN,
+ "bad range start time: \"%s\"",
+ datestring1);
+ }
+ }
+ if (datestring2 == NULL)
+ {
+ t2 = NOEND_ABSTIME;
+ }
+ else
+ {
+ t2 = nabstimein(datestring2);
+ if (!AbsoluteTimeIsValid(t2))
+ {
+ elog(WARN,
+ "bad range end time: \"%s\"",
+ datestring2);
+ }
+ }
+ qual = TimeFormRangedTimeQual(t1, t2);
+ break;
+ default:
+ elog(WARN, "MakeTimeRange: internal parser error");
}
- qual = TimeFormRangedTimeQual(t1,t2);
- break;
- default:
- elog(WARN, "MakeTimeRange: internal parser error");
- }
- return qual;
+ return qual;
}
static void
-disallow_setop(char *op, Type optype, Node *operand)
+disallow_setop(char *op, Type optype, Node * operand)
{
- if (operand==NULL)
- return;
-
- if (nodeTag(operand) == T_Iter) {
- elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
- op, tname(optype));
- elog(WARN, "but '%s' takes single values, not sets.",
- op);
- }
+ if (operand == NULL)
+ return;
+
+ if (nodeTag(operand) == T_Iter)
+ {
+ elog(NOTICE, "An operand to the '%s' operator returns a set of %s,",
+ op, tname(optype));
+ elog(WARN, "but '%s' takes single values, not sets.",
+ op);
+ }
}
-static Node *
+static Node *
make_operand(char *opname,
- Node *tree,
- Oid orig_typeId,
- Oid true_typeId)
+ Node * tree,
+ Oid orig_typeId,
+ Oid true_typeId)
{
- Node *result;
- Type true_type;
- Datum val;
- Oid infunc;
-
- if (tree != NULL) {
- result = tree;
- true_type = get_id_type(true_typeId);
- disallow_setop(opname, true_type, result);
- if (true_typeId != orig_typeId) { /* must coerce */
- Const *con= (Const *)result;
-
- Assert(nodeTag(result)==T_Const);
- val = (Datum)textout((struct varlena *)
- con->constvalue);
- infunc = typeid_get_retinfunc(true_typeId);
- con = makeNode(Const);
- con->consttype = true_typeId;
- con->constlen = tlen(true_type);
- con->constvalue = (Datum)fmgr(infunc,
- val,
- get_typelem(true_typeId),
- -1 /* for varchar() type */);
- con->constisnull = false;
- con->constbyval = true;
- con->constisset = false;
- result = (Node *)con;
+ Node *result;
+ Type true_type;
+ Datum val;
+ Oid infunc;
+
+ if (tree != NULL)
+ {
+ result = tree;
+ true_type = get_id_type(true_typeId);
+ disallow_setop(opname, true_type, result);
+ if (true_typeId != orig_typeId)
+ { /* must coerce */
+ Const *con = (Const *) result;
+
+ Assert(nodeTag(result) == T_Const);
+ val = (Datum) textout((struct varlena *)
+ con->constvalue);
+ infunc = typeid_get_retinfunc(true_typeId);
+ con = makeNode(Const);
+ con->consttype = true_typeId;
+ con->constlen = tlen(true_type);
+ con->constvalue = (Datum) fmgr(infunc,
+ val,
+ get_typelem(true_typeId),
+ -1 /* for varchar() type */ );
+ con->constisnull = false;
+ con->constbyval = true;
+ con->constisset = false;
+ result = (Node *) con;
+ }
+ }
+ else
+ {
+ Const *con = makeNode(Const);
+
+ con->consttype = true_typeId;
+ con->constlen = 0;
+ con->constvalue = (Datum) (struct varlena *) NULL;
+ con->constisnull = true;
+ con->constbyval = true;
+ con->constisset = false;
+ result = (Node *) con;
}
- }else {
- Const *con= makeNode(Const);
-
- con->consttype = true_typeId;
- con->constlen = 0;
- con->constvalue = (Datum)(struct varlena *)NULL;
- con->constisnull = true;
- con->constbyval = true;
- con->constisset = false;
- result = (Node *)con;
- }
-
- return result;
+
+ return result;
}
-Expr *
-make_op(char *opname, Node *ltree, Node *rtree)
+Expr *
+make_op(char *opname, Node * ltree, Node * rtree)
{
- Oid ltypeId, rtypeId;
- Operator temp;
- OperatorTupleForm opform;
- Oper *newop;
- Node *left, *right;
- Expr *result;
-
- if (rtree == NULL) {
-
- /* right operator */
- ltypeId = (ltree==NULL) ? UNKNOWNOID : exprType(ltree);
- temp = right_oper(opname, ltypeId);
- opform = (OperatorTupleForm) GETSTRUCT(temp);
- left = make_operand(opname, ltree, ltypeId, opform->oprleft);
- right = NULL;
-
- }else if (ltree == NULL) {
-
- /* left operator */
- rtypeId = (rtree==NULL) ? UNKNOWNOID : exprType(rtree);
- temp = left_oper(opname, rtypeId);
- opform = (OperatorTupleForm) GETSTRUCT(temp);
- right = make_operand(opname, rtree, rtypeId, opform->oprright);
- left = NULL;
-
- }else {
- char *outstr;
- Oid infunc, outfunc;
- Type newtype;
+ Oid ltypeId,
+ rtypeId;
+ Operator temp;
+ OperatorTupleForm opform;
+ Oper *newop;
+ Node *left,
+ *right;
+ Expr *result;
+
+ if (rtree == NULL)
+ {
+
+ /* right operator */
+ ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
+ temp = right_oper(opname, ltypeId);
+ opform = (OperatorTupleForm) GETSTRUCT(temp);
+ left = make_operand(opname, ltree, ltypeId, opform->oprleft);
+ right = NULL;
+
+ }
+ else if (ltree == NULL)
+ {
+
+ /* left operator */
+ rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
+ temp = left_oper(opname, rtypeId);
+ opform = (OperatorTupleForm) GETSTRUCT(temp);
+ right = make_operand(opname, rtree, rtypeId, opform->oprright);
+ left = NULL;
+
+ }
+ else
+ {
+ char *outstr;
+ Oid infunc,
+ outfunc;
+ Type newtype;
#define CONVERTABLE_TYPE(t) ( (t) == INT2OID || \
- (t) == INT4OID || \
- (t) == OIDOID || \
- (t) == FLOAT4OID || \
- (t) == FLOAT8OID || \
- (t) == CASHOID)
-
- /* binary operator */
- ltypeId = (ltree==NULL) ? UNKNOWNOID : exprType(ltree);
- rtypeId = (rtree==NULL) ? UNKNOWNOID : exprType(rtree);
-
- /* convert constant when using a const of a numeric type
- and a non-const of another numeric type */
- if (CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const &&
- CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
- !((Const *)rtree)->constiscast) {
- outfunc = typeid_get_retoutfunc(rtypeId);
- infunc = typeid_get_retinfunc(ltypeId);
- outstr = (char *)fmgr(outfunc, ((Const *)rtree)->constvalue);
- ((Const *)rtree)->constvalue = (Datum)fmgr(infunc, outstr);
- pfree(outstr);
- ((Const *)rtree)->consttype = rtypeId = ltypeId;
- newtype = get_id_type(rtypeId);
- ((Const *)rtree)->constlen = tlen(newtype);
- ((Const *)rtree)->constbyval = tbyval(newtype);
+ (t) == INT4OID || \
+ (t) == OIDOID || \
+ (t) == FLOAT4OID || \
+ (t) == FLOAT8OID || \
+ (t) == CASHOID)
+
+ /* binary operator */
+ ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree);
+ rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree);
+
+ /*
+ * convert constant when using a const of a numeric type and a
+ * non-const of another numeric type
+ */
+ if (CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const &&
+ CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const &&
+ !((Const *) rtree)->constiscast)
+ {
+ outfunc = typeid_get_retoutfunc(rtypeId);
+ infunc = typeid_get_retinfunc(ltypeId);
+ outstr = (char *) fmgr(outfunc, ((Const *) rtree)->constvalue);
+ ((Const *) rtree)->constvalue = (Datum) fmgr(infunc, outstr);
+ pfree(outstr);
+ ((Const *) rtree)->consttype = rtypeId = ltypeId;
+ newtype = get_id_type(rtypeId);
+ ((Const *) rtree)->constlen = tlen(newtype);
+ ((Const *) rtree)->constbyval = tbyval(newtype);
+ }
+
+ if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
+ CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
+ !((Const *) ltree)->constiscast)
+ {
+ outfunc = typeid_get_retoutfunc(ltypeId);
+ infunc = typeid_get_retinfunc(rtypeId);
+ outstr = (char *) fmgr(outfunc, ((Const *) ltree)->constvalue);
+ ((Const *) ltree)->constvalue = (Datum) fmgr(infunc, outstr);
+ pfree(outstr);
+ ((Const *) ltree)->consttype = ltypeId = rtypeId;
+ newtype = get_id_type(ltypeId);
+ ((Const *) ltree)->constlen = tlen(newtype);
+ ((Const *) ltree)->constbyval = tbyval(newtype);
+ }
+
+ temp = oper(opname, ltypeId, rtypeId, false);
+ opform = (OperatorTupleForm) GETSTRUCT(temp);
+ left = make_operand(opname, ltree, ltypeId, opform->oprleft);
+ right = make_operand(opname, rtree, rtypeId, opform->oprright);
}
- if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const &&
- CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const &&
- !((Const *)ltree)->constiscast) {
- outfunc = typeid_get_retoutfunc(ltypeId);
- infunc = typeid_get_retinfunc(rtypeId);
- outstr = (char *)fmgr(outfunc, ((Const *)ltree)->constvalue);
- ((Const *)ltree)->constvalue = (Datum)fmgr(infunc, outstr);
- pfree(outstr);
- ((Const *)ltree)->consttype = ltypeId = rtypeId;
- newtype = get_id_type(ltypeId);
- ((Const *)ltree)->constlen = tlen(newtype);
- ((Const *)ltree)->constbyval = tbyval(newtype);
+ newop = makeOper(oprid(temp), /* opno */
+ InvalidOid,/* opid */
+ opform->oprresult, /* operator result type */
+ 0,
+ NULL);
+
+ result = makeNode(Expr);
+ result->typeOid = opform->oprresult;
+ result->opType = OP_EXPR;
+ result->oper = (Node *) newop;
+
+ if (!left)
+ {
+ result->args = lcons(right, NIL);
+ }
+ else if (!right)
+ {
+ result->args = lcons(left, NIL);
+ }
+ else
+ {
+ result->args = lcons(left, lcons(right, NIL));
}
- temp = oper(opname, ltypeId, rtypeId, false);
- opform = (OperatorTupleForm) GETSTRUCT(temp);
- left = make_operand(opname, ltree, ltypeId, opform->oprleft);
- right = make_operand(opname, rtree, rtypeId, opform->oprright);
- }
-
- newop = makeOper(oprid(temp), /* opno */
- InvalidOid, /* opid */
- opform->oprresult, /* operator result type */
- 0,
- NULL);
-
- result = makeNode(Expr);
- result->typeOid = opform->oprresult;
- result->opType = OP_EXPR;
- result->oper = (Node *)newop;
-
- if (!left) {
- result->args = lcons(right, NIL);
- } else if (!right) {
- result->args = lcons(left, NIL);
- } else {
- result->args = lcons(left, lcons(right, NIL));
- }
-
- return result;
+ return result;
}
Oid
find_atttype(Oid relid, char *attrname)
{
- int attid;
- Oid vartype;
- Relation rd;
-
- rd = heap_open(relid);
- if (!RelationIsValid(rd)) {
- rd = heap_openr(tname(get_id_type(relid)));
+ int attid;
+ Oid vartype;
+ Relation rd;
+
+ rd = heap_open(relid);
if (!RelationIsValid(rd))
- elog(WARN, "cannot compute type of att %s for relid %d",
- attrname, relid);
- }
-
- attid = nf_varattno(rd, attrname);
-
- if (attid == InvalidAttrNumber)
- elog(WARN, "Invalid attribute %s\n", attrname);
-
- vartype = att_typeid(rd , attid);
-
- /*
- * close relation we're done with it now
- */
- heap_close(rd);
-
- return (vartype);
+ {
+ rd = heap_openr(tname(get_id_type(relid)));
+ if (!RelationIsValid(rd))
+ elog(WARN, "cannot compute type of att %s for relid %d",
+ attrname, relid);
+ }
+
+ attid = nf_varattno(rd, attrname);
+
+ if (attid == InvalidAttrNumber)
+ elog(WARN, "Invalid attribute %s\n", attrname);
+
+ vartype = att_typeid(rd, attid);
+
+ /*
+ * close relation we're done with it now
+ */
+ heap_close(rd);
+
+ return (vartype);
}
-Var *
-make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id)
+Var *
+make_var(ParseState * pstate, char *refname, char *attrname, Oid * type_id)
{
- Var *varnode;
- int vnum, attid;
- Oid vartypeid;
- Relation rd;
- RangeTblEntry *rte;
+ Var *varnode;
+ int vnum,
+ attid;
+ Oid vartypeid;
+ Relation rd;
+ RangeTblEntry *rte;
- rte = refnameRangeTableEntry(pstate->p_rtable, refname);
- if (rte == NULL)
- rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE, NULL);
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE, NULL);
- vnum = refnameRangeTablePosn(pstate->p_rtable, refname);
+ vnum = refnameRangeTablePosn(pstate->p_rtable, refname);
- rd = heap_open(rte->relid);
+ rd = heap_open(rte->relid);
- attid = nf_varattno(rd, attrname);
- if (attid == InvalidAttrNumber)
- elog(WARN, "Invalid attribute %s\n", attrname);
- vartypeid = att_typeid(rd, attid);
+ attid = nf_varattno(rd, attrname);
+ if (attid == InvalidAttrNumber)
+ elog(WARN, "Invalid attribute %s\n", attrname);
+ vartypeid = att_typeid(rd, attid);
- varnode = makeVar(vnum, attid, vartypeid, vnum, attid);
+ varnode = makeVar(vnum, attid, vartypeid, vnum, attid);
- heap_close(rd);
+ heap_close(rd);
- *type_id = vartypeid;
- return varnode;
+ *type_id = vartypeid;
+ return varnode;
}
/*
- * make_array_ref() -- Make an array reference node.
+ * make_array_ref() -- Make an array reference node.
*
- * Array references can hang off of arbitrary nested dot (or
- * function invocation) expressions. This routine takes a
- * tree generated by ParseFunc() and an array index and
- * generates a new array reference tree. We do some simple
- * typechecking to be sure the dereference is valid in the
- * type system, but we don't do any bounds checking here.
+ * Array references can hang off of arbitrary nested dot (or
+ * function invocation) expressions. This routine takes a
+ * tree generated by ParseFunc() and an array index and
+ * generates a new array reference tree. We do some simple
+ * typechecking to be sure the dereference is valid in the
+ * type system, but we don't do any bounds checking here.
*
- * indirection is a list of A_Indices
+ * indirection is a list of A_Indices
*/
-ArrayRef *
-make_array_ref(Node *expr,
- List *indirection)
+ArrayRef *
+make_array_ref(Node * expr,
+ List * indirection)
{
- Oid typearray;
- HeapTuple type_tuple;
- TypeTupleForm type_struct_array, type_struct_element;
- ArrayRef *aref;
- Oid reftype;
- List *upperIndexpr=NIL;
- List *lowerIndexpr=NIL;
-
- typearray = exprType(expr);
-
- type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(typearray),
- 0,0,0);
-
- if (!HeapTupleIsValid(type_tuple))
- elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
- typearray);
-
- /* get the array type struct from the type tuple */
- type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
-
- if (type_struct_array->typelem == InvalidOid) {
- elog(WARN, "make_array_ref: type %s is not an array",
- (Name)&(type_struct_array->typname.data[0]));
- }
-
- /* get the type tuple for the element type */
- type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_struct_array->typelem),
- 0,0,0);
- if (!HeapTupleIsValid(type_tuple))
- elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
- typearray);
-
- type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
-
- while(indirection!=NIL) {
- A_Indices *ind = lfirst(indirection);
- if (ind->lidx) {
- /* XXX assumes all lower indices non null in this case
- */
- lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
+ Oid typearray;
+ HeapTuple type_tuple;
+ TypeTupleForm type_struct_array,
+ type_struct_element;
+ ArrayRef *aref;
+ Oid reftype;
+ List *upperIndexpr = NIL;
+ List *lowerIndexpr = NIL;
+
+ typearray = exprType(expr);
+
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(typearray),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
+ typearray);
+
+ /* get the array type struct from the type tuple */
+ type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ if (type_struct_array->typelem == InvalidOid)
+ {
+ elog(WARN, "make_array_ref: type %s is not an array",
+ (Name) & (type_struct_array->typname.data[0]));
+ }
+
+ /* get the type tuple for the element type */
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type_struct_array->typelem),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
+ typearray);
+
+ type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ while (indirection != NIL)
+ {
+ A_Indices *ind = lfirst(indirection);
+
+ if (ind->lidx)
+ {
+
+ /*
+ * XXX assumes all lower indices non null in this case
+ */
+ lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
+ }
+ upperIndexpr = lappend(upperIndexpr, ind->uidx);
+ indirection = lnext(indirection);
}
- upperIndexpr = lappend(upperIndexpr, ind->uidx);
- indirection = lnext(indirection);
- }
- aref = makeNode(ArrayRef);
- aref->refattrlength = type_struct_array->typlen;
- aref->refelemlength = type_struct_element->typlen;
- aref->refelemtype = type_struct_array->typelem;
- aref->refelembyval = type_struct_element->typbyval;
- aref->refupperindexpr = upperIndexpr;
- aref->reflowerindexpr = lowerIndexpr;
- aref->refexpr = expr;
- aref->refassgnexpr = NULL;
-
- if (lowerIndexpr == NIL) /* accessing a single array element */
- reftype = aref->refelemtype;
- else /* request to clip a part of the array, the result is another array */
- reftype = typearray;
-
- /* we change it to reflect the true type; since the original refelemtype
- * doesn't seem to get used anywhere. - ay 10/94
- */
- aref->refelemtype = reftype;
-
- return aref;
+ aref = makeNode(ArrayRef);
+ aref->refattrlength = type_struct_array->typlen;
+ aref->refelemlength = type_struct_element->typlen;
+ aref->refelemtype = type_struct_array->typelem;
+ aref->refelembyval = type_struct_element->typbyval;
+ aref->refupperindexpr = upperIndexpr;
+ aref->reflowerindexpr = lowerIndexpr;
+ aref->refexpr = expr;
+ aref->refassgnexpr = NULL;
+
+ if (lowerIndexpr == NIL) /* accessing a single array element */
+ reftype = aref->refelemtype;
+ else
+/* request to clip a part of the array, the result is another array */
+ reftype = typearray;
+
+ /*
+ * we change it to reflect the true type; since the original
+ * refelemtype doesn't seem to get used anywhere. - ay 10/94
+ */
+ aref->refelemtype = reftype;
+
+ return aref;
}
-ArrayRef *
-make_array_set(Expr *target_expr,
- List *upperIndexpr,
- List *lowerIndexpr,
- Expr *expr)
+ArrayRef *
+make_array_set(Expr * target_expr,
+ List * upperIndexpr,
+ List * lowerIndexpr,
+ Expr * expr)
{
- Oid typearray;
- HeapTuple type_tuple;
- TypeTupleForm type_struct_array;
- TypeTupleForm type_struct_element;
- ArrayRef *aref;
- Oid reftype;
-
- typearray = exprType((Node*)target_expr);
-
- type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(typearray),
- 0,0,0);
-
- if (!HeapTupleIsValid(type_tuple))
- elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
- typearray);
-
- /* get the array type struct from the type tuple */
- type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
-
- if (type_struct_array->typelem == InvalidOid) {
- elog(WARN, "make_array_ref: type %s is not an array",
- (Name)&(type_struct_array->typname.data[0]));
- }
- /* get the type tuple for the element type */
- type_tuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type_struct_array->typelem),
- 0,0,0);
-
- if (!HeapTupleIsValid(type_tuple))
- elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
- typearray);
-
- type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
-
- aref = makeNode(ArrayRef);
- aref->refattrlength = type_struct_array->typlen;
- aref->refelemlength = type_struct_element->typlen;
- aref->refelemtype = type_struct_array->typelem;
- aref->refelembyval = type_struct_element->typbyval;
- aref->refupperindexpr = upperIndexpr;
- aref->reflowerindexpr = lowerIndexpr;
- aref->refexpr = (Node*)target_expr;
- aref->refassgnexpr = (Node*)expr;
-
- if (lowerIndexpr == NIL) /* accessing a single array element */
- reftype = aref->refelemtype;
- else /* request to set a part of the array, by another array */
- reftype = typearray;
-
- aref->refelemtype = reftype;
-
- return aref;
+ Oid typearray;
+ HeapTuple type_tuple;
+ TypeTupleForm type_struct_array;
+ TypeTupleForm type_struct_element;
+ ArrayRef *aref;
+ Oid reftype;
+
+ typearray = exprType((Node *) target_expr);
+
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(typearray),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
+ typearray);
+
+ /* get the array type struct from the type tuple */
+ type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ if (type_struct_array->typelem == InvalidOid)
+ {
+ elog(WARN, "make_array_ref: type %s is not an array",
+ (Name) & (type_struct_array->typname.data[0]));
+ }
+ /* get the type tuple for the element type */
+ type_tuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type_struct_array->typelem),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(type_tuple))
+ elog(WARN, "make_array_ref: Cache lookup failed for type %d\n",
+ typearray);
+
+ type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple);
+
+ aref = makeNode(ArrayRef);
+ aref->refattrlength = type_struct_array->typlen;
+ aref->refelemlength = type_struct_element->typlen;
+ aref->refelemtype = type_struct_array->typelem;
+ aref->refelembyval = type_struct_element->typbyval;
+ aref->refupperindexpr = upperIndexpr;
+ aref->reflowerindexpr = lowerIndexpr;
+ aref->refexpr = (Node *) target_expr;
+ aref->refassgnexpr = (Node *) expr;
+
+ if (lowerIndexpr == NIL) /* accessing a single array element */
+ reftype = aref->refelemtype;
+ else
+/* request to set a part of the array, by another array */
+ reftype = typearray;
+
+ aref->refelemtype = reftype;
+
+ return aref;
}
/*
- *
+ *
* make_const -
- *
+ *
* - takes a lispvalue, (as returned to the yacc routine by the lexer)
- * extracts the type, and makes the appropriate type constant
- * by invoking the (c-callable) lisp routine c-make-const
- * via the lisp_call() mechanism
+ * extracts the type, and makes the appropriate type constant
+ * by invoking the (c-callable) lisp routine c-make-const
+ * via the lisp_call() mechanism
*
* eventually, produces a "const" lisp-struct as per nodedefs.cl
- */
-Const *
-make_const(Value *value)
+ */
+Const *
+make_const(Value * value)
{
- Type tp;
- Datum val;
- Const *con;
-
- switch(nodeTag(value)) {
- case T_Integer:
- tp = type("int4");
- val = Int32GetDatum(intVal(value));
- break;
-
- case T_Float:
- {
- float64 dummy;
- tp = type("float8");
-
- dummy = (float64)palloc(sizeof(float64data));
- *dummy = floatVal(value);
-
- val = Float64GetDatum(dummy);
- }
- break;
-
- case T_String:
- tp = type("unknown"); /* unknown for now, will be type coerced */
- val = PointerGetDatum(textin(strVal(value)));
- break;
-
- case T_Null:
- default:
- {
- if (nodeTag(value)!=T_Null)
- elog(NOTICE,"unknown type : %d\n", nodeTag(value));
+ Type tp;
+ Datum val;
+ Const *con;
- /* null const */
- con = makeConst(0, 0, (Datum)NULL, true, false, false, false);
- return con;
+ switch (nodeTag(value))
+ {
+ case T_Integer:
+ tp = type("int4");
+ val = Int32GetDatum(intVal(value));
+ break;
+
+ case T_Float:
+ {
+ float64 dummy;
+
+ tp = type("float8");
+
+ dummy = (float64) palloc(sizeof(float64data));
+ *dummy = floatVal(value);
+
+ val = Float64GetDatum(dummy);
+ }
+ break;
+
+ case T_String:
+ tp = type("unknown"); /* unknown for now, will be type coerced */
+ val = PointerGetDatum(textin(strVal(value)));
+ break;
+
+ case T_Null:
+ default:
+ {
+ if (nodeTag(value) != T_Null)
+ elog(NOTICE, "unknown type : %d\n", nodeTag(value));
+
+ /* null const */
+ con = makeConst(0, 0, (Datum) NULL, true, false, false, false);
+ return con;
+ }
}
- }
- con = makeConst(typeid(tp),
- tlen(tp),
- val,
- false,
- tbyval(tp),
- false, /* not a set */
- false);
+ con = makeConst(typeid(tp),
+ tlen(tp),
+ val,
+ false,
+ tbyval(tp),
+ false, /* not a set */
+ false);
- return (con);
+ return (con);
}
/*
@@ -721,87 +785,93 @@ make_const(Value *value)
* used in postquel functions
*/
void
-param_type_init(Oid* typev, int nargs)
+param_type_init(Oid * typev, int nargs)
{
- pfunc_num_args = nargs;
- param_type_info = typev;
+ pfunc_num_args = nargs;
+ param_type_info = typev;
}
Oid
param_type(int t)
{
- if ((t >pfunc_num_args) ||(t ==0)) return InvalidOid;
- return param_type_info[t-1];
+ if ((t > pfunc_num_args) || (t == 0))
+ return InvalidOid;
+ return param_type_info[t - 1];
}
/*
* handleTargetColname -
- * use column names from insert
+ * use column names from insert
*/
void
-handleTargetColname(ParseState *pstate, char **resname,
+handleTargetColname(ParseState * pstate, char **resname,
char *refname, char *colname)
{
- if (pstate->p_is_insert) {
- if (pstate->p_insert_columns != NIL ) {
- Ident *id = lfirst(pstate->p_insert_columns);
- *resname = id->name;
- pstate->p_insert_columns = lnext(pstate->p_insert_columns);
- }
- else
- elog(WARN, "insert: more expressions than target columns");
- }
- if (pstate->p_is_insert||pstate->p_is_update)
- checkTargetTypes(pstate, *resname, refname, colname);
+ if (pstate->p_is_insert)
+ {
+ if (pstate->p_insert_columns != NIL)
+ {
+ Ident *id = lfirst(pstate->p_insert_columns);
+
+ *resname = id->name;
+ pstate->p_insert_columns = lnext(pstate->p_insert_columns);
+ }
+ else
+ elog(WARN, "insert: more expressions than target columns");
+ }
+ if (pstate->p_is_insert || pstate->p_is_update)
+ checkTargetTypes(pstate, *resname, refname, colname);
}
/*
* checkTargetTypes -
- * checks value and target column types
+ * checks value and target column types
*/
static void
-checkTargetTypes(ParseState *pstate, char *target_colname,
- char *refname, char *colname)
+checkTargetTypes(ParseState * pstate, char *target_colname,
+ char *refname, char *colname)
{
- Oid attrtype_id, attrtype_target;
- int resdomno_id, resdomno_target;
- Relation rd;
- RangeTblEntry *rte;
-
- if (target_colname == NULL || colname == NULL)
- return;
-
- if (refname != NULL)
- rte = refnameRangeTableEntry(pstate->p_rtable, refname);
- else {
- rte = colnameRangeTableEntry(pstate, colname);
- if ( rte == (RangeTblEntry *) NULL )
- elog (WARN, "attribute %s not found", colname);
- refname = rte->refname;
- }
+ Oid attrtype_id,
+ attrtype_target;
+ int resdomno_id,
+ resdomno_target;
+ Relation rd;
+ RangeTblEntry *rte;
+
+ if (target_colname == NULL || colname == NULL)
+ return;
+
+ if (refname != NULL)
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ else
+ {
+ rte = colnameRangeTableEntry(pstate, colname);
+ if (rte == (RangeTblEntry *) NULL)
+ elog(WARN, "attribute %s not found", colname);
+ refname = rte->refname;
+ }
/*
- if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
- elog(WARN, "%s not available in this context", colname);
+ if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
+ elog(WARN, "%s not available in this context", colname);
*/
- rd = heap_open(rte->relid);
+ rd = heap_open(rte->relid);
- resdomno_id = varattno(rd,colname);
- attrtype_id = att_typeid(rd,resdomno_id);
+ resdomno_id = varattno(rd, colname);
+ attrtype_id = att_typeid(rd, resdomno_id);
- resdomno_target = varattno(pstate->p_target_relation,target_colname);
- attrtype_target = att_typeid(pstate->p_target_relation, resdomno_target);
+ resdomno_target = varattno(pstate->p_target_relation, target_colname);
+ attrtype_target = att_typeid(pstate->p_target_relation, resdomno_target);
- if (attrtype_id != attrtype_target)
- elog(WARN, "Type of %s does not match target column %s",
- colname, target_colname);
+ if (attrtype_id != attrtype_target)
+ elog(WARN, "Type of %s does not match target column %s",
+ colname, target_colname);
- if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) &&
- rd->rd_att->attrs[resdomno_id-1]->attlen !=
- pstate->p_target_relation->rd_att->attrs[resdomno_target-1]->attlen)
- elog(WARN, "Length of %s does not match length of target column %s",
- colname, target_colname);
+ if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) &&
+ rd->rd_att->attrs[resdomno_id - 1]->attlen !=
+ pstate->p_target_relation->rd_att->attrs[resdomno_target - 1]->attlen)
+ elog(WARN, "Length of %s does not match length of target column %s",
+ colname, target_colname);
- heap_close(rd);
+ heap_close(rd);
}
-
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index ab4276055cd..99c6ce2bfdb 100644
--- a/src/backend/parser/parser.c
+++ b/src/backend/parser/parser.c
@@ -6,14 +6,14 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.22 1997/08/22 07:12:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.23 1997/09/07 04:44:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include <stdio.h>
#include <pwd.h>
-#include <sys/param.h> /* for MAXPATHLEN */
+#include <sys/param.h> /* for MAXPATHLEN */
#include "postgres.h"
#include "parser/catalog_utils.h"
@@ -34,456 +34,510 @@
#include "catalog/pg_aggregate.h"
#include "catalog/pg_type.h"
#include "access/heapam.h"
-#include "optimizer/clauses.h"
+#include "optimizer/clauses.h"
-void init_io(); /* from scan.l */
-void parser_init(Oid *typev, int nargs); /* from gram.y */
-int yyparse(); /* from gram.c */
+void init_io(); /* from scan.l */
+void parser_init(Oid * typev, int nargs); /* from gram.y */
+int yyparse(); /* from gram.c */
-char *parseString; /* the char* which holds the string to be parsed */
-char *parseCh; /* a pointer used during parsing to walk down ParseString*/
+char *parseString; /* the char* which holds the string to be
+ * parsed */
+char *parseCh; /* a pointer used during parsing to walk
+ * down ParseString */
-List *parsetree = NIL;
+List *parsetree = NIL;
#ifdef SETS_FIXED
-static void fixupsets();
-static void define_sets();
+static void fixupsets();
+static void define_sets();
+
#endif
/*
* parser-- returns a list of parse trees
- *
- * CALLER is responsible for free'ing the list returned
+ *
+ * CALLER is responsible for free'ing the list returned
*/
-QueryTreeList *
-parser(char *str, Oid *typev, int nargs)
+QueryTreeList *
+parser(char *str, Oid * typev, int nargs)
{
- QueryTreeList* queryList;
- int yyresult;
+ QueryTreeList *queryList;
+ int yyresult;
#if defined(FLEX_SCANNER)
- extern void DeleteBuffer(void);
-#endif /* FLEX_SCANNER */
-
- init_io();
-
- /* Set things up to read from the string, if there is one */
- parseString = (char *) palloc(strlen(str) + 1);
- memmove(parseString,str,strlen(str)+1);
-
- parser_init(typev, nargs);
- yyresult = yyparse();
+ extern void DeleteBuffer(void);
+
+#endif /* FLEX_SCANNER */
+
+ init_io();
+
+ /* Set things up to read from the string, if there is one */
+ parseString = (char *) palloc(strlen(str) + 1);
+ memmove(parseString, str, strlen(str) + 1);
+
+ parser_init(typev, nargs);
+ yyresult = yyparse();
#if defined(FLEX_SCANNER)
- DeleteBuffer();
-#endif /* FLEX_SCANNER */
-
- clearerr(stdin);
-
- if (yyresult) { /* error */
- return((QueryTreeList*)NULL);
- }
-
- queryList = parse_analyze(parsetree);
-
+ DeleteBuffer();
+#endif /* FLEX_SCANNER */
+
+ clearerr(stdin);
+
+ if (yyresult)
+ { /* error */
+ return ((QueryTreeList *) NULL);
+ }
+
+ queryList = parse_analyze(parsetree);
+
#ifdef SETS_FIXED
- /* Fixing up sets calls the parser, so it reassigns the global
- * variable parsetree. So save the real parsetree.
- */
- savetree = parsetree;
- foreach (parse, savetree) { /* savetree is really a list of parses */
- /* find set definitions embedded in query */
- fixupsets((Query *)lfirst(parse));
+ /*
+ * Fixing up sets calls the parser, so it reassigns the global
+ * variable parsetree. So save the real parsetree.
+ */
+ savetree = parsetree;
+ foreach(parse, savetree)
+ { /* savetree is really a list of parses */
+
+ /* find set definitions embedded in query */
+ fixupsets((Query *) lfirst(parse));
- }
- return savetree;
-#endif
+ }
+ return savetree;
+#endif
- return queryList;
+ return queryList;
}
#ifdef SETS_FIXED
static void
-fixupsets(Query *parse)
+fixupsets(Query * parse)
{
- if (parse == NULL)
- return;
- if (parse->commandType==CMD_UTILITY) /* utility */
- return;
- if (parse->commandType!=CMD_INSERT)
- return;
- define_sets(parse);
+ if (parse == NULL)
+ return;
+ if (parse->commandType == CMD_UTILITY) /* utility */
+ return;
+ if (parse->commandType != CMD_INSERT)
+ return;
+ define_sets(parse);
}
/* Recursively find all of the Consts in the parsetree. Some of
* these may represent a set. The value of the Const will be the
- * query (a string) which defines the set. Call SetDefine to define
+ * query (a string) which defines the set. Call SetDefine to define
* the set, and store the OID of the new set in the Const instead.
*/
static void
-define_sets(Node *clause)
+define_sets(Node * clause)
{
- Oid setoid;
- Type t = type("oid");
- Oid typeoid = typeid(t);
- Size oidsize = tlen(t);
- bool oidbyval = tbyval(t);
-
- if (clause==NULL) {
- return;
- } else if (IsA(clause,LispList)) {
- define_sets(lfirst(clause));
- define_sets(lnext(clause));
- } else if (IsA(clause,Const)) {
- if (get_constisnull((Const)clause) ||
- !get_constisset((Const)clause)) {
- return;
+ Oid setoid;
+ Type t = type("oid");
+ Oid typeoid = typeid(t);
+ Size oidsize = tlen(t);
+ bool oidbyval = tbyval(t);
+
+ if (clause == NULL)
+ {
+ return;
+ }
+ else if (IsA(clause, LispList))
+ {
+ define_sets(lfirst(clause));
+ define_sets(lnext(clause));
+ }
+ else if (IsA(clause, Const))
+ {
+ if (get_constisnull((Const) clause) ||
+ !get_constisset((Const) clause))
+ {
+ return;
+ }
+ setoid = SetDefine(((Const *) clause)->constvalue,
+ get_id_typname(((Const *) clause)->consttype));
+ set_constvalue((Const) clause, setoid);
+ set_consttype((Const) clause, typeoid);
+ set_constlen((Const) clause, oidsize);
+ set_constbyval((Const) clause, oidbyval);
+ }
+ else if (IsA(clause, Iter))
+ {
+ define_sets(((Iter *) clause)->iterexpr);
+ }
+ else if (single_node(clause))
+ {
+ return;
+ }
+ else if (or_clause(clause))
+ {
+ List *temp;
+
+ /* mapcan */
+ foreach(temp, ((Expr *) clause)->args)
+ {
+ define_sets(lfirst(temp));
+ }
}
- setoid = SetDefine(((Const*)clause)->constvalue,
- get_id_typname(((Const*)clause)->consttype));
- set_constvalue((Const)clause, setoid);
- set_consttype((Const)clause,typeoid);
- set_constlen((Const)clause,oidsize);
- set_constbyval((Const)clause,oidbyval);
- } else if ( IsA(clause,Iter) ) {
- define_sets(((Iter*)clause)->iterexpr);
- } else if (single_node (clause)) {
- return;
- } else if (or_clause(clause)) {
- List *temp;
- /* mapcan */
- foreach (temp, ((Expr*)clause)->args) {
- define_sets(lfirst(temp));
+ else if (is_funcclause(clause))
+ {
+ List *temp;
+
+ /* mapcan */
+ foreach(temp, ((Expr *) clause)->args)
+ {
+ define_sets(lfirst(temp));
+ }
}
- } else if (is_funcclause (clause)) {
- List *temp;
- /* mapcan */
- foreach(temp, ((Expr*)clause)->args) {
- define_sets(lfirst(temp));
+ else if (IsA(clause, ArrayRef))
+ {
+ define_sets(((ArrayRef *) clause)->refassgnexpr);
+ }
+ else if (not_clause(clause))
+ {
+ define_sets(get_notclausearg(clause));
+ }
+ else if (is_opclause(clause))
+ {
+ define_sets(get_leftop(clause));
+ define_sets(get_rightop(clause));
}
- } else if (IsA(clause,ArrayRef)) {
- define_sets(((ArrayRef*)clause)->refassgnexpr);
- } else if (not_clause (clause)) {
- define_sets (get_notclausearg (clause));
- } else if (is_opclause (clause)) {
- define_sets(get_leftop (clause));
- define_sets(get_rightop (clause));
- }
}
+
#endif
/* not used
-#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
+#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
*/
-Node *
-parser_typecast(Value *expr, TypeName *typename, int typlen)
+Node *
+parser_typecast(Value * expr, TypeName * typename, int typlen)
{
- /* check for passing non-ints */
- Const *adt;
- Datum lcp;
- Type tp;
- char type_string[16];
- int32 len;
- char *cp = NULL;
- char *const_string = NULL;
- bool string_palloced = false;
-
- switch(nodeTag(expr)) {
- case T_String:
- const_string = DatumGetPointer(expr->val.str);
- break;
- case T_Integer:
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%d", expr->val.ival);
- break;
- default:
- elog(WARN,
- "parser_typecast: cannot cast this expression to type \"%s\"",
- typename->name);
- }
-
- if (typename->arrayBounds != NIL) {
- sprintf(type_string,"_%s", typename->name);
- tp = (Type) type(type_string);
- } else {
- tp = (Type) type(typename->name);
- }
-
- len = tlen(tp);
-
-#if 0 /* fix me */
- switch ( CInteger(lfirst(expr)) ) {
- case INT4OID: /* int4 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%d", ((Const*)lnext(expr))->constvalue);
- break;
-
- case NAMEOID: /* char16 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%s", ((Const*)lnext(expr))->constvalue);
- break;
-
- case CHAROID: /* char */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%c", ((Const)lnext(expr))->constvalue);
- break;
-
- case FLOAT8OID:/* float8 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%f", ((Const)lnext(expr))->constvalue);
- break;
-
- case CASHOID: /* money */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%d",
- (int) ((Const*)expr)->constvalue);
- break;
-
- case TEXTOID: /* text */
- const_string = DatumGetPointer(((Const)lnext(expr))->constvalue);
- const_string = (char *) textout((struct varlena *)const_string);
- break;
-
- case UNKNOWNOID: /* unknown */
- const_string = DatumGetPointer(((Const)lnext(expr))->constvalue);
- const_string = (char *) textout((struct varlena *)const_string);
- break;
-
- default:
- elog(WARN,"unknown type %d", CInteger(lfirst(expr)));
- }
+ /* check for passing non-ints */
+ Const *adt;
+ Datum lcp;
+ Type tp;
+ char type_string[16];
+ int32 len;
+ char *cp = NULL;
+ char *const_string = NULL;
+ bool string_palloced = false;
+
+ switch (nodeTag(expr))
+ {
+ case T_String:
+ const_string = DatumGetPointer(expr->val.str);
+ break;
+ case T_Integer:
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%d", expr->val.ival);
+ break;
+ default:
+ elog(WARN,
+ "parser_typecast: cannot cast this expression to type \"%s\"",
+ typename->name);
+ }
+
+ if (typename->arrayBounds != NIL)
+ {
+ sprintf(type_string, "_%s", typename->name);
+ tp = (Type) type(type_string);
+ }
+ else
+ {
+ tp = (Type) type(typename->name);
+ }
+
+ len = tlen(tp);
+
+#if 0 /* fix me */
+ switch (CInteger(lfirst(expr)))
+ {
+ case INT4OID: /* int4 */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%d", ((Const *) lnext(expr))->constvalue);
+ break;
+
+ case NAMEOID: /* char16 */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%s", ((Const *) lnext(expr))->constvalue);
+ break;
+
+ case CHAROID: /* char */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%c", ((Const) lnext(expr))->constvalue);
+ break;
+
+ case FLOAT8OID: /* float8 */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%f", ((Const) lnext(expr))->constvalue);
+ break;
+
+ case CASHOID: /* money */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%d",
+ (int) ((Const *) expr)->constvalue);
+ break;
+
+ case TEXTOID: /* text */
+ const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
+ const_string = (char *) textout((struct varlena *) const_string);
+ break;
+
+ case UNKNOWNOID: /* unknown */
+ const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
+ const_string = (char *) textout((struct varlena *) const_string);
+ break;
+
+ default:
+ elog(WARN, "unknown type %d", CInteger(lfirst(expr)));
+ }
#endif
- cp = instr2 (tp, const_string, typlen);
-
- if (!tbyvalue(tp)) {
+ cp = instr2(tp, const_string, typlen);
+
+ if (!tbyvalue(tp))
+ {
/*
- if (len >= 0 && len != PSIZE(cp)) {
- char *pp;
- pp = (char *) palloc(len);
- memmove(pp, cp, len);
- cp = pp;
- }
+ if (len >= 0 && len != PSIZE(cp)) {
+ char *pp;
+ pp = (char *) palloc(len);
+ memmove(pp, cp, len);
+ cp = pp;
+ }
*/
- lcp = PointerGetDatum(cp);
- } else {
- switch(len) {
- case 1:
- lcp = Int8GetDatum(cp);
- break;
- case 2:
- lcp = Int16GetDatum(cp);
- break;
- case 4:
- lcp = Int32GetDatum(cp);
- break;
- default:
- lcp = PointerGetDatum(cp);
- break;
+ lcp = PointerGetDatum(cp);
+ }
+ else
+ {
+ switch (len)
+ {
+ case 1:
+ lcp = Int8GetDatum(cp);
+ break;
+ case 2:
+ lcp = Int16GetDatum(cp);
+ break;
+ case 4:
+ lcp = Int32GetDatum(cp);
+ break;
+ default:
+ lcp = PointerGetDatum(cp);
+ break;
+ }
}
- }
-
- adt = makeConst(typeid(tp),
- len,
- (Datum)lcp ,
- false,
- tbyvalue(tp),
- false, /* not a set */
- true /* is cast */);
-
- if (string_palloced)
- pfree(const_string);
-
- return (Node*)adt;
+
+ adt = makeConst(typeid(tp),
+ len,
+ (Datum) lcp,
+ false,
+ tbyvalue(tp),
+ false, /* not a set */
+ true /* is cast */ );
+
+ if (string_palloced)
+ pfree(const_string);
+
+ return (Node *) adt;
}
-Node *
-parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen)
+Node *
+parser_typecast2(Node * expr, Oid exprType, Type tp, int typlen)
{
- /* check for passing non-ints */
- Const *adt;
- Datum lcp;
- int32 len = tlen(tp);
- char *cp = NULL;
-
- char *const_string = NULL;
- bool string_palloced = false;
-
- Assert(IsA(expr,Const));
-
- switch (exprType) {
- case 0: /* NULL */
- break;
- case INT4OID: /* int4 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%d",
- (int) ((Const*)expr)->constvalue);
- break;
- case NAMEOID: /* char16 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%s",
- (char*) ((Const*)expr)->constvalue);
- break;
- case CHAROID: /* char */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%c",
- (char) ((Const*)expr)->constvalue);
- break;
- case FLOAT4OID: /* float4 */
+ /* check for passing non-ints */
+ Const *adt;
+ Datum lcp;
+ int32 len = tlen(tp);
+ char *cp = NULL;
+
+ char *const_string = NULL;
+ bool string_palloced = false;
+
+ Assert(IsA(expr, Const));
+
+ switch (exprType)
{
- float32 floatVal =
- DatumGetFloat32(((Const*)expr)->constvalue);
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%f", *floatVal);
- break;
+ case 0: /* NULL */
+ break;
+ case INT4OID: /* int4 */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%d",
+ (int) ((Const *) expr)->constvalue);
+ break;
+ case NAMEOID: /* char16 */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%s",
+ (char *) ((Const *) expr)->constvalue);
+ break;
+ case CHAROID: /* char */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%c",
+ (char) ((Const *) expr)->constvalue);
+ break;
+ case FLOAT4OID: /* float4 */
+ {
+ float32 floatVal =
+ DatumGetFloat32(((Const *) expr)->constvalue);
+
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%f", *floatVal);
+ break;
+ }
+ case FLOAT8OID: /* float8 */
+ {
+ float64 floatVal =
+ DatumGetFloat64(((Const *) expr)->constvalue);
+
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%f", *floatVal);
+ break;
+ }
+ case CASHOID: /* money */
+ const_string = (char *) palloc(256);
+ string_palloced = true;
+ sprintf(const_string, "%d",
+ (long) ((Const *) expr)->constvalue);
+ break;
+ case TEXTOID: /* text */
+ const_string =
+ DatumGetPointer(((Const *) expr)->constvalue);
+ const_string = (char *) textout((struct varlena *) const_string);
+ break;
+ case UNKNOWNOID: /* unknown */
+ const_string =
+ DatumGetPointer(((Const *) expr)->constvalue);
+ const_string = (char *) textout((struct varlena *) const_string);
+ break;
+ default:
+ elog(WARN, "unknown type %u ", exprType);
}
- case FLOAT8OID:/* float8 */
+
+ if (!exprType)
{
- float64 floatVal =
- DatumGetFloat64(((Const*)expr)->constvalue);
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%f", *floatVal);
- break;
+ adt = makeConst(typeid(tp),
+ (Size) 0,
+ (Datum) NULL,
+ true, /* isnull */
+ false, /* was omitted */
+ false, /* not a set */
+ true /* is cast */ );
+ return ((Node *) adt);
}
- case CASHOID: /* money */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string,"%d",
- (long) ((Const*)expr)->constvalue);
- break;
- case TEXTOID: /* text */
- const_string =
- DatumGetPointer(((Const*)expr)->constvalue );
- const_string = (char *) textout((struct varlena *)const_string);
- break;
- case UNKNOWNOID: /* unknown */
- const_string =
- DatumGetPointer(((Const*)expr)->constvalue );
- const_string = (char *) textout((struct varlena *)const_string);
- break;
- default:
- elog(WARN,"unknown type %u ",exprType);
- }
-
- if (!exprType) {
- adt = makeConst(typeid(tp),
- (Size) 0,
- (Datum) NULL,
- true, /* isnull */
- false, /* was omitted */
- false, /* not a set */
- true /* is cast */);
- return ((Node*) adt);
- }
-
- cp = instr2 (tp, const_string, typlen);
-
-
- if (!tbyvalue(tp)) {
+
+ cp = instr2(tp, const_string, typlen);
+
+
+ if (!tbyvalue(tp))
+ {
/*
- if (len >= 0 && len != PSIZE(cp)) {
- char *pp;
- pp = (char *) palloc(len);
- memmove(pp, cp, len);
- cp = pp;
- }
+ if (len >= 0 && len != PSIZE(cp)) {
+ char *pp;
+ pp = (char *) palloc(len);
+ memmove(pp, cp, len);
+ cp = pp;
+ }
*/
- lcp = PointerGetDatum(cp);
- } else {
- switch(len) {
- case 1:
- lcp = Int8GetDatum(cp);
- break;
- case 2:
- lcp = Int16GetDatum(cp);
- break;
- case 4:
- lcp = Int32GetDatum(cp);
- break;
- default:
- lcp = PointerGetDatum(cp);
- break;
+ lcp = PointerGetDatum(cp);
+ }
+ else
+ {
+ switch (len)
+ {
+ case 1:
+ lcp = Int8GetDatum(cp);
+ break;
+ case 2:
+ lcp = Int16GetDatum(cp);
+ break;
+ case 4:
+ lcp = Int32GetDatum(cp);
+ break;
+ default:
+ lcp = PointerGetDatum(cp);
+ break;
+ }
}
- }
-
- adt = makeConst(typeid(tp),
- (Size)len,
- (Datum)lcp,
- false,
- false, /*was omitted*/
- false, /* not a set */
- true /* is cast */);
- /*
- printf("adt %s : %u %d %d\n",CString(expr),typeid(tp) ,
- len,cp);
- */
- if (string_palloced) pfree(const_string);
-
- return ((Node*) adt);
+
+ adt = makeConst(typeid(tp),
+ (Size) len,
+ (Datum) lcp,
+ false,
+ false, /* was omitted */
+ false, /* not a set */
+ true /* is cast */ );
+
+ /*
+ * printf("adt %s : %u %d %d\n",CString(expr),typeid(tp) , len,cp);
+ */
+ if (string_palloced)
+ pfree(const_string);
+
+ return ((Node *) adt);
}
-Aggreg *
-ParseAgg(char *aggname, Oid basetype, Node *target)
+Aggreg *
+ParseAgg(char *aggname, Oid basetype, Node * target)
{
- Oid fintype;
- Oid vartype;
- Oid xfn1;
- Form_pg_aggregate aggform;
- Aggreg *aggreg;
- HeapTuple theAggTuple;
-
- theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname),
- ObjectIdGetDatum(basetype),
- 0, 0);
- if (!HeapTupleIsValid(theAggTuple)) {
- elog(WARN, "aggregate %s does not exist", aggname);
- }
-
- aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
- fintype = aggform->aggfinaltype;
- xfn1 = aggform->aggtransfn1;
-
- if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
- elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
-
- /* only aggregates with transfn1 need a base type */
- if (OidIsValid(xfn1)) {
- basetype = aggform->aggbasetype;
- if (nodeTag(target) == T_Var)
- vartype = ((Var*)target)->vartype;
- else
- vartype = ((Expr*)target)->typeOid;
-
- if (basetype != vartype) {
- Type tp1, tp2;
-
- tp1 = get_id_type(basetype);
- tp2 = get_id_type(vartype);
- elog(NOTICE, "Aggregate type mismatch:");
- elog(WARN, "%s works on %s, not %s", aggname,
- tname(tp1), tname(tp2));
- }
- }
-
- aggreg = makeNode(Aggreg);
- aggreg->aggname = pstrdup(aggname);
- aggreg->basetype = aggform->aggbasetype;
- aggreg->aggtype = fintype;
-
- aggreg->target = target;
-
- return aggreg;
-}
+ Oid fintype;
+ Oid vartype;
+ Oid xfn1;
+ Form_pg_aggregate aggform;
+ Aggreg *aggreg;
+ HeapTuple theAggTuple;
+ theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname),
+ ObjectIdGetDatum(basetype),
+ 0, 0);
+ if (!HeapTupleIsValid(theAggTuple))
+ {
+ elog(WARN, "aggregate %s does not exist", aggname);
+ }
+
+ aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
+ fintype = aggform->aggfinaltype;
+ xfn1 = aggform->aggtransfn1;
+
+ if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
+ elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
+
+ /* only aggregates with transfn1 need a base type */
+ if (OidIsValid(xfn1))
+ {
+ basetype = aggform->aggbasetype;
+ if (nodeTag(target) == T_Var)
+ vartype = ((Var *) target)->vartype;
+ else
+ vartype = ((Expr *) target)->typeOid;
+
+ if (basetype != vartype)
+ {
+ Type tp1,
+ tp2;
+
+ tp1 = get_id_type(basetype);
+ tp2 = get_id_type(vartype);
+ elog(NOTICE, "Aggregate type mismatch:");
+ elog(WARN, "%s works on %s, not %s", aggname,
+ tname(tp1), tname(tp2));
+ }
+ }
+
+ aggreg = makeNode(Aggreg);
+ aggreg->aggname = pstrdup(aggname);
+ aggreg->basetype = aggform->aggbasetype;
+ aggreg->aggtype = fintype;
+
+ aggreg->target = target;
+
+ return aggreg;
+}
diff --git a/src/backend/parser/scansup.c b/src/backend/parser/scansup.c
index 98bf6dba93b..0b944528980 100644
--- a/src/backend/parser/scansup.c
+++ b/src/backend/parser/scansup.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* scansup.c--
- * support routines for the lex/flex scanner, used by both the normal
+ * support routines for the lex/flex scanner, used by both the normal
* backend as well as the bootstrap backend
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.5 1996/11/15 18:38:55 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.6 1997/09/07 04:44:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,12 +24,12 @@
#include "parser/scansup.h"
/* ----------------
- * scanstr
- *
+ * scanstr
+ *
* if the string passed in has escaped codes, map the escape codes to actual
* chars
*
- * also, remove leading and ending quotes '"' if any
+ * also, remove leading and ending quotes '"' if any
*
* the string passed in must be non-null
*
@@ -38,88 +38,95 @@
* ----------------
*/
-char*
+char *
scanstr(char *s)
{
- static char newStr[MAX_PARSE_BUFFER];
- int len, i, j;
-
- if (s == NULL || s[0] == '\0')
- return s;
+ static char newStr[MAX_PARSE_BUFFER];
+ int len,
+ i,
+ j;
- len = strlen(s);
+ if (s == NULL || s[0] == '\0')
+ return s;
- for (i = 0, j = 0; i < len ; i++) {
- if (s[i] == '\'') {
- i = i + 1;
- if (s[i] == '\'')
- newStr[j] = '\'';
- }
- else {
- if (s[i] == '\\') {
- i = i + 1;
- switch (s[i]) {
- case '\\':
- newStr[j] = '\\';
- break;
- case 'b':
- newStr[j] = '\b';
- break;
- case 'f':
- newStr[j] = '\f';
- break;
- case 'n':
- newStr[j] = '\n';
- break;
- case 'r':
- newStr[j] = '\r';
- break;
- case 't':
- newStr[j] = '\t';
- break;
- case '"':
- newStr[j] = '"';
- break;
- case '\'':
- newStr[j] = '\'';
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- {
- char octal[4];
- int k;
- long octVal;
+ len = strlen(s);
+
+ for (i = 0, j = 0; i < len; i++)
+ {
+ if (s[i] == '\'')
+ {
+ i = i + 1;
+ if (s[i] == '\'')
+ newStr[j] = '\'';
+ }
+ else
+ {
+ if (s[i] == '\\')
+ {
+ i = i + 1;
+ switch (s[i])
+ {
+ case '\\':
+ newStr[j] = '\\';
+ break;
+ case 'b':
+ newStr[j] = '\b';
+ break;
+ case 'f':
+ newStr[j] = '\f';
+ break;
+ case 'n':
+ newStr[j] = '\n';
+ break;
+ case 'r':
+ newStr[j] = '\r';
+ break;
+ case 't':
+ newStr[j] = '\t';
+ break;
+ case '"':
+ newStr[j] = '"';
+ break;
+ case '\'':
+ newStr[j] = '\'';
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ char octal[4];
+ int k;
+ long octVal;
- for (k=0;
- s[i+k] >= '0' && s[i+k] <= '7' && k < 3;
- k++)
- octal[k] = s[i+k];
- i += k-1;
- octal[3] = '\0';
-
- octVal = strtol(octal,0,8);
-/* elog (NOTICE, "octal = %s octVal = %d, %od", octal, octVal, octVal);*/
- if (octVal <= 0377) {
- newStr[j] = ((char)octVal);
- break;
- }
- }
- default:
- newStr[j] = s[i];
- } /* switch */
- } /* s[i] == '\\' */
- else
- newStr[j] = s[i];
+ for (k = 0;
+ s[i + k] >= '0' && s[i + k] <= '7' && k < 3;
+ k++)
+ octal[k] = s[i + k];
+ i += k - 1;
+ octal[3] = '\0';
+
+ octVal = strtol(octal, 0, 8);
+/* elog (NOTICE, "octal = %s octVal = %d, %od", octal, octVal, octVal);*/
+ if (octVal <= 0377)
+ {
+ newStr[j] = ((char) octVal);
+ break;
+ }
+ }
+ default:
+ newStr[j] = s[i];
+ } /* switch */
+ } /* s[i] == '\\' */
+ else
+ newStr[j] = s[i];
+ }
+ j++;
}
- j++;
- }
- newStr[j] = '\0';
- return newStr;
+ newStr[j] = '\0';
+ return newStr;
}
-
diff --git a/src/backend/parser/sysfunc.c b/src/backend/parser/sysfunc.c
index fac1b60fd5a..02d6d6b21a7 100644
--- a/src/backend/parser/sysfunc.c
+++ b/src/backend/parser/sysfunc.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
- *
+ *
* sysfunc.c--
- * process system functions and return a string result
- *
+ * process system functions and return a string result
+ *
* Notes:
* 1) I return a string result because most of the functions cannot return any
- * normal type anyway (e.g. SYS_DATE, SYS_TIME, etc...), and the few that
- * might (SYS_UID or whatever) can just return it as a string - no problem.
- * This keeps the function flexible enough to be of good use.
- *
+ * normal type anyway (e.g. SYS_DATE, SYS_TIME, etc...), and the few that
+ * might (SYS_UID or whatever) can just return it as a string - no problem.
+ * This keeps the function flexible enough to be of good use.
+ *
* Written by Chad Robinson, [email protected]
* Last modified: 04/27/1996
* -------------------------------------------------------------------------
@@ -27,39 +27,42 @@
* Can't get much more obvious than this. Might need to replace localtime()
* on older systems...
*/
-static char *Sysfunc_system_date(void)
+static char *
+Sysfunc_system_date(void)
{
- time_t cur_time_secs;
- struct tm *cur_time_expanded;
- static char buf[12]; /* Just for safety, y'understand... */
-
+ time_t cur_time_secs;
+ struct tm *cur_time_expanded;
+ static char buf[12]; /* Just for safety, y'understand... */
+
time(&cur_time_secs);
cur_time_expanded = localtime(&cur_time_secs);
if (EuroDates == 1)
sprintf(buf, "%2.2d-%2.2d-%4.4d", cur_time_expanded->tm_mday,
- cur_time_expanded->tm_mon+1, cur_time_expanded->tm_year+1900);
+ cur_time_expanded->tm_mon + 1, cur_time_expanded->tm_year + 1900);
else
- sprintf(buf, "%2.2d-%2.2d-%4.4d", cur_time_expanded->tm_mon+1,
- cur_time_expanded->tm_mday, cur_time_expanded->tm_year+1900);
+ sprintf(buf, "%2.2d-%2.2d-%4.4d", cur_time_expanded->tm_mon + 1,
+ cur_time_expanded->tm_mday, cur_time_expanded->tm_year + 1900);
return &buf[0];
}
-static char *Sysfunc_system_time(void)
+static char *
+Sysfunc_system_time(void)
{
- time_t cur_time_secs;
- struct tm *cur_time_expanded;
- static char buf[10]; /* Just for safety, y'understand... */
-
+ time_t cur_time_secs;
+ struct tm *cur_time_expanded;
+ static char buf[10]; /* Just for safety, y'understand... */
+
time(&cur_time_secs);
cur_time_expanded = localtime(&cur_time_secs);
sprintf(buf, "%2.2d:%2.2d:%2.2d", cur_time_expanded->tm_hour,
- cur_time_expanded->tm_min, cur_time_expanded->tm_sec);
+ cur_time_expanded->tm_min, cur_time_expanded->tm_sec);
return &buf[0];
}
-char *SystemFunctionHandler(char *funct)
+char *
+SystemFunctionHandler(char *funct)
{
if (!strcmp(funct, "SYS_DATE"))
return Sysfunc_system_date();
@@ -73,9 +76,11 @@ char *SystemFunctionHandler(char *funct)
* Chad's rule of coding #4 - never delete a test function, even a stupid
* one - you always need it 10 minutes after you delete it.
*/
-void main(void)
+void
+main(void)
{
printf("Current system date: %s\n", SystemFunctionHandler("SYS_DATE"));
return;
}
+
#endif
diff --git a/src/backend/port/BSD44_derived/dl.c b/src/backend/port/BSD44_derived/dl.c
index 0a6525c8ac8..091507204b4 100644
--- a/src/backend/port/BSD44_derived/dl.c
+++ b/src/backend/port/BSD44_derived/dl.c
@@ -6,22 +6,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)
@@ -32,8 +32,9 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)dl.c 5.4 (Berkeley) 2/23/91";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)dl.c 5.4 (Berkeley) 2/23/91";
+
+#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <nlist.h>
@@ -45,52 +46,55 @@ static char sccsid[] = "@(#)dl.c 5.4 (Berkeley) 2/23/91";
#include "port-protos.h"
-static char error_message[BUFSIZ];
+static char error_message[BUFSIZ];
-char *
+char *
BSD44_derived_dlerror(void)
{
- static char ret[BUFSIZ];
+ static char ret[BUFSIZ];
strcpy(ret, error_message);
error_message[0] = 0;
- return((ret[0] == 0) ? (char *) NULL : ret);
+ return ((ret[0] == 0) ? (char *) NULL : ret);
}
-void *
+void *
BSD44_derived_dlopen(const char *file, int num)
{
#ifdef __mips__
- sprintf(error_message, "dlopen (%s) not supported", file);
+ sprintf(error_message, "dlopen (%s) not supported", file);
return NULL;
#else
- void *vp;
+ void *vp;
- if ((vp = dlopen((char *) file, num)) == (void *) NULL) {
+ if ((vp = dlopen((char *) file, num)) == (void *) NULL)
+ {
sprintf(error_message, "dlopen (%s) failed", file);
}
- return(vp);
+ return (vp);
#endif
}
-void *
+void *
BSD44_derived_dlsym(void *handle, const char *name)
{
#ifdef __mips__
sprintf(error_message, "dlsym (%s) failed", name);
return NULL;
#else
- void *vp;
- char buf[BUFSIZ];
+ void *vp;
+ char buf[BUFSIZ];
- if (*name != '_') {
+ if (*name != '_')
+ {
sprintf(buf, "_%s", name);
name = buf;
}
- if ((vp = dlsym(handle, (char *) name)) == (void *) NULL) {
+ if ((vp = dlsym(handle, (char *) name)) == (void *) NULL)
+ {
sprintf(error_message, "dlsym (%s) failed", name);
}
- return(vp);
+ return (vp);
#endif
}
diff --git a/src/backend/port/BSD44_derived/port-protos.h b/src/backend/port/BSD44_derived/port-protos.h
index e1f52bbdd63..2452355d29d 100644
--- a/src/backend/port/BSD44_derived/port-protos.h
+++ b/src/backend/port/BSD44_derived/port-protos.h
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for NetBSD 1.0
+ * port-specific prototypes for NetBSD 1.0
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.6 1997/03/19 03:56:50 scrappy Exp $
+ * $Id: port-protos.h,v 1.7 1997/09/07 04:45:03 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,14 +19,14 @@
#include "postgres.h"
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
/*
* Dynamic Loader on NetBSD 1.0.
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
@@ -35,14 +35,14 @@
* begin with an underscore is fairly tricky, and some versions of
* NetBSD (like 1.0, and 1.0A pre June 1995) have no dlerror.)
*/
-# define pg_dlopen(f) BSD44_derived_dlopen(f, 1)
-# define pg_dlsym BSD44_derived_dlsym
-# define pg_dlclose BSD44_derived_dlclose
-# define pg_dlerror BSD44_derived_dlerror
+#define pg_dlopen(f) BSD44_derived_dlopen(f, 1)
+#define pg_dlsym BSD44_derived_dlsym
+#define pg_dlclose BSD44_derived_dlclose
+#define pg_dlerror BSD44_derived_dlerror
-char * BSD44_derived_dlerror(void);
-void * BSD44_derived_dlopen(const char *filename, int num);
-void * BSD44_derived_dlsym(void *handle, const char *name);
-void BSD44_derived_dlclose(void *handle);
+char *BSD44_derived_dlerror(void);
+void *BSD44_derived_dlopen(const char *filename, int num);
+void *BSD44_derived_dlsym(void *handle, const char *name);
+void BSD44_derived_dlclose(void *handle);
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/aix/dlfcn.c b/src/backend/port/aix/dlfcn.c
index 4e95271e098..58a3dea3c12 100644
--- a/src/backend/port/aix/dlfcn.c
+++ b/src/backend/port/aix/dlfcn.c
@@ -22,33 +22,36 @@
* address.
*/
-typedef struct {
- char *name; /* the symbols's name */
- void *addr; /* its relocated virtual address */
-} Export, *ExportPtr;
+typedef struct
+{
+ char *name; /* the symbols's name */
+ void *addr; /* its relocated virtual address */
+} Export, *ExportPtr;
/*
* xlC uses the following structure to list its constructors and
* destructors. This is gleaned from the output of munch.
*/
-typedef struct {
- void (*init)(void); /* call static constructors */
- void (*term)(void); /* call static destructors */
-} Cdtor, *CdtorPtr;
+typedef struct
+{
+ void (*init) (void); /* call static constructors */
+ void (*term) (void); /* call static destructors */
+} Cdtor, *CdtorPtr;
/*
* The void * handle returned from dlopen is actually a ModulePtr.
*/
-typedef struct Module {
- struct Module *next;
- char *name; /* module name for refcounting */
- int refCnt; /* the number of references */
- void *entry; /* entry point from load */
- struct dl_info *info; /* optional init/terminate functions */
- CdtorPtr cdtors; /* optional C++ constructors */
- int nExports; /* the number of exports found */
- ExportPtr exports; /* the array of exports */
-} Module, *ModulePtr;
+typedef struct Module
+{
+ struct Module *next;
+ char *name; /* module name for refcounting */
+ int refCnt; /* the number of references */
+ void *entry; /* entry point from load */
+ struct dl_info *info; /* optional init/terminate functions */
+ CdtorPtr cdtors; /* optional C++ constructors */
+ int nExports; /* the number of exports found */
+ ExportPtr exports; /* the array of exports */
+} Module, *ModulePtr;
/*
* We keep a list of all loaded modules to be able to call the fini
@@ -60,98 +63,116 @@ static ModulePtr modList;
* The last error from one of the dl* routines is kept in static
* variables here. Each error is returned only once to the caller.
*/
-static char errbuf[BUFSIZ];
-static int errvalid;
+static char errbuf[BUFSIZ];
+static int errvalid;
-extern char *strdup(const char *);
-static void caterr(char *);
-static int readExports(ModulePtr);
-static void terminate(void);
-static void *findMain(void);
+extern char *strdup(const char *);
+static void caterr(char *);
+static int readExports(ModulePtr);
+static void terminate(void);
+static void *findMain(void);
-void *dlopen(const char *path, int mode)
+void *
+dlopen(const char *path, int mode)
{
register ModulePtr mp;
- static void *mainModule;
+ static void *mainModule;
/*
- * Upon the first call register a terminate handler that will
- * close all libraries. Also get a reference to the main module
- * for use with loadbind.
+ * Upon the first call register a terminate handler that will close
+ * all libraries. Also get a reference to the main module for use with
+ * loadbind.
*/
- if (!mainModule) {
+ if (!mainModule)
+ {
if ((mainModule = findMain()) == NULL)
return NULL;
atexit(terminate);
}
+
/*
* Scan the list of modules if we have the module already loaded.
*/
for (mp = modList; mp; mp = mp->next)
- if (strcmp(mp->name, path) == 0) {
+ if (strcmp(mp->name, path) == 0)
+ {
mp->refCnt++;
return mp;
}
- if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) {
+ if ((mp = (ModulePtr) calloc(1, sizeof(*mp))) == NULL)
+ {
errvalid++;
strcpy(errbuf, "calloc: ");
strcat(errbuf, strerror(errno));
return NULL;
}
- if ((mp->name = strdup(path)) == NULL) {
+ if ((mp->name = strdup(path)) == NULL)
+ {
errvalid++;
strcpy(errbuf, "strdup: ");
strcat(errbuf, strerror(errno));
free(mp);
return NULL;
}
+
/*
- * load should be declared load(const char *...). Thus we
- * cast the path to a normal char *. Ugly.
+ * load should be declared load(const char *...). Thus we cast the
+ * path to a normal char *. Ugly.
*/
- if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
+ if ((mp->entry = (void *) load((char *) path, L_NOAUTODEFER, NULL)) == NULL)
+ {
free(mp->name);
free(mp);
errvalid++;
strcpy(errbuf, "dlopen: ");
strcat(errbuf, path);
strcat(errbuf, ": ");
+
/*
- * If AIX says the file is not executable, the error
- * can be further described by querying the loader about
- * the last error.
+ * If AIX says the file is not executable, the error can be
+ * further described by querying the loader about the last error.
*/
- if (errno == ENOEXEC) {
- char *tmp[BUFSIZ/sizeof(char *)];
+ if (errno == ENOEXEC)
+ {
+ char *tmp[BUFSIZ / sizeof(char *)];
+
if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
strcpy(errbuf, strerror(errno));
- else {
- char **p;
+ else
+ {
+ char **p;
+
for (p = tmp; *p; p++)
caterr(*p);
}
- } else
+ }
+ else
strcat(errbuf, strerror(errno));
return NULL;
}
mp->refCnt = 1;
mp->next = modList;
modList = mp;
- if (loadbind(0, mainModule, mp->entry) == -1) {
+ if (loadbind(0, mainModule, mp->entry) == -1)
+ {
dlclose(mp);
errvalid++;
strcpy(errbuf, "loadbind: ");
strcat(errbuf, strerror(errno));
return NULL;
}
+
/*
- * If the user wants global binding, loadbind against all other
- * loaded modules.
+ * If the user wants global binding, loadbind against all other loaded
+ * modules.
*/
- if (mode & RTLD_GLOBAL) {
+ if (mode & RTLD_GLOBAL)
+ {
register ModulePtr mp1;
+
for (mp1 = mp->next; mp1; mp1 = mp1->next)
- if (loadbind(0, mp1->entry, mp->entry) == -1) {
+ if (loadbind(0, mp1->entry, mp->entry) == -1)
+ {
dlclose(mp);
errvalid++;
strcpy(errbuf, "loadbind: ");
@@ -159,28 +180,36 @@ void *dlopen(const char *path, int mode)
return NULL;
}
}
- if (readExports(mp) == -1) {
+ if (readExports(mp) == -1)
+ {
dlclose(mp);
return NULL;
}
+
/*
* If there is a dl_info structure, call the init function.
*/
- if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {
+ if (mp->info = (struct dl_info *) dlsym(mp, "dl_info"))
+ {
if (mp->info->init)
- (*mp->info->init)();
- } else
+ (*mp->info->init) ();
+ }
+ else
errvalid = 0;
+
/*
- * If the shared object was compiled using xlC we will need
- * to call static constructors (and later on dlclose destructors).
+ * If the shared object was compiled using xlC we will need to call
+ * static constructors (and later on dlclose destructors).
*/
- if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) {
- while (mp->cdtors->init) {
- (*mp->cdtors->init)();
+ if (mp->cdtors = (CdtorPtr) dlsym(mp, "__cdtors"))
+ {
+ while (mp->cdtors->init)
+ {
+ (*mp->cdtors->init) ();
mp->cdtors++;
}
- } else
+ }
+ else
errvalid = 0;
return mp;
}
@@ -189,13 +218,15 @@ void *dlopen(const char *path, int mode)
* Attempt to decipher an AIX loader error message and append it
* to our static error message buffer.
*/
-static void caterr(char *s)
+static void
+caterr(char *s)
{
- register char *p = s;
+ register char *p = s;
while (*p >= '0' && *p <= '9')
p++;
- switch(atoi(s)) {
+ switch (atoi(s))
+ {
case L_ERROR_TOOMANY:
strcat(errbuf, "to many errors");
break;
@@ -224,15 +255,16 @@ static void caterr(char *s)
}
}
-void *dlsym(void *handle, const char *symbol)
+void *
+dlsym(void *handle, const char *symbol)
{
- register ModulePtr mp = (ModulePtr)handle;
+ register ModulePtr mp = (ModulePtr) handle;
register ExportPtr ep;
- register int i;
+ register int i;
/*
- * Could speed up the search, but I assume that one assigns
- * the result to function pointers anyways.
+ * Could speed up the search, but I assume that one assigns the result
+ * to function pointers anyways.
*/
for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
if (strcmp(ep->name, symbol) == 0)
@@ -243,38 +275,45 @@ void *dlsym(void *handle, const char *symbol)
return NULL;
}
-char *dlerror(void)
+char *
+dlerror(void)
{
- if (errvalid) {
+ if (errvalid)
+ {
errvalid = 0;
return errbuf;
}
return NULL;
}
-int dlclose(void *handle)
+int
+dlclose(void *handle)
{
- register ModulePtr mp = (ModulePtr)handle;
- int result;
+ register ModulePtr mp = (ModulePtr) handle;
+ int result;
register ModulePtr mp1;
if (--mp->refCnt > 0)
return 0;
if (mp->info && mp->info->fini)
- (*mp->info->fini)();
+ (*mp->info->fini) ();
if (mp->cdtors)
- while (mp->cdtors->term) {
- (*mp->cdtors->term)();
+ while (mp->cdtors->term)
+ {
+ (*mp->cdtors->term) ();
mp->cdtors++;
}
result = unload(mp->entry);
- if (result == -1) {
+ if (result == -1)
+ {
errvalid++;
strcpy(errbuf, strerror(errno));
}
- if (mp->exports) {
+ if (mp->exports)
+ {
register ExportPtr ep;
- register int i;
+ register int i;
+
for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
if (ep->name)
free(ep->name);
@@ -282,9 +321,11 @@ int dlclose(void *handle)
}
if (mp == modList)
modList = mp->next;
- else {
+ else
+ {
for (mp1 = modList; mp1; mp1 = mp1->next)
- if (mp1->next == mp) {
+ if (mp1->next == mp)
+ {
mp1->next = mp->next;
break;
}
@@ -294,7 +335,8 @@ int dlclose(void *handle)
return result;
}
-static void terminate(void)
+static void
+terminate(void)
{
while (modList)
dlclose(modList);
@@ -303,180 +345,208 @@ static void terminate(void)
/*
* Build the export table from the XCOFF .loader section.
*/
-static int readExports(ModulePtr mp)
+static int
+readExports(ModulePtr mp)
{
- LDFILE *ldp = NULL;
- SCNHDR sh, shdata;
- LDHDR *lhp;
- char *ldbuf;
- LDSYM *ls;
- int i;
- ExportPtr ep;
-
- if ((ldp = ldopen(mp->name, ldp)) == NULL) {
+ LDFILE *ldp = NULL;
+ SCNHDR sh,
+ shdata;
+ LDHDR *lhp;
+ char *ldbuf;
+ LDSYM *ls;
+ int i;
+ ExportPtr ep;
+
+ if ((ldp = ldopen(mp->name, ldp)) == NULL)
+ {
struct ld_info *lp;
- char *buf;
- int size = 4*1024;
- if (errno != ENOENT) {
+ char *buf;
+ int size = 4 * 1024;
+
+ if (errno != ENOENT)
+ {
errvalid++;
strcpy(errbuf, "readExports: ");
strcat(errbuf, strerror(errno));
return -1;
}
+
/*
- * The module might be loaded due to the LIBPATH
- * environment variable. Search for the loaded
- * module using L_GETINFO.
+ * The module might be loaded due to the LIBPATH environment
+ * variable. Search for the loaded module using L_GETINFO.
*/
- if ((buf = malloc(size)) == NULL) {
+ if ((buf = malloc(size)) == NULL)
+ {
errvalid++;
strcpy(errbuf, "readExports: ");
strcat(errbuf, strerror(errno));
return -1;
}
- while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
+ while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM)
+ {
free(buf);
- size += 4*1024;
- if ((buf = malloc(size)) == NULL) {
+ size += 4 * 1024;
+ if ((buf = malloc(size)) == NULL)
+ {
errvalid++;
strcpy(errbuf, "readExports: ");
strcat(errbuf, strerror(errno));
return -1;
}
}
- if (i == -1) {
+ if (i == -1)
+ {
errvalid++;
strcpy(errbuf, "readExports: ");
strcat(errbuf, strerror(errno));
free(buf);
return -1;
}
+
/*
- * Traverse the list of loaded modules. The entry point
- * returned by load() does actually point to the data
- * segment origin.
+ * Traverse the list of loaded modules. The entry point returned
+ * by load() does actually point to the data segment origin.
*/
- lp = (struct ld_info *)buf;
- while (lp) {
- if (lp->ldinfo_dataorg == mp->entry) {
+ lp = (struct ld_info *) buf;
+ while (lp)
+ {
+ if (lp->ldinfo_dataorg == mp->entry)
+ {
ldp = ldopen(lp->ldinfo_filename, ldp);
break;
}
if (lp->ldinfo_next == 0)
lp = NULL;
else
- lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
+ lp = (struct ld_info *) ((char *) lp + lp->ldinfo_next);
}
free(buf);
- if (!ldp) {
+ if (!ldp)
+ {
errvalid++;
strcpy(errbuf, "readExports: ");
strcat(errbuf, strerror(errno));
return -1;
}
}
- if (TYPE(ldp) != U802TOCMAGIC) {
+ if (TYPE(ldp) != U802TOCMAGIC)
+ {
errvalid++;
strcpy(errbuf, "readExports: bad magic");
- while(ldclose(ldp) == FAILURE)
+ while (ldclose(ldp) == FAILURE)
;
return -1;
}
+
/*
- * Get the padding for the data section. This is needed for
- * AIX 4.1 compilers. This is used when building the final
- * function pointer to the exported symbol.
+ * Get the padding for the data section. This is needed for AIX 4.1
+ * compilers. This is used when building the final function pointer to
+ * the exported symbol.
*/
- if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
+ if (ldnshread(ldp, _DATA, &shdata) != SUCCESS)
+ {
errvalid++;
strcpy(errbuf, "readExports: cannot read data section header");
- while(ldclose(ldp) == FAILURE)
+ while (ldclose(ldp) == FAILURE)
;
return -1;
}
- if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
+ if (ldnshread(ldp, _LOADER, &sh) != SUCCESS)
+ {
errvalid++;
strcpy(errbuf, "readExports: cannot read loader section header");
- while(ldclose(ldp) == FAILURE)
+ while (ldclose(ldp) == FAILURE)
;
return -1;
}
+
/*
* We read the complete loader section in one chunk, this makes
* finding long symbol names residing in the string table easier.
*/
- if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) {
+ if ((ldbuf = (char *) malloc(sh.s_size)) == NULL)
+ {
errvalid++;
strcpy(errbuf, "readExports: ");
strcat(errbuf, strerror(errno));
- while(ldclose(ldp) == FAILURE)
+ while (ldclose(ldp) == FAILURE)
;
return -1;
}
- if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
+ if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK)
+ {
errvalid++;
strcpy(errbuf, "readExports: cannot seek to loader section");
free(ldbuf);
- while(ldclose(ldp) == FAILURE)
+ while (ldclose(ldp) == FAILURE)
;
return -1;
}
- if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
+ if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1)
+ {
errvalid++;
strcpy(errbuf, "readExports: cannot read loader section");
free(ldbuf);
- while(ldclose(ldp) == FAILURE)
+ while (ldclose(ldp) == FAILURE)
;
return -1;
}
- lhp = (LDHDR *)ldbuf;
- ls = (LDSYM *)(ldbuf+LDHDRSZ);
+ lhp = (LDHDR *) ldbuf;
+ ls = (LDSYM *) (ldbuf + LDHDRSZ);
+
/*
* Count the number of exports to include in our export table.
*/
- for (i = lhp->l_nsyms; i; i--, ls++) {
+ for (i = lhp->l_nsyms; i; i--, ls++)
+ {
if (!LDR_EXPORT(*ls))
continue;
mp->nExports++;
}
- if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
+ if ((mp->exports = (ExportPtr) calloc(mp->nExports, sizeof(*mp->exports))) == NULL)
+ {
errvalid++;
strcpy(errbuf, "readExports: ");
strcat(errbuf, strerror(errno));
free(ldbuf);
- while(ldclose(ldp) == FAILURE)
+ while (ldclose(ldp) == FAILURE)
;
return -1;
}
+
/*
- * Fill in the export table. All entries are relative to
- * the entry point we got from load.
+ * Fill in the export table. All entries are relative to the entry
+ * point we got from load.
*/
ep = mp->exports;
- ls = (LDSYM *)(ldbuf+LDHDRSZ);
- for (i = lhp->l_nsyms; i; i--, ls++) {
- char *symname;
- char tmpsym[SYMNMLEN+1];
+ ls = (LDSYM *) (ldbuf + LDHDRSZ);
+ for (i = lhp->l_nsyms; i; i--, ls++)
+ {
+ char *symname;
+ char tmpsym[SYMNMLEN + 1];
+
if (!LDR_EXPORT(*ls))
continue;
if (ls->l_zeroes == 0)
- symname = ls->l_offset+lhp->l_stoff+ldbuf;
- else {
+ symname = ls->l_offset + lhp->l_stoff + ldbuf;
+ else
+ {
+
/*
- * The l_name member is not zero terminated, we
- * must copy the first SYMNMLEN chars and make
- * sure we have a zero byte at the end.
+ * The l_name member is not zero terminated, we must copy the
+ * first SYMNMLEN chars and make sure we have a zero byte at
+ * the end.
*/
strNcpy(tmpsym, ls->l_name, SYMNMLEN);
symname = tmpsym;
}
ep->name = strdup(symname);
- ep->addr = (void *)((unsigned long)mp->entry +
- ls->l_value - shdata.s_vaddr);
+ ep->addr = (void *) ((unsigned long) mp->entry +
+ ls->l_value - shdata.s_vaddr);
ep++;
}
free(ldbuf);
- while(ldclose(ldp) == FAILURE)
+ while (ldclose(ldp) == FAILURE)
;
return 0;
}
@@ -485,43 +555,48 @@ static int readExports(ModulePtr mp)
* Find the main modules entry point. This is used as export pointer
* for loadbind() to be able to resolve references to the main part.
*/
-static void * findMain(void)
+static void *
+findMain(void)
{
struct ld_info *lp;
- char *buf;
- int size = 4*1024;
- int i;
- void *ret;
+ char *buf;
+ int size = 4 * 1024;
+ int i;
+ void *ret;
- if ((buf = malloc(size)) == NULL) {
+ if ((buf = malloc(size)) == NULL)
+ {
errvalid++;
strcpy(errbuf, "findMain: ");
strcat(errbuf, strerror(errno));
return NULL;
}
- while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
+ while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM)
+ {
free(buf);
- size += 4*1024;
- if ((buf = malloc(size)) == NULL) {
+ size += 4 * 1024;
+ if ((buf = malloc(size)) == NULL)
+ {
errvalid++;
strcpy(errbuf, "findMain: ");
strcat(errbuf, strerror(errno));
return NULL;
}
}
- if (i == -1) {
+ if (i == -1)
+ {
errvalid++;
strcpy(errbuf, "findMain: ");
strcat(errbuf, strerror(errno));
free(buf);
return NULL;
}
+
/*
- * The first entry is the main module. The entry point
- * returned by load() does actually point to the data
- * segment origin.
+ * The first entry is the main module. The entry point returned by
+ * load() does actually point to the data segment origin.
*/
- lp = (struct ld_info *)buf;
+ lp = (struct ld_info *) buf;
ret = lp->ldinfo_dataorg;
free(buf);
return ret;
diff --git a/src/backend/port/aix/dlfcn.h b/src/backend/port/aix/dlfcn.h
index 5671e9caa3a..1e874d96559 100644
--- a/src/backend/port/aix/dlfcn.h
+++ b/src/backend/port/aix/dlfcn.h
@@ -8,39 +8,42 @@
#define __dlfcn_h__
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
/*
* Mode flags for the dlopen routine.
*/
-#define RTLD_LAZY 1 /* lazy function call binding */
-#define RTLD_NOW 2 /* immediate function call binding */
-#define RTLD_GLOBAL 0x100 /* allow symbols to be global */
+#define RTLD_LAZY 1 /* lazy function call binding */
+#define RTLD_NOW 2 /* immediate function call binding */
+#define RTLD_GLOBAL 0x100 /* allow symbols to be global */
/*
* To be able to intialize, a library may provide a dl_info structure
* that contains functions to be called to initialize and terminate.
*/
-struct dl_info {
- void (*init)(void);
- void (*fini)(void);
-};
+ struct dl_info
+ {
+ void (*init) (void);
+ void (*fini) (void);
+ };
#if __STDC__ || defined(_IBMR2)
-void *dlopen(const char *path, int mode);
-void *dlsym(void *handle, const char *symbol);
-char *dlerror(void);
-int dlclose(void *handle);
+ void *dlopen(const char *path, int mode);
+ void *dlsym(void *handle, const char *symbol);
+ char *dlerror(void);
+ int dlclose(void *handle);
#else
-void *dlopen();
-void *dlsym();
-char *dlerror();
-int dlclose();
+ void *dlopen();
+ void *dlsym();
+ char *dlerror();
+ int dlclose();
#endif
#ifdef __cplusplus
}
+
#endif
-#endif /* __dlfcn_h__ */
+#endif /* __dlfcn_h__ */
diff --git a/src/backend/port/aix/port-protos.h b/src/backend/port/aix/port-protos.h
index 986e5bd7d48..6429dc26c04 100644
--- a/src/backend/port/aix/port-protos.h
+++ b/src/backend/port/aix/port-protos.h
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for AIX
+ * port-specific prototypes for AIX
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.1.1.1 1996/07/09 06:21:41 scrappy Exp $
+ * $Id: port-protos.h,v 1.2 1997/09/07 04:45:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PORT_PROTOS_H
#define PORT_PROTOS_H
-#include "dlfcn.h" /* this is from jum's libdl package */
+#include "dlfcn.h" /* this is from jum's libdl package */
/* dynloader.c */
@@ -22,4 +22,4 @@
#define pg_dlclose(h) dlclose(h)
#define pg_dlerror() dlerror()
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/alpha/port-protos.h b/src/backend/port/alpha/port-protos.h
index 3bd8d454a5e..3b5cb47adea 100644
--- a/src/backend/port/alpha/port-protos.h
+++ b/src/backend/port/alpha/port-protos.h
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * prototypes for OSF/1-specific routines
+ * prototypes for OSF/1-specific routines
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.1.1.1 1996/07/09 06:21:42 scrappy Exp $
+ * $Id: port-protos.h,v 1.2 1997/09/07 04:45:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,18 +22,18 @@
/*
* Dynamic Loader on Alpha OSF/1.x
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
*/
#define pg_dlopen(f) dlopen(f, RTLD_LAZY)
-#define pg_dlsym(h, f) ((func_ptr)dlsym(h, f))
-#define pg_dlclose(h) dlclose(h)
+#define pg_dlsym(h, f) ((func_ptr)dlsym(h, f))
+#define pg_dlclose(h) dlclose(h)
#define pg_dlerror() dlerror()
/* port.c */
-extern void init_address_fixup(void);
+extern void init_address_fixup(void);
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/alpha/port.c b/src/backend/port/alpha/port.c
index d7c17b0a5ba..80b03088a43 100644
--- a/src/backend/port/alpha/port.c
+++ b/src/backend/port/alpha/port.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * OSF/1-specific routines
+ * OSF/1-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/alpha/Attic/port.c,v 1.1.1.1 1996/07/09 06:21:42 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/alpha/Attic/port.c,v 1.2 1997/09/07 04:45:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,14 +21,17 @@ void
init_address_fixup()
{
#ifdef NOFIXADE
- int buffer[] = { SSIN_UACPROC, UAC_SIGBUS };
-#endif /* NOFIXADE */
+ int buffer[] = {SSIN_UACPROC, UAC_SIGBUS};
+
+#endif /* NOFIXADE */
#ifdef NOPRINTADE
- int buffer[] = { SSIN_UACPROC, UAC_NOPRINT };
-#endif /* NOPRINTADE */
+ int buffer[] = {SSIN_UACPROC, UAC_NOPRINT};
+
+#endif /* NOPRINTADE */
- if (setsysinfo(SSI_NVPAIRS, buffer, 1, (caddr_t) NULL,
- (unsigned long) NULL) < 0) {
- elog(NOTICE, "setsysinfo failed: %d\n", errno);
- }
+ if (setsysinfo(SSI_NVPAIRS, buffer, 1, (caddr_t) NULL,
+ (unsigned long) NULL) < 0)
+ {
+ elog(NOTICE, "setsysinfo failed: %d\n", errno);
+ }
}
diff --git a/src/backend/port/bsdi/dynloader.c b/src/backend/port/bsdi/dynloader.c
index f9b2180f03a..cfaeec0c200 100644
--- a/src/backend/port/bsdi/dynloader.c
+++ b/src/backend/port/bsdi/dynloader.c
@@ -1,16 +1,16 @@
/*-------------------------------------------------------------------------
*
* dynloader.c--
- * Dynamic Loader for Postgres for Linux, generated from those for
- * Ultrix.
+ * Dynamic Loader for Postgres for Linux, generated from those for
+ * Ultrix.
*
- * You need to install the dld library on your Linux system!
+ * You need to install the dld library on your Linux system!
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/port/linux/dynloader.c,v 1.1.1.1 1994/11/07 05:19:37 andrew Exp
+ * /usr/local/devel/pglite/cvs/src/backend/port/linux/dynloader.c,v 1.1.1.1 1994/11/07 05:19:37 andrew Exp
*
*-------------------------------------------------------------------------
*/
@@ -22,74 +22,85 @@
#include "utils/elog.h"
#include "fmgr.h"
-extern char pg_pathname[];
+extern char pg_pathname[];
-void *
+void *
pg_dlopen(char *filename)
{
- static int dl_initialized= 0;
+ static int dl_initialized = 0;
- /*
- * initializes the dynamic loader with the executable's pathname.
- * (only needs to do this the first time pg_dlopen is called.)
- */
- if (!dl_initialized) {
- if (dld_init (dld_find_executable (pg_pathname))) {
- return NULL;
- }
/*
- * if there are undefined symbols, we want dl to search from the
- * following libraries also.
+ * initializes the dynamic loader with the executable's pathname.
+ * (only needs to do this the first time pg_dlopen is called.)
*/
- dl_initialized= 1;
- }
-
- /*
- * link the file, then check for undefined symbols!
- */
- if (dld_link(filename)) {
- return NULL;
- }
+ if (!dl_initialized)
+ {
+ if (dld_init(dld_find_executable(pg_pathname)))
+ {
+ return NULL;
+ }
- /*
- * If undefined symbols: try to link with the C and math libraries!
- * This could be smarter, if the dynamic linker was able to handle
- * shared libs!
- */
- if(dld_undefined_sym_count > 0) {
- if (dld_link("/usr/lib/libc.a")) {
- elog(NOTICE, "dld: Cannot link C library!");
- return NULL;
+ /*
+ * if there are undefined symbols, we want dl to search from the
+ * following libraries also.
+ */
+ dl_initialized = 1;
}
- if(dld_undefined_sym_count > 0) {
- if (dld_link("/usr/lib/libm.a")) {
- elog(NOTICE, "dld: Cannot link math library!");
+
+ /*
+ * link the file, then check for undefined symbols!
+ */
+ if (dld_link(filename))
+ {
return NULL;
- }
- if(dld_undefined_sym_count > 0) {
- int count = dld_undefined_sym_count;
- char **list= dld_list_undefined_sym();
+ }
- /* list the undefined symbols, if any */
- elog(NOTICE, "dld: Undefined:");
- do {
- elog(NOTICE, " %s", *list);
- list++;
- count--;
- } while(count > 0);
+ /*
+ * If undefined symbols: try to link with the C and math libraries!
+ * This could be smarter, if the dynamic linker was able to handle
+ * shared libs!
+ */
+ if (dld_undefined_sym_count > 0)
+ {
+ if (dld_link("/usr/lib/libc.a"))
+ {
+ elog(NOTICE, "dld: Cannot link C library!");
+ return NULL;
+ }
+ if (dld_undefined_sym_count > 0)
+ {
+ if (dld_link("/usr/lib/libm.a"))
+ {
+ elog(NOTICE, "dld: Cannot link math library!");
+ return NULL;
+ }
+ if (dld_undefined_sym_count > 0)
+ {
+ int count = dld_undefined_sym_count;
+ char **list = dld_list_undefined_sym();
- dld_unlink_by_file(filename, 1);
- return NULL;
- }
+ /* list the undefined symbols, if any */
+ elog(NOTICE, "dld: Undefined:");
+ do
+ {
+ elog(NOTICE, " %s", *list);
+ list++;
+ count--;
+ } while (count > 0);
+
+ dld_unlink_by_file(filename, 1);
+ return NULL;
+ }
+ }
}
- }
- return (void *) strdup(filename);
+ return (void *) strdup(filename);
}
-char *
+char *
pg_dlerror()
{
- return dld_strerror(dld_errno);
+ return dld_strerror(dld_errno);
}
+
#endif
diff --git a/src/backend/port/bsdi/port-protos.h b/src/backend/port/bsdi/port-protos.h
index 9d21bb15115..acd0e85a49b 100644
--- a/src/backend/port/bsdi/port-protos.h
+++ b/src/backend/port/bsdi/port-protos.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for SunOS 4
+ * port-specific prototypes for SunOS 4
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -17,26 +17,26 @@
* Externals in libc that need prototypes (or at least declarations)
*/
-extern char *ecvt(double, int, int*, int*);
-extern char *fcvt(double, int, int*, int*);
+extern char *ecvt(double, int, int *, int *);
+extern char *fcvt(double, int, int *, int *);
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
#ifndef PRE_BSDI_2_1
-# include <dlfcn.h>
-# define pg_dlopen(f) dlopen(f, 1)
-# define pg_dlsym dlsym
-# define pg_dlclose dlclose
-# define pg_dlerror dlerror
+#include <dlfcn.h>
+#define pg_dlopen(f) dlopen(f, 1)
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
#else
-# define pg_dlsym(handle, funcname) ((func_ptr) dld_get_func((funcname)))
-# define pg_dlclose(handle) ({ dld_unlink_by_file(handle, 1); free(handle); })
+#define pg_dlsym(handle, funcname) ((func_ptr) dld_get_func((funcname)))
+#define pg_dlclose(handle) ({ dld_unlink_by_file(handle, 1); free(handle); })
#endif
/* port.c */
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/dgux/dynloader.c b/src/backend/port/dgux/dynloader.c
index 7ec648fb44b..0f7d38bc092 100644
--- a/src/backend/port/dgux/dynloader.c
+++ b/src/backend/port/dgux/dynloader.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* dynloader.c--
- * Dynamic Loader for Postgres for DG/UX, generated from those for
- * Linux.
+ * Dynamic Loader for Postgres for DG/UX, generated from those for
+ * Linux.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/dgux/Attic/dynloader.c,v 1.1 1996/07/25 20:43:58 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/dgux/Attic/dynloader.c,v 1.2 1997/09/07 04:45:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,73 +19,83 @@
#include "utils/elog.h"
#include "fmgr.h"
-extern char pg_pathname[];
+extern char pg_pathname[];
-void *
+void *
pg_dlopen(char *filename)
{
- static int dl_initialized= 0;
+ static int dl_initialized = 0;
- /*
- * initializes the dynamic loader with the executable's pathname.
- * (only needs to do this the first time pg_dlopen is called.)
- */
- if (!dl_initialized) {
- if (dld_init (dld_find_executable (pg_pathname))) {
- return NULL;
- }
/*
- * if there are undefined symbols, we want dl to search from the
- * following libraries also.
+ * initializes the dynamic loader with the executable's pathname.
+ * (only needs to do this the first time pg_dlopen is called.)
*/
- dl_initialized= 1;
- }
-
- /*
- * link the file, then check for undefined symbols!
- */
- if (dld_link(filename)) {
- return NULL;
- }
+ if (!dl_initialized)
+ {
+ if (dld_init(dld_find_executable(pg_pathname)))
+ {
+ return NULL;
+ }
- /*
- * If undefined symbols: try to link with the C and math libraries!
- * This could be smarter, if the dynamic linker was able to handle
- * shared libs!
- */
- if(dld_undefined_sym_count > 0) {
- if (dld_link("/usr/lib/libc.a")) {
- elog(NOTICE, "dld: Cannot link C library!");
- return NULL;
+ /*
+ * if there are undefined symbols, we want dl to search from the
+ * following libraries also.
+ */
+ dl_initialized = 1;
}
- if(dld_undefined_sym_count > 0) {
- if (dld_link("/usr/lib/libm.a")) {
- elog(NOTICE, "dld: Cannot link math library!");
+
+ /*
+ * link the file, then check for undefined symbols!
+ */
+ if (dld_link(filename))
+ {
return NULL;
- }
- if(dld_undefined_sym_count > 0) {
- int count = dld_undefined_sym_count;
- char **list= dld_list_undefined_sym();
+ }
- /* list the undefined symbols, if any */
- elog(NOTICE, "dld: Undefined:");
- do {
- elog(NOTICE, " %s", *list);
- list++;
- count--;
- } while(count > 0);
+ /*
+ * If undefined symbols: try to link with the C and math libraries!
+ * This could be smarter, if the dynamic linker was able to handle
+ * shared libs!
+ */
+ if (dld_undefined_sym_count > 0)
+ {
+ if (dld_link("/usr/lib/libc.a"))
+ {
+ elog(NOTICE, "dld: Cannot link C library!");
+ return NULL;
+ }
+ if (dld_undefined_sym_count > 0)
+ {
+ if (dld_link("/usr/lib/libm.a"))
+ {
+ elog(NOTICE, "dld: Cannot link math library!");
+ return NULL;
+ }
+ if (dld_undefined_sym_count > 0)
+ {
+ int count = dld_undefined_sym_count;
+ char **list = dld_list_undefined_sym();
- dld_unlink_by_file(filename, 1);
- return NULL;
- }
+ /* list the undefined symbols, if any */
+ elog(NOTICE, "dld: Undefined:");
+ do
+ {
+ elog(NOTICE, " %s", *list);
+ list++;
+ count--;
+ } while (count > 0);
+
+ dld_unlink_by_file(filename, 1);
+ return NULL;
+ }
+ }
}
- }
- return (void *) strdup(filename);
+ return (void *) strdup(filename);
}
-char *
+char *
pg_dlerror()
{
- return dld_strerror(dld_errno);
+ return dld_strerror(dld_errno);
}
diff --git a/src/backend/port/dgux/port-protos.h b/src/backend/port/dgux/port-protos.h
index 13862f9a007..9ca45ba234a 100644
--- a/src/backend/port/dgux/port-protos.h
+++ b/src/backend/port/dgux/port-protos.h
@@ -1,30 +1,30 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for SunOS 4
+ * port-specific prototypes for SunOS 4
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.1 1996/07/25 20:44:00 scrappy Exp $
+ * $Id: port-protos.h,v 1.2 1997/09/07 04:45:39 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PORT_PROTOS_H
#define PORT_PROTOS_H
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
#include "dlfcn.h"
/* dynloader.c */
-/* #define pg_dlopen(f) dlopen(f, 1) */
-#define pg_dlopen(f) dlopen(f, 2)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+/* #define pg_dlopen(f) dlopen(f, 1) */
+#define pg_dlopen(f) dlopen(f, 2)
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
/* port.c */
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/dgux/port.c b/src/backend/port/dgux/port.c
index 46fe71db568..1cc325c0db0 100644
--- a/src/backend/port/dgux/port.c
+++ b/src/backend/port/dgux/port.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * Linux-specific routines
+ * Linux-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/dgux/Attic/port.c,v 1.1 1996/07/25 20:44:00 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/dgux/Attic/port.c,v 1.2 1997/09/07 04:45:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
diff --git a/src/backend/port/hpux/dynloader.c b/src/backend/port/hpux/dynloader.c
index deea2e1dc29..3c7a8acaa7a 100644
--- a/src/backend/port/hpux/dynloader.c
+++ b/src/backend/port/hpux/dynloader.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* dynloader.c--
- * dynamic loader for HP-UX using the shared library mechanism
+ * dynamic loader for HP-UX using the shared library mechanism
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/hpux/Attic/dynloader.c,v 1.1.1.1 1996/07/09 06:21:43 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/hpux/Attic/dynloader.c,v 1.2 1997/09/07 04:45:44 momjian Exp $
*
- * NOTES
- * all functions are defined here -- it's impossible to trace the
- * shl_* routines from the bundled HP-UX debugger.
+ * NOTES
+ * all functions are defined here -- it's impossible to trace the
+ * shl_* routines from the bundled HP-UX debugger.
*
*-------------------------------------------------------------------------
*/
@@ -24,34 +24,36 @@
#include "utils/dynamic_loader.h"
#include "port-protos.h"
-void *
+void *
pg_dlopen(char *filename)
{
- shl_t handle = shl_load(filename, BIND_DEFERRED, 0);
+ shl_t handle = shl_load(filename, BIND_DEFERRED, 0);
- return((void *) handle);
+ return ((void *) handle);
}
func_ptr
pg_dlsym(void *handle, char *funcname)
{
- func_ptr f;
+ func_ptr f;
- if (shl_findsym((shl_t *) &handle, funcname, TYPE_PROCEDURE, &f) == -1) {
- f = (func_ptr) NULL;
- }
- return(f);
+ if (shl_findsym((shl_t *) & handle, funcname, TYPE_PROCEDURE, &f) == -1)
+ {
+ f = (func_ptr) NULL;
+ }
+ return (f);
}
void
pg_dlclose(void *handle)
{
- shl_unload((shl_t) handle);
+ shl_unload((shl_t) handle);
}
-char *
+char *
pg_dlerror()
{
- static char errmsg[]= "shl_load failed";
- return errmsg;
+ static char errmsg[] = "shl_load failed";
+
+ return errmsg;
}
diff --git a/src/backend/port/hpux/fixade.h b/src/backend/port/hpux/fixade.h
index 62324eb05d7..094cd13ca83 100644
--- a/src/backend/port/hpux/fixade.h
+++ b/src/backend/port/hpux/fixade.h
@@ -1,63 +1,66 @@
/*-------------------------------------------------------------------------
*
* fixade.h--
- * compiler tricks to make things work while POSTGRES does non-native
- * dereferences on PA-RISC.
+ * compiler tricks to make things work while POSTGRES does non-native
+ * dereferences on PA-RISC.
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: fixade.h,v 1.1.1.1 1996/07/09 06:21:43 scrappy Exp $
+ * $Id: fixade.h,v 1.2 1997/09/07 04:45:48 momjian Exp $
*
- * NOTES
- * This must be included in EVERY source file.
+ * NOTES
+ * This must be included in EVERY source file.
*
*-------------------------------------------------------------------------
*/
-#ifndef FIXADE_H
+#ifndef FIXADE_H
#define FIXADE_H
#if !defined(NOFIXADE)
#if defined(HP_S500_ALIGN)
/* ----------------
- * This cheesy hack turns ON unaligned-access fixup on H-P PA-RISC;
- * the resulting object files contain code that explicitly handles
- * realignment on reference, so it slows memory access down by a
- * considerable factor. It must be used in conjunction with the +u
- * flag to cc. The #pragma is included in c.h to be safe since EVERY
- * source file that performs unaligned access must contain the #pragma.
+ * This cheesy hack turns ON unaligned-access fixup on H-P PA-RISC;
+ * the resulting object files contain code that explicitly handles
+ * realignment on reference, so it slows memory access down by a
+ * considerable factor. It must be used in conjunction with the +u
+ * flag to cc. The #pragma is included in c.h to be safe since EVERY
+ * source file that performs unaligned access must contain the #pragma.
* ----------------
*/
#pragma HP_ALIGN HPUX_NATURAL_S500
#if defined(BROKEN_STRUCT_INIT)
/* ----------------
- * This is so bogus. The HP-UX 9.01 compiler has totally broken
- * struct initialization code. It actually length-checks ALL
- * array initializations within structs against the FIRST one that
- * it sees (when #pragma HP_ALIGN HPUX_NATURAL_S500 is defined)..
- * we have to throw in this unused structure before struct varlena
- * is defined.
+ * This is so bogus. The HP-UX 9.01 compiler has totally broken
+ * struct initialization code. It actually length-checks ALL
+ * array initializations within structs against the FIRST one that
+ * it sees (when #pragma HP_ALIGN HPUX_NATURAL_S500 is defined)..
+ * we have to throw in this unused structure before struct varlena
+ * is defined.
*
- * XXX guess you don't need the #pragma anymore after all :-)
- * since no one looks at this except me i think i'll just leave
- * this here for now..
+ * XXX guess you don't need the #pragma anymore after all :-)
+ * since no one looks at this except me i think i'll just leave
+ * this here for now..
* ----------------
*/
-struct HP_WAY_BOGUS {
- char hpwb_bogus[8192];
+struct HP_WAY_BOGUS
+{
+ char hpwb_bogus[8192];
};
-struct HP_TOO_BOGUS {
- int hptb_bogus[8192];
+struct HP_TOO_BOGUS
+{
+ int hptb_bogus[8192];
};
-#endif /* BROKEN_STRUCT_INIT */
-#endif /* HP_S500_ALIGN */
+
+#endif /* BROKEN_STRUCT_INIT */
+#endif /* HP_S500_ALIGN */
#if defined(WEAK_C_OPTIMIZER)
#pragma OPT_LEVEL 1
-#endif /* WEAK_C_OPTIMIZER */
+#endif /* WEAK_C_OPTIMIZER */
-#endif /* !NOFIXADE */
+#endif /* !NOFIXADE */
-#endif /* FIXADE_H */
+#endif /* FIXADE_H */
diff --git a/src/backend/port/hpux/port-protos.h b/src/backend/port/hpux/port-protos.h
index 33d2dd66def..76b336aae22 100644
--- a/src/backend/port/hpux/port-protos.h
+++ b/src/backend/port/hpux/port-protos.h
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for HP-UX
+ * port-specific prototypes for HP-UX
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.2 1997/07/27 18:51:57 momjian Exp $
+ * $Id: port-protos.h,v 1.3 1997/09/07 04:45:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -14,7 +14,7 @@
#define PORT_PROTOS_H
#include <sys/resource.h> /* for struct rusage */
-#include <dl.h> /* for shl_t */
+#include <dl.h> /* for shl_t */
#include "utils/dynamic_loader.h"
@@ -24,11 +24,11 @@
/* port.c */
-extern int init_address_fixup(void);
-extern double rint(double x);
-extern double cbrt(double x);
-extern long random(void);
-extern void srandom(unsigned seed);
-extern int getrusage(int who, struct rusage *ru);
+extern int init_address_fixup(void);
+extern double rint(double x);
+extern double cbrt(double x);
+extern long random(void);
+extern void srandom(unsigned seed);
+extern int getrusage(int who, struct rusage * ru);
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/hpux/port.c b/src/backend/port/hpux/port.c
index 205a3178267..8f37cd44484 100644
--- a/src/backend/port/hpux/port.c
+++ b/src/backend/port/hpux/port.c
@@ -1,47 +1,49 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * port-specific routines for HP-UX
+ * port-specific routines for HP-UX
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/hpux/Attic/port.c,v 1.2 1997/07/27 18:52:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/hpux/Attic/port.c,v 1.3 1997/09/07 04:45:52 momjian Exp $
*
* NOTES
- * For the most part, this file gets around some non-POSIX calls
- * in POSTGRES.
+ * For the most part, this file gets around some non-POSIX calls
+ * in POSTGRES.
*
*-------------------------------------------------------------------------
*/
-#include <unistd.h> /* for rand()/srand() prototypes */
-#include <math.h> /* for pow() prototype */
-#include <sys/syscall.h> /* for syscall #defines */
+#include <unistd.h> /* for rand()/srand() prototypes */
+#include <math.h> /* for pow() prototype */
+#include <sys/syscall.h> /* for syscall #defines */
#include "c.h"
void
init_address_fixup()
{
- /*
- * On PA-RISC, unaligned access fixup is handled by the compiler,
- * not by the kernel.
- */
+
+ /*
+ * On PA-RISC, unaligned access fixup is handled by the compiler, not
+ * by the kernel.
+ */
}
long
random()
{
- return(lrand48());
+ return (lrand48());
}
-void srandom(unsigned seed)
+void
+srandom(unsigned seed)
{
srand48((long int) seed);
}
-getrusage(int who, struct rusage *ru)
+getrusage(int who, struct rusage * ru)
{
- return(syscall(SYS_GETRUSAGE, who, ru));
+ return (syscall(SYS_GETRUSAGE, who, ru));
}
diff --git a/src/backend/port/hpux/rusagestub.h b/src/backend/port/hpux/rusagestub.h
index d2393eb792d..5eda998802e 100644
--- a/src/backend/port/hpux/rusagestub.h
+++ b/src/backend/port/hpux/rusagestub.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* rusagestub.h--
- * Stubs for getrusage(3).
+ * Stubs for getrusage(3).
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -13,18 +13,19 @@
#ifndef RUSAGESTUB_H
#define RUSAGESTUB_H
-#include <sys/time.h> /* for struct timeval */
-#include <sys/times.h> /* for struct tms */
-#include <limits.h> /* for CLK_TCK */
+#include <sys/time.h> /* for struct timeval */
+#include <sys/times.h> /* for struct tms */
+#include <limits.h> /* for CLK_TCK */
-#define RUSAGE_SELF 0
-#define RUSAGE_CHILDREN -1
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN -1
-struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
+struct rusage
+{
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
};
-extern int getrusage(int who, struct rusage *rusage);
+extern int getrusage(int who, struct rusage * rusage);
-#endif /* RUSAGESTUB_H */
+#endif /* RUSAGESTUB_H */
diff --git a/src/backend/port/i386_solaris/port-protos.h b/src/backend/port/i386_solaris/port-protos.h
index 45e56ad1e75..6118a650460 100644
--- a/src/backend/port/i386_solaris/port-protos.h
+++ b/src/backend/port/i386_solaris/port-protos.h
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for SunOS 4
+ * port-specific prototypes for SunOS 4
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.1 1996/07/20 08:34:33 scrappy Exp $
+ * $Id: port-protos.h,v 1.2 1997/09/07 04:45:56 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -14,25 +14,25 @@
#define PORT_PROTOS_H
#include <dlfcn.h>
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
/*
* Dynamic Loader on SunOS 4.
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
*/
#define pg_dlopen(f) dlopen(f,1)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
/* port.c */
-extern long random(void);
-extern void srandom(int seed);
+extern long random(void);
+extern void srandom(int seed);
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/i386_solaris/port.c b/src/backend/port/i386_solaris/port.c
index c6fcdab98e7..119163a1869 100644
--- a/src/backend/port/i386_solaris/port.c
+++ b/src/backend/port/i386_solaris/port.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * SunOS5-specific routines
+ * SunOS5-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/i386_solaris/Attic/port.c,v 1.1 1996/07/20 08:34:34 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/i386_solaris/Attic/port.c,v 1.2 1997/09/07 04:45:58 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <math.h> /* for pow() prototype */
+#include <math.h> /* for pow() prototype */
#include <errno.h>
#include "rusagestub.h"
@@ -19,48 +19,52 @@
long
random()
{
- return(lrand48());
+ return (lrand48());
}
void
srandom(int seed)
{
- srand48((long int) seed);
+ srand48((long int) seed);
}
int
-getrusage(int who, struct rusage *rusage)
+getrusage(int who, struct rusage * rusage)
{
- struct tms tms;
- register int tick_rate = CLK_TCK; /* ticks per second */
- clock_t u, s;
+ struct tms tms;
+ register int tick_rate = CLK_TCK; /* ticks per second */
+ clock_t u,
+ s;
- if (rusage == (struct rusage *) NULL) {
- errno = EFAULT;
- return(-1);
- }
- if (times(&tms) < 0) {
- /* errno set by times */
- return(-1);
- }
- switch (who) {
- case RUSAGE_SELF:
- u = tms.tms_utime;
- s = tms.tms_stime;
- break;
- case RUSAGE_CHILDREN:
- u = tms.tms_cutime;
- s = tms.tms_cstime;
- break;
- default:
- errno = EINVAL;
- return(-1);
- }
+ if (rusage == (struct rusage *) NULL)
+ {
+ errno = EFAULT;
+ return (-1);
+ }
+ if (times(&tms) < 0)
+ {
+ /* errno set by times */
+ return (-1);
+ }
+ switch (who)
+ {
+ case RUSAGE_SELF:
+ u = tms.tms_utime;
+ s = tms.tms_stime;
+ break;
+ case RUSAGE_CHILDREN:
+ u = tms.tms_cutime;
+ s = tms.tms_cstime;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
#define TICK_TO_SEC(T, RATE) ((T)/(RATE))
-#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
- rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
- rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
- rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
- rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
- return(0);
+#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
+ rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
+ rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
+ rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ return (0);
}
diff --git a/src/backend/port/i386_solaris/rusagestub.h b/src/backend/port/i386_solaris/rusagestub.h
index 0ad45fafaad..c6e2ceae453 100644
--- a/src/backend/port/i386_solaris/rusagestub.h
+++ b/src/backend/port/i386_solaris/rusagestub.h
@@ -1,30 +1,31 @@
/*-------------------------------------------------------------------------
*
* rusagestub.h--
- * Stubs for getrusage(3).
+ * Stubs for getrusage(3).
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: rusagestub.h,v 1.1 1996/07/20 08:34:34 scrappy Exp $
+ * $Id: rusagestub.h,v 1.2 1997/09/07 04:46:04 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef RUSAGESTUB_H
#define RUSAGESTUB_H
-#include <sys/time.h> /* for struct timeval */
-#include <sys/times.h> /* for struct tms */
-#include <limits.h> /* for CLK_TCK */
+#include <sys/time.h> /* for struct timeval */
+#include <sys/times.h> /* for struct tms */
+#include <limits.h> /* for CLK_TCK */
-#define RUSAGE_SELF 0
-#define RUSAGE_CHILDREN -1
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN -1
-struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
+struct rusage
+{
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
};
-extern int getrusage(int who, struct rusage *rusage);
+extern int getrusage(int who, struct rusage * rusage);
-#endif /* RUSAGESTUB_H */
+#endif /* RUSAGESTUB_H */
diff --git a/src/backend/port/inet_aton.c b/src/backend/port/inet_aton.c
index 37c11b621b7..122875eda3b 100644
--- a/src/backend/port/inet_aton.c
+++ b/src/backend/port/inet_aton.c
@@ -1,39 +1,39 @@
/*
*
- * This inet_aton() function was taken from the GNU C library and
- * incorporated into Postgres for those systems which do not have this
- * routine in their standard C libraries.
+ * This inet_aton() function was taken from the GNU C library and
+ * incorporated into Postgres for those systems which do not have this
+ * routine in their standard C libraries.
*
- * The function was been extracted whole from the file inet_aton.c in
- * Release 5.3.12 of the Linux C library, which is derived from the
- * GNU C library, by Bryan Henderson in October 1996. The copyright
- * notice from that file is below.
+ * The function was been extracted whole from the file inet_aton.c in
+ * Release 5.3.12 of the Linux C library, which is derived from the
+ * GNU C library, by Bryan Henderson in October 1996. The copyright
+ * notice from that file is below.
*/
/*
* Copyright (c) 1983, 1990, 1993
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* 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)
@@ -55,82 +55,92 @@
* cannot distinguish between failure and a local broadcast address.
*/
int
-inet_aton(const char *cp, struct in_addr *addr)
+inet_aton(const char *cp, struct in_addr * addr)
{
register u_long val;
- register int base, n;
- register char c;
- u_int parts[4];
+ register int base,
+ n;
+ register char c;
+ u_int parts[4];
register u_int *pp = parts;
- for (;;) {
+ for (;;)
+ {
+
/*
- * Collect number up to ``.''.
- * Values are specified as for C:
+ * Collect number up to ``.''. Values are specified as for C:
* 0x=hex, 0=octal, other=decimal.
*/
- val = 0; base = 10;
- if (*cp == '0') {
+ val = 0;
+ base = 10;
+ if (*cp == '0')
+ {
if (*++cp == 'x' || *cp == 'X')
base = 16, cp++;
else
base = 8;
}
- while ((c = *cp) != '\0') {
- if (isascii(c) && isdigit(c)) {
+ while ((c = *cp) != '\0')
+ {
+ if (isascii(c) && isdigit(c))
+ {
val = (val * base) + (c - '0');
cp++;
continue;
}
- if (base == 16 && isascii(c) && isxdigit(c)) {
- val = (val << 4) +
+ if (base == 16 && isascii(c) && isxdigit(c))
+ {
+ val = (val << 4) +
(c + 10 - (islower(c) ? 'a' : 'A'));
cp++;
continue;
}
break;
}
- if (*cp == '.') {
+ if (*cp == '.')
+ {
+
/*
- * Internet format:
- * a.b.c.d
- * a.b.c (with c treated as 16-bits)
- * a.b (with b treated as 24 bits)
+ * Internet format: a.b.c.d a.b.c (with c treated as
+ * 16-bits) a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3 || val > 0xff)
return (0);
*pp++ = val, cp++;
- } else
+ }
+ else
break;
}
+
/*
* Check for trailing characters.
*/
if (*cp && (!isascii(*cp) || !isspace(*cp)))
return (0);
+
/*
- * Concoct the address according to
- * the number of parts specified.
+ * Concoct the address according to the number of parts specified.
*/
n = pp - parts + 1;
- switch (n) {
+ switch (n)
+ {
- case 1: /* a -- 32 bits */
+ case 1: /* a -- 32 bits */
break;
- case 2: /* a.b -- 8.24 bits */
+ case 2: /* a.b -- 8.24 bits */
if (val > 0xffffff)
return (0);
val |= parts[0] << 24;
break;
- case 3: /* a.b.c -- 8.8.16 bits */
+ case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16);
break;
- case 4: /* a.b.c.d -- 8.8.8.8 bits */
+ case 4: /* a.b.c.d -- 8.8.8.8 bits */
if (val > 0xff)
return (0);
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);
diff --git a/src/backend/port/inet_aton.h b/src/backend/port/inet_aton.h
index 6909bd2b12d..b1df9a8ff3d 100644
--- a/src/backend/port/inet_aton.h
+++ b/src/backend/port/inet_aton.h
@@ -1,2 +1,2 @@
int
-inet_aton(const char *cp, struct in_addr *addr);
+ inet_aton(const char *cp, struct in_addr * addr);
diff --git a/src/backend/port/irix5/port-protos.h b/src/backend/port/irix5/port-protos.h
index 3f580758416..be894ed5b12 100644
--- a/src/backend/port/irix5/port-protos.h
+++ b/src/backend/port/irix5/port-protos.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for Irix 5
+ * port-specific prototypes for Irix 5
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -14,24 +14,24 @@
#define PORT_PROTOS_H
#include <dlfcn.h>
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
/*
* Dynamic Loader on SunOS 4.
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
*/
#define pg_dlopen(f) dlopen(f,1)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
/* port.c */
-extern long random(void);
+extern long random(void);
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/irix5/port.c b/src/backend/port/irix5/port.c
index 82303ed7fcb..6c60ade72f9 100644
--- a/src/backend/port/irix5/port.c
+++ b/src/backend/port/irix5/port.c
@@ -1,16 +1,16 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * Irix5-specific routines
+ * Irix5-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/port/sparc_solaris/port.c,v 1.2 1995/03/17 06:40:19 andrew Exp
+ * /usr/local/devel/pglite/cvs/src/backend/port/sparc_solaris/port.c,v 1.2 1995/03/17 06:40:19 andrew Exp
*
*-------------------------------------------------------------------------
*/
-#include <math.h> /* for pow() prototype */
+#include <math.h> /* for pow() prototype */
#include <errno.h>
diff --git a/src/backend/port/linux/dynloader.c b/src/backend/port/linux/dynloader.c
index a3b551b6f95..adb13b40194 100644
--- a/src/backend/port/linux/dynloader.c
+++ b/src/backend/port/linux/dynloader.c
@@ -1,16 +1,16 @@
/*-------------------------------------------------------------------------
*
* dynloader.c--
- * Dynamic Loader for Postgres for Linux, generated from those for
- * Ultrix.
+ * Dynamic Loader for Postgres for Linux, generated from those for
+ * Ultrix.
*
- * You need to install the dld library on your Linux system!
+ * You need to install the dld library on your Linux system!
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/linux/Attic/dynloader.c,v 1.2 1997/02/06 08:39:40 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/linux/Attic/dynloader.c,v 1.3 1997/09/07 04:46:12 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,82 +23,92 @@
#include "utils/elog.h"
#include "fmgr.h"
-extern char pg_pathname[];
+extern char pg_pathname[];
-void *
+void *
pg_dlopen(char *filename)
{
#ifndef HAVE_DLD_H
- elog(WARN, "dynamic load not supported");
- return(NULL);
+ elog(WARN, "dynamic load not supported");
+ return (NULL);
#else
- static int dl_initialized= 0;
+ static int dl_initialized = 0;
- /*
- * initializes the dynamic loader with the executable's pathname.
- * (only needs to do this the first time pg_dlopen is called.)
- */
- if (!dl_initialized) {
- if (dld_init (dld_find_executable (pg_pathname))) {
- return NULL;
- }
/*
- * if there are undefined symbols, we want dl to search from the
- * following libraries also.
+ * initializes the dynamic loader with the executable's pathname.
+ * (only needs to do this the first time pg_dlopen is called.)
*/
- dl_initialized= 1;
- }
-
- /*
- * link the file, then check for undefined symbols!
- */
- if (dld_link(filename)) {
- return NULL;
- }
+ if (!dl_initialized)
+ {
+ if (dld_init(dld_find_executable(pg_pathname)))
+ {
+ return NULL;
+ }
- /*
- * If undefined symbols: try to link with the C and math libraries!
- * This could be smarter, if the dynamic linker was able to handle
- * shared libs!
- */
- if(dld_undefined_sym_count > 0) {
- if (dld_link("/usr/lib/libc.a")) {
- elog(NOTICE, "dld: Cannot link C library!");
- return NULL;
+ /*
+ * if there are undefined symbols, we want dl to search from the
+ * following libraries also.
+ */
+ dl_initialized = 1;
}
- if(dld_undefined_sym_count > 0) {
- if (dld_link("/usr/lib/libm.a")) {
- elog(NOTICE, "dld: Cannot link math library!");
+
+ /*
+ * link the file, then check for undefined symbols!
+ */
+ if (dld_link(filename))
+ {
return NULL;
- }
- if(dld_undefined_sym_count > 0) {
- int count = dld_undefined_sym_count;
- char **list= dld_list_undefined_sym();
+ }
- /* list the undefined symbols, if any */
- elog(NOTICE, "dld: Undefined:");
- do {
- elog(NOTICE, " %s", *list);
- list++;
- count--;
- } while(count > 0);
+ /*
+ * If undefined symbols: try to link with the C and math libraries!
+ * This could be smarter, if the dynamic linker was able to handle
+ * shared libs!
+ */
+ if (dld_undefined_sym_count > 0)
+ {
+ if (dld_link("/usr/lib/libc.a"))
+ {
+ elog(NOTICE, "dld: Cannot link C library!");
+ return NULL;
+ }
+ if (dld_undefined_sym_count > 0)
+ {
+ if (dld_link("/usr/lib/libm.a"))
+ {
+ elog(NOTICE, "dld: Cannot link math library!");
+ return NULL;
+ }
+ if (dld_undefined_sym_count > 0)
+ {
+ int count = dld_undefined_sym_count;
+ char **list = dld_list_undefined_sym();
- dld_unlink_by_file(filename, 1);
- return NULL;
- }
+ /* list the undefined symbols, if any */
+ elog(NOTICE, "dld: Undefined:");
+ do
+ {
+ elog(NOTICE, " %s", *list);
+ list++;
+ count--;
+ } while (count > 0);
+
+ dld_unlink_by_file(filename, 1);
+ return NULL;
+ }
+ }
}
- }
- return (void *) strdup(filename);
+ return (void *) strdup(filename);
#endif
}
-char *
+char *
pg_dlerror()
{
#ifndef HAVE_DLD_H
- return("dynaloader unspported");
+ return ("dynaloader unspported");
#else
- return dld_strerror(dld_errno);
+ return dld_strerror(dld_errno);
#endif
}
diff --git a/src/backend/port/linux/port-protos.h b/src/backend/port/linux/port-protos.h
index 76f02b48fe9..f5af9beecee 100644
--- a/src/backend/port/linux/port-protos.h
+++ b/src/backend/port/linux/port-protos.h
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for SunOS 4
+ * port-specific prototypes for SunOS 4
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.2 1997/02/06 08:39:53 scrappy Exp $
+ * $Id: port-protos.h,v 1.3 1997/09/07 04:46:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PORT_PROTOS_H
#define PORT_PROTOS_H
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
#ifdef LINUX_ELF
#include "dlfcn.h"
@@ -22,21 +22,21 @@
/* dynloader.c */
#ifndef LINUX_ELF
-# ifndef HAVE_DLD_H
-#define pg_dlsym(handle, funcname) (NULL)
-# define pg_dlclose(handle) ({})
-# else
-#define pg_dlsym(handle, funcname) ((func_ptr) dld_get_func((funcname)))
-# define pg_dlclose(handle) ({ dld_unlink_by_file(handle, 1); free(handle); })
-# endif
+#ifndef HAVE_DLD_H
+#define pg_dlsym(handle, funcname) (NULL)
+#define pg_dlclose(handle) ({})
#else
-/* #define pg_dlopen(f) dlopen(f, 1) */
-#define pg_dlopen(f) dlopen(f, 2)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlsym(handle, funcname) ((func_ptr) dld_get_func((funcname)))
+#define pg_dlclose(handle) ({ dld_unlink_by_file(handle, 1); free(handle); })
+#endif
+#else
+/* #define pg_dlopen(f) dlopen(f, 1) */
+#define pg_dlopen(f) dlopen(f, 2)
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
#endif
/* port.c */
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/linux/port.c b/src/backend/port/linux/port.c
index e4c5edfb9e5..942340f40fd 100644
--- a/src/backend/port/linux/port.c
+++ b/src/backend/port/linux/port.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * Linux-specific routines
+ * Linux-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/linux/Attic/port.c,v 1.1.1.1 1996/07/09 06:21:44 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/linux/Attic/port.c,v 1.2 1997/09/07 04:46:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
diff --git a/src/backend/port/linuxalpha/machine.h b/src/backend/port/linuxalpha/machine.h
index 78d45d41ba9..eee148e390c 100644
--- a/src/backend/port/linuxalpha/machine.h
+++ b/src/backend/port/linuxalpha/machine.h
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* machine.h--
- *
+ *
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: machine.h,v 1.1 1997/03/14 06:01:21 scrappy Exp $
+ * $Id: machine.h,v 1.2 1997/09/07 04:46:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
diff --git a/src/backend/port/linuxalpha/port-protos.h b/src/backend/port/linuxalpha/port-protos.h
index 7bcbaf020d1..350c0c52809 100644
--- a/src/backend/port/linuxalpha/port-protos.h
+++ b/src/backend/port/linuxalpha/port-protos.h
@@ -1,25 +1,25 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for SunOS 4
+ * port-specific prototypes for SunOS 4
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.1 1997/03/14 06:01:33 scrappy Exp $
+ * $Id: port-protos.h,v 1.2 1997/09/07 04:46:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PORT_PROTOS_H
#define PORT_PROTOS_H
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
#include "dlfcn.h"
-#define pg_dlopen(f) dlopen(f, 2)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlopen(f) dlopen(f, 2)
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/linuxalpha/port.c b/src/backend/port/linuxalpha/port.c
index a9886814449..8ddc6ddc1e3 100644
--- a/src/backend/port/linuxalpha/port.c
+++ b/src/backend/port/linuxalpha/port.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * Linux-specific routines
+ * Linux-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/linuxalpha/Attic/port.c,v 1.1 1997/03/14 06:01:40 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/linuxalpha/Attic/port.c,v 1.2 1997/09/07 04:46:28 momjian Exp $
*
*-------------------------------------------------------------------------
*/
diff --git a/src/backend/port/nextstep/dynloader.c b/src/backend/port/nextstep/dynloader.c
index af183d436de..c37508f7f19 100644
--- a/src/backend/port/nextstep/dynloader.c
+++ b/src/backend/port/nextstep/dynloader.c
@@ -2,71 +2,80 @@
#include <streams/streams.h>
#include <stdlib.h>
-static char* lastError = NULL;
+static char *lastError = NULL;
-static NXStream* OpenError()
+static NXStream *
+OpenError()
{
- return NXOpenMemory(NULL, 0, NX_WRITEONLY);
+ return NXOpenMemory(NULL, 0, NX_WRITEONLY);
}
-static void CloseError(NXStream* s)
+static void
+CloseError(NXStream * s)
{
- if (s)
- NXCloseMemory (s, NX_FREEBUFFER);
+ if (s)
+ NXCloseMemory(s, NX_FREEBUFFER);
}
-static void TransferError(NXStream* s)
+static void
+TransferError(NXStream * s)
{
- char *buffer;
- int len, maxlen;
+ char *buffer;
+ int len,
+ maxlen;
- if (lastError)
- free (lastError);
- NXGetMemoryBuffer (s, &buffer, &len, &maxlen);
- lastError = malloc (len + 1);
- strcpy (lastError, buffer);
+ if (lastError)
+ free(lastError);
+ NXGetMemoryBuffer(s, &buffer, &len, &maxlen);
+ lastError = malloc(len + 1);
+ strcpy(lastError, buffer);
}
-void* next_dlopen(char* name)
+void *
+next_dlopen(char *name)
{
- int rld_success;
- NXStream* errorStream;
- char* result = NULL;
- char **p;
-
- errorStream = OpenError();
- p = calloc (2, sizeof(void*));
- p[0] = name;
- rld_success = rld_load(errorStream, NULL, p, NULL);
- free (p);
+ int rld_success;
+ NXStream *errorStream;
+ char *result = NULL;
+ char **p;
- if (!rld_success) {
- TransferError (errorStream);
- result = (char*)1;
- }
- CloseError (errorStream);
- return result;
+ errorStream = OpenError();
+ p = calloc(2, sizeof(void *));
+ p[0] = name;
+ rld_success = rld_load(errorStream, NULL, p, NULL);
+ free(p);
+
+ if (!rld_success)
+ {
+ TransferError(errorStream);
+ result = (char *) 1;
+ }
+ CloseError(errorStream);
+ return result;
}
-int next_dlclose(void* handle)
+int
+next_dlclose(void *handle)
{
- return 0;
+ return 0;
}
-void* next_dlsym (void *handle, char *symbol)
+void *
+next_dlsym(void *handle, char *symbol)
{
- NXStream* errorStream = OpenError();
- char symbuf[1024];
- unsigned long symref = 0;
+ NXStream *errorStream = OpenError();
+ char symbuf[1024];
+ unsigned long symref = 0;
- sprintf(symbuf, "_%s", symbol);
- if (!rld_lookup (errorStream, symbuf, &symref))
- TransferError(errorStream);
- CloseError(errorStream);
- return (void*) symref;
+ sprintf(symbuf, "_%s", symbol);
+ if (!rld_lookup(errorStream, symbuf, &symref))
+ TransferError(errorStream);
+ CloseError(errorStream);
+ return (void *) symref;
}
-char* next_dlerror(void)
+char *
+next_dlerror(void)
{
- return lastError;
+ return lastError;
}
diff --git a/src/backend/port/nextstep/port-protos.h b/src/backend/port/nextstep/port-protos.h
index 93fec7642f0..ce17beb69a6 100644
--- a/src/backend/port/nextstep/port-protos.h
+++ b/src/backend/port/nextstep/port-protos.h
@@ -1,27 +1,27 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for NeXT
+ * port-specific prototypes for NeXT
*
-
+
-------------------------------------------------------------------------
*/
#ifndef PORT_PROTOS_H
#define PORT_PROTOS_H
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
-void* next_dlopen(char* name);
-int next_dlclose(void* handle);
-void* next_dlsym (void *handle, char *symbol);
-char* next_dlerror(void);
+void *next_dlopen(char *name);
+int next_dlclose(void *handle);
+void *next_dlsym(void *handle, char *symbol);
+char *next_dlerror(void);
-#define pg_dlopen(f) next_dlopen
-#define pg_dlsym next_dlsym
-#define pg_dlclose next_dlclose
-#define pg_dlerror next_dlerror
+#define pg_dlopen(f) next_dlopen
+#define pg_dlsym next_dlsym
+#define pg_dlclose next_dlclose
+#define pg_dlerror next_dlerror
/* port.c */
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/nextstep/port.c b/src/backend/port/nextstep/port.c
index 3da87b32eb8..baf026d5d1d 100644
--- a/src/backend/port/nextstep/port.c
+++ b/src/backend/port/nextstep/port.c
@@ -1,58 +1,65 @@
#ifndef _POSIX_SOURCE
-# include <libc.h>
+#include <libc.h>
#else
-# include <unistd.h>
-# include <stdlib.h>
+#include <unistd.h>
+#include <stdlib.h>
#endif
#include <string.h>
#include <sys/signal.h>
-void putenv(char* name)
+void
+putenv(char *name)
{
- extern char** environ;
- static int was_mallocated = 0;
- int size;
-
- /* Compute the size of environ array including the final NULL */
- for (size = 1; environ[size++];)
- /* nothing */;
-
- if (!was_mallocated) {
- char** tmp = environ;
- int i;
-
- was_mallocated = 1;
- environ = malloc (size * sizeof(char*));
- for (i = 0; i < size; i++)
- environ[i] = tmp[i];
- }
-
- environ = realloc (environ, (size + 1) * sizeof (char*));
- environ[size - 1] = strcpy (malloc (strlen (name) + 1), name);
- environ[size] = NULL;
+ extern char **environ;
+ static int was_mallocated = 0;
+ int size;
+
+ /* Compute the size of environ array including the final NULL */
+ for (size = 1; environ[size++];)
+ /* nothing */ ;
+
+ if (!was_mallocated)
+ {
+ char **tmp = environ;
+ int i;
+
+ was_mallocated = 1;
+ environ = malloc(size * sizeof(char *));
+ for (i = 0; i < size; i++)
+ environ[i] = tmp[i];
+ }
+
+ environ = realloc(environ, (size + 1) * sizeof(char *));
+ environ[size - 1] = strcpy(malloc(strlen(name) + 1), name);
+ environ[size] = NULL;
}
-char* strdup (const char* string)
+char *
+strdup(const char *string)
{
- return strcpy (malloc (strlen (string) + 1), string);
+ return strcpy(malloc(strlen(string) + 1), string);
}
#ifndef _POSIX_SOURCE
-int sigaddset(int *set, int signo)
+int
+sigaddset(int *set, int signo)
{
- *set |= sigmask(signo);
- return *set;
+ *set |= sigmask(signo);
+ return *set;
}
-int sigemptyset(int *set)
+int
+sigemptyset(int *set)
{
- return (*set = 0);
+ return (*set = 0);
}
-char *getcwd(char *buf, size_t size)
+char *
+getcwd(char *buf, size_t size)
{
- return getwd (buf);
+ return getwd(buf);
}
+
#endif
diff --git a/src/backend/port/sco/port-protos.h b/src/backend/port/sco/port-protos.h
index 17e3b02a265..9526f7c747d 100644
--- a/src/backend/port/sco/port-protos.h
+++ b/src/backend/port/sco/port-protos.h
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for SCO 3.2v5.2
+ * port-specific prototypes for SCO 3.2v5.2
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.1 1997/07/28 01:33:55 momjian Exp $
+ * $Id: port-protos.h,v 1.2 1997/09/07 04:46:41 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -14,23 +14,23 @@
#define PORT_PROTOS_H
#include <dlfcn.h>
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
/*
* Dynamic Loader on SCO 3.2v5.0.2
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
*/
#define pg_dlopen(f) dlopen(f,1)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
/* port.c */
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/sco/port.c b/src/backend/port/sco/port.c
index 3f1b84d6189..d1c868e8426 100644
--- a/src/backend/port/sco/port.c
+++ b/src/backend/port/sco/port.c
@@ -1,57 +1,60 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * SCO 3.2v5.0.2 specific routines
+ * SCO 3.2v5.0.2 specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/port/svr4/port.c,v 1.2 1995/03/17 06:40:19 andrew Exp
+ * /usr/local/devel/pglite/cvs/src/backend/port/svr4/port.c,v 1.2 1995/03/17 06:40:19 andrew Exp
*
*-------------------------------------------------------------------------
*/
#include <unistd.h>
-#include <math.h> /* for pow() prototype */
+#include <math.h> /* for pow() prototype */
#include <errno.h>
#include "rusagestub.h"
int
-getrusage(int who, struct rusage *rusage)
+getrusage(int who, struct rusage * rusage)
{
- struct tms tms;
- register int tick_rate = CLK_TCK; /* ticks per second */
- clock_t u, s;
+ struct tms tms;
+ register int tick_rate = CLK_TCK; /* ticks per second */
+ clock_t u,
+ s;
- if (rusage == (struct rusage *) NULL) {
- errno = EFAULT;
- return(-1);
- }
- if (times(&tms) < 0) {
- /* errno set by times */
- return(-1);
- }
- switch (who) {
- case RUSAGE_SELF:
- u = tms.tms_utime;
- s = tms.tms_stime;
- break;
- case RUSAGE_CHILDREN:
- u = tms.tms_cutime;
- s = tms.tms_cstime;
- break;
- default:
- errno = EINVAL;
- return(-1);
- }
+ if (rusage == (struct rusage *) NULL)
+ {
+ errno = EFAULT;
+ return (-1);
+ }
+ if (times(&tms) < 0)
+ {
+ /* errno set by times */
+ return (-1);
+ }
+ switch (who)
+ {
+ case RUSAGE_SELF:
+ u = tms.tms_utime;
+ s = tms.tms_stime;
+ break;
+ case RUSAGE_CHILDREN:
+ u = tms.tms_cutime;
+ s = tms.tms_cstime;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
#define TICK_TO_SEC(T, RATE) ((T)/(RATE))
-#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
- rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
- rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
- rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
- rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
- return(0);
+#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
+ rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
+ rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
+ rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ return (0);
}
-
diff --git a/src/backend/port/sco/rusagestub.h b/src/backend/port/sco/rusagestub.h
index d2393eb792d..5eda998802e 100644
--- a/src/backend/port/sco/rusagestub.h
+++ b/src/backend/port/sco/rusagestub.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* rusagestub.h--
- * Stubs for getrusage(3).
+ * Stubs for getrusage(3).
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -13,18 +13,19 @@
#ifndef RUSAGESTUB_H
#define RUSAGESTUB_H
-#include <sys/time.h> /* for struct timeval */
-#include <sys/times.h> /* for struct tms */
-#include <limits.h> /* for CLK_TCK */
+#include <sys/time.h> /* for struct timeval */
+#include <sys/times.h> /* for struct tms */
+#include <limits.h> /* for CLK_TCK */
-#define RUSAGE_SELF 0
-#define RUSAGE_CHILDREN -1
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN -1
-struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
+struct rusage
+{
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
};
-extern int getrusage(int who, struct rusage *rusage);
+extern int getrusage(int who, struct rusage * rusage);
-#endif /* RUSAGESTUB_H */
+#endif /* RUSAGESTUB_H */
diff --git a/src/backend/port/sparc_solaris/port-protos.h b/src/backend/port/sparc_solaris/port-protos.h
index c2cbf5803b5..95239173462 100644
--- a/src/backend/port/sparc_solaris/port-protos.h
+++ b/src/backend/port/sparc_solaris/port-protos.h
@@ -1,52 +1,52 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for SunOS 4
+ * port-specific prototypes for SunOS 4
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.4 1997/04/15 18:18:33 scrappy Exp $
+ * $Id: port-protos.h,v 1.5 1997/09/07 04:46:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PORT_PROTOS_H
#define PORT_PROTOS_H
-#include <netinet/in.h> /* For struct in_addr */
+#include <netinet/in.h> /* For struct in_addr */
#include <arpa/inet.h>
#include <dlfcn.h>
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
/*
* Dynamic Loader on SunOS 4.
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
*/
#define pg_dlopen(f) dlopen(f,1)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
/* port.c */
-extern long random(void);
-extern void srandom(int seed);
+extern long random(void);
+extern void srandom(int seed);
/* inet_aton.c in backend/port directory */
-extern int inet_aton(const char *cp, struct in_addr *addr);
+extern int inet_aton(const char *cp, struct in_addr * addr);
/* In system library, but can't find prototype in system library .h files */
-extern int gethostname(char *name, int namelen);
+extern int gethostname(char *name, int namelen);
/* In system library, but can't find prototype in system library .h files */
#include <sys/resource.h>
-extern int getrusage(int who, struct rusage *rusage);
+extern int getrusage(int who, struct rusage * rusage);
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/sparc_solaris/port.c b/src/backend/port/sparc_solaris/port.c
index 8710ec95451..7f19a1ae237 100644
--- a/src/backend/port/sparc_solaris/port.c
+++ b/src/backend/port/sparc_solaris/port.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * SunOS5-specific routines
+ * SunOS5-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/sparc_solaris/Attic/port.c,v 1.4 1997/04/15 18:18:45 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/sparc_solaris/Attic/port.c,v 1.5 1997/09/07 04:46:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <math.h> /* for pow() prototype */
+#include <math.h> /* for pow() prototype */
#include <stdlib.h>
#include <errno.h>
@@ -20,55 +20,60 @@
#include "port-protos.h"
#ifndef HAVE_GETRUSAGE
#include "rusagestub.h"
-#endif /* HAVE_GETRUSAGE */
+#endif /* HAVE_GETRUSAGE */
long
random()
{
- return(lrand48());
+ return (lrand48());
}
void
srandom(int seed)
{
- srand48((long int) seed);
+ srand48((long int) seed);
}
#ifndef HAVE_GETRUSAGE
int
-getrusage(int who, struct rusage *rusage)
+getrusage(int who, struct rusage * rusage)
{
- struct tms tms;
- register int tick_rate = CLK_TCK; /* ticks per second */
- clock_t u, s;
+ struct tms tms;
+ register int tick_rate = CLK_TCK; /* ticks per second */
+ clock_t u,
+ s;
- if (rusage == (struct rusage *) NULL) {
- errno = EFAULT;
- return(-1);
- }
- if (times(&tms) < 0) {
- /* errno set by times */
- return(-1);
- }
- switch (who) {
- case RUSAGE_SELF:
- u = tms.tms_utime;
- s = tms.tms_stime;
- break;
- case RUSAGE_CHILDREN:
- u = tms.tms_cutime;
- s = tms.tms_cstime;
- break;
- default:
- errno = EINVAL;
- return(-1);
- }
+ if (rusage == (struct rusage *) NULL)
+ {
+ errno = EFAULT;
+ return (-1);
+ }
+ if (times(&tms) < 0)
+ {
+ /* errno set by times */
+ return (-1);
+ }
+ switch (who)
+ {
+ case RUSAGE_SELF:
+ u = tms.tms_utime;
+ s = tms.tms_stime;
+ break;
+ case RUSAGE_CHILDREN:
+ u = tms.tms_cutime;
+ s = tms.tms_cstime;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
#define TICK_TO_SEC(T, RATE) ((T)/(RATE))
-#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
- rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
- rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
- rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
- rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
- return(0);
+#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
+ rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
+ rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
+ rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ return (0);
}
-#endif /* HAVE_GETRUSAGE */
+
+#endif /* HAVE_GETRUSAGE */
diff --git a/src/backend/port/sparc_solaris/rusagestub.h b/src/backend/port/sparc_solaris/rusagestub.h
index 5e413bd0d9a..87957a45eac 100644
--- a/src/backend/port/sparc_solaris/rusagestub.h
+++ b/src/backend/port/sparc_solaris/rusagestub.h
@@ -1,30 +1,31 @@
/*-------------------------------------------------------------------------
*
* rusagestub.h--
- * Stubs for getrusage(3).
+ * Stubs for getrusage(3).
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: rusagestub.h,v 1.1.1.1 1996/07/09 06:21:45 scrappy Exp $
+ * $Id: rusagestub.h,v 1.2 1997/09/07 04:46:56 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef RUSAGESTUB_H
#define RUSAGESTUB_H
-#include <sys/time.h> /* for struct timeval */
-#include <sys/times.h> /* for struct tms */
-#include <limits.h> /* for CLK_TCK */
+#include <sys/time.h> /* for struct timeval */
+#include <sys/times.h> /* for struct tms */
+#include <limits.h> /* for CLK_TCK */
-#define RUSAGE_SELF 0
-#define RUSAGE_CHILDREN -1
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN -1
-struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
+struct rusage
+{
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
};
-extern int getrusage(int who, struct rusage *rusage);
+extern int getrusage(int who, struct rusage * rusage);
-#endif /* RUSAGESTUB_H */
+#endif /* RUSAGESTUB_H */
diff --git a/src/backend/port/strerror.c b/src/backend/port/strerror.c
index 7ec842e366e..5bcd3cb4527 100644
--- a/src/backend/port/strerror.c
+++ b/src/backend/port/strerror.c
@@ -7,24 +7,23 @@
* modified for ANSI by D'Arcy J.M. Cain
*/
-#include <string.h>
-#include <stdio.h>
-#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
-extern const char * const sys_errlist[];
-extern int sys_nerr;
+extern const char *const sys_errlist[];
+extern int sys_nerr;
-const char *
+const char *
strerror(int errnum)
{
- static char buf[24];
+ static char buf[24];
- if (errnum < 0 || errnum > sys_nerr)
- {
- sprintf(buf, "unknown error %d", errnum);
- return(buf);
- }
+ if (errnum < 0 || errnum > sys_nerr)
+ {
+ sprintf(buf, "unknown error %d", errnum);
+ return (buf);
+ }
- return(sys_errlist[errnum]);
+ return (sys_errlist[errnum]);
}
-
diff --git a/src/backend/port/sunos4/float.h b/src/backend/port/sunos4/float.h
index eb9ec5c2a2e..e81d29557fe 100644
--- a/src/backend/port/sunos4/float.h
+++ b/src/backend/port/sunos4/float.h
@@ -1,30 +1,30 @@
/*-------------------------------------------------------------------------
*
* float.h--
- * definitions for ANSI floating point
+ * definitions for ANSI floating point
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: float.h,v 1.1 1997/07/28 00:08:35 momjian Exp $
+ * $Id: float.h,v 1.2 1997/09/07 04:46:58 momjian Exp $
*
* NOTES
- * These come straight out of ANSI X3.159-1989 (p.18) and
- * would be unnecessary if SunOS 4 were ANSI-compliant.
+ * These come straight out of ANSI X3.159-1989 (p.18) and
+ * would be unnecessary if SunOS 4 were ANSI-compliant.
*
- * This is only a partial listing because I'm lazy to type
- * the whole thing in.
+ * This is only a partial listing because I'm lazy to type
+ * the whole thing in.
*
*-------------------------------------------------------------------------
*/
#ifndef FLOAT_H
#define FLOAT_H
-#define FLT_DIG 6
-#define FLT_MIN ((float) 1.17549435e-38)
-#define FLT_MAX ((float) 3.40282347e+38)
-#define DBL_DIG 15
-#define DBL_MIN 2.2250738585072014e-308
-#define DBL_MAX 1.7976931348623157e+308
+#define FLT_DIG 6
+#define FLT_MIN ((float) 1.17549435e-38)
+#define FLT_MAX ((float) 3.40282347e+38)
+#define DBL_DIG 15
+#define DBL_MIN 2.2250738585072014e-308
+#define DBL_MAX 1.7976931348623157e+308
-#endif /* FLOAT_H */
+#endif /* FLOAT_H */
diff --git a/src/backend/port/sunos4/port-protos.h b/src/backend/port/sunos4/port-protos.h
index ce1de05aa02..33ec1e40e93 100644
--- a/src/backend/port/sunos4/port-protos.h
+++ b/src/backend/port/sunos4/port-protos.h
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for SunOS 4
+ * port-specific prototypes for SunOS 4
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.1 1997/07/28 00:08:39 momjian Exp $
+ * $Id: port-protos.h,v 1.2 1997/09/07 04:47:00 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -14,21 +14,21 @@
#define PORT_PROTOS_H
#include <dlfcn.h>
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
/*
* Dynamic Loader on SunOS 4.
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
*/
-#define pg_dlopen(f) dlopen(f, 1)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlopen(f) dlopen(f, 1)
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/sunos4/strtol.c b/src/backend/port/sunos4/strtol.c
index 5850848e66a..c788d94bd50 100644
--- a/src/backend/port/sunos4/strtol.c
+++ b/src/backend/port/sunos4/strtol.c
@@ -6,22 +6,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)
@@ -32,8 +32,9 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strtol.c 5.4 (Berkeley) 2/23/91";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)strtol.c 5.4 (Berkeley) 2/23/91";
+
+#endif /* LIBC_SCCS and not lint */
#include <limits.h>
#include <ctype.h>
@@ -50,31 +51,37 @@ static char sccsid[] = "@(#)strtol.c 5.4 (Berkeley) 2/23/91";
*/
long
strtol(nptr, endptr, base)
- const char *nptr;
- char **endptr;
- register int base;
+const char *nptr;
+char **endptr;
+register int base;
{
register const char *s = nptr;
register unsigned long acc;
- register int c;
+ register int c;
register unsigned long cutoff;
- register int neg = 0, any, cutlim;
+ register int neg = 0,
+ any,
+ cutlim;
/*
- * Skip white space and pick up leading +/- sign if any.
- * If base is 0, allow 0x for hex and 0 for octal, else
- * assume decimal; if base is already 16, allow 0x.
+ * Skip white space and pick up leading +/- sign if any. If base is 0,
+ * allow 0x for hex and 0 for octal, else assume decimal; if base is
+ * already 16, allow 0x.
*/
- do {
+ do
+ {
c = *s++;
} while (isspace(c));
- if (c == '-') {
+ if (c == '-')
+ {
neg = 1;
c = *s++;
- } else if (c == '+')
+ }
+ else if (c == '+')
c = *s++;
if ((base == 0 || base == 16) &&
- c == '0' && (*s == 'x' || *s == 'X')) {
+ c == '0' && (*s == 'x' || *s == 'X'))
+ {
c = s[1];
s += 2;
base = 16;
@@ -83,26 +90,26 @@ strtol(nptr, endptr, base)
base = c == '0' ? 8 : 10;
/*
- * Compute the cutoff value between legal numbers and illegal
- * numbers. That is the largest legal value, divided by the
- * base. An input number that is greater than this value, if
- * followed by a legal input character, is too big. One that
- * is equal to this value may be valid or not; the limit
- * between valid and invalid numbers is then based on the last
- * digit. For instance, if the range for longs is
- * [-2147483648..2147483647] and the input base is 10,
- * cutoff will be set to 214748364 and cutlim to either
- * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
- * a value > 214748364, or equal but the next digit is > 7 (or 8),
- * the number is too big, and we will return a range error.
+ * Compute the cutoff value between legal numbers and illegal numbers.
+ * That is the largest legal value, divided by the base. An input
+ * number that is greater than this value, if followed by a legal
+ * input character, is too big. One that is equal to this value may
+ * be valid or not; the limit between valid and invalid numbers is
+ * then based on the last digit. For instance, if the range for longs
+ * is [-2147483648..2147483647] and the input base is 10, cutoff will
+ * be set to 214748364 and cutlim to either 7 (neg==0) or 8 (neg==1),
+ * meaning that if we have accumulated a value > 214748364, or equal
+ * but the next digit is > 7 (or 8), the number is too big, and we
+ * will return a range error.
*
* Set any if any `digits' consumed; make it negative to indicate
* overflow.
*/
- cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
- cutlim = cutoff % (unsigned long)base;
- cutoff /= (unsigned long)base;
- for (acc = 0, any = 0;; c = *s++) {
+ cutoff = neg ? -(unsigned long) LONG_MIN : LONG_MAX;
+ cutlim = cutoff % (unsigned long) base;
+ cutoff /= (unsigned long) base;
+ for (acc = 0, any = 0;; c = *s++)
+ {
if (isdigit(c))
c -= '0';
else if (isalpha(c))
@@ -113,18 +120,21 @@ strtol(nptr, endptr, base)
break;
if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
any = -1;
- else {
+ else
+ {
any = 1;
acc *= base;
acc += c;
}
}
- if (any < 0) {
+ if (any < 0)
+ {
acc = neg ? LONG_MIN : LONG_MAX;
errno = ERANGE;
- } else if (neg)
+ }
+ else if (neg)
acc = -acc;
if (endptr != 0)
- *endptr = any ? s - 1 : (char *)nptr;
+ *endptr = any ? s - 1 : (char *) nptr;
return (acc);
}
diff --git a/src/backend/port/svr4/port-protos.h b/src/backend/port/svr4/port-protos.h
index 4b992570acd..1baff088769 100644
--- a/src/backend/port/svr4/port-protos.h
+++ b/src/backend/port/svr4/port-protos.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for Intel x86/Intel SVR4
+ * port-specific prototypes for Intel x86/Intel SVR4
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -14,25 +14,25 @@
#define PORT_PROTOS_H
#include <dlfcn.h>
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
/*
* Dynamic Loader on Intel x86/Intel SVR4.
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
*/
#define pg_dlopen(f) dlopen(f,RTLD_LAZY)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
/* port.c */
-extern long random(void);
-extern void srandom(int seed);
+extern long random(void);
+extern void srandom(int seed);
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/svr4/port.c b/src/backend/port/svr4/port.c
index 137cebbcbe3..0b38e2c4acd 100644
--- a/src/backend/port/svr4/port.c
+++ b/src/backend/port/svr4/port.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * Intel x86/Intel SVR4-specific routines
+ * Intel x86/Intel SVR4-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/port/svr4/port.c,v 1.2 1995/03/17 06:40:19 andrew Exp
+ * /usr/local/devel/pglite/cvs/src/backend/port/svr4/port.c,v 1.2 1995/03/17 06:40:19 andrew Exp
*
*-------------------------------------------------------------------------
*/
-#include <math.h> /* for pow() prototype */
+#include <math.h> /* for pow() prototype */
#include <errno.h>
#include "rusagestub.h"
@@ -19,50 +19,54 @@
long
random()
{
- return(lrand48());
+ return (lrand48());
}
void
srandom(int seed)
{
- srand48((long int) seed);
+ srand48((long int) seed);
}
int
-getrusage(int who, struct rusage *rusage)
+getrusage(int who, struct rusage * rusage)
{
- struct tms tms;
- register int tick_rate = CLK_TCK; /* ticks per second */
- clock_t u, s;
+ struct tms tms;
+ register int tick_rate = CLK_TCK; /* ticks per second */
+ clock_t u,
+ s;
- if (rusage == (struct rusage *) NULL) {
- errno = EFAULT;
- return(-1);
- }
- if (times(&tms) < 0) {
- /* errno set by times */
- return(-1);
- }
- switch (who) {
- case RUSAGE_SELF:
- u = tms.tms_utime;
- s = tms.tms_stime;
- break;
- case RUSAGE_CHILDREN:
- u = tms.tms_cutime;
- s = tms.tms_cstime;
- break;
- default:
- errno = EINVAL;
- return(-1);
- }
+ if (rusage == (struct rusage *) NULL)
+ {
+ errno = EFAULT;
+ return (-1);
+ }
+ if (times(&tms) < 0)
+ {
+ /* errno set by times */
+ return (-1);
+ }
+ switch (who)
+ {
+ case RUSAGE_SELF:
+ u = tms.tms_utime;
+ s = tms.tms_stime;
+ break;
+ case RUSAGE_CHILDREN:
+ u = tms.tms_cutime;
+ s = tms.tms_cstime;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
#define TICK_TO_SEC(T, RATE) ((T)/(RATE))
-#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
- rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
- rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
- rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
- rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
- return(0);
+#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
+ rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
+ rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
+ rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ return (0);
}
/*
@@ -78,15 +82,16 @@ getrusage(int who, struct rusage *rusage)
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87";
+
+#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <string.h>
/*
* This array is designed for mapping upper and lower case letter
- * together for a case independent comparison. The mappings are
+ * together for a case independent comparison. The mappings are
p * based upon ascii character sequences.
*/
static unsigned char charmap[] = {
@@ -127,17 +132,20 @@ static unsigned char charmap[] = {
int
strcasecmp(char *s1, char *s2)
{
- register unsigned char u1, u2;
+ register unsigned char u1,
+ u2;
- for (;;) {
+ for (;;)
+ {
u1 = (unsigned char) *s1++;
u2 = (unsigned char) *s2++;
- if (charmap[u1] != charmap[u2]) {
+ if (charmap[u1] != charmap[u2])
+ {
return charmap[u1] - charmap[u2];
}
- if (u1 == '\0') {
+ if (u1 == '\0')
+ {
return 0;
}
- }
+ }
}
-
diff --git a/src/backend/port/svr4/rusagestub.h b/src/backend/port/svr4/rusagestub.h
index d2393eb792d..5eda998802e 100644
--- a/src/backend/port/svr4/rusagestub.h
+++ b/src/backend/port/svr4/rusagestub.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* rusagestub.h--
- * Stubs for getrusage(3).
+ * Stubs for getrusage(3).
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -13,18 +13,19 @@
#ifndef RUSAGESTUB_H
#define RUSAGESTUB_H
-#include <sys/time.h> /* for struct timeval */
-#include <sys/times.h> /* for struct tms */
-#include <limits.h> /* for CLK_TCK */
+#include <sys/time.h> /* for struct timeval */
+#include <sys/times.h> /* for struct tms */
+#include <limits.h> /* for CLK_TCK */
-#define RUSAGE_SELF 0
-#define RUSAGE_CHILDREN -1
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN -1
-struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
+struct rusage
+{
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
};
-extern int getrusage(int who, struct rusage *rusage);
+extern int getrusage(int who, struct rusage * rusage);
-#endif /* RUSAGESTUB_H */
+#endif /* RUSAGESTUB_H */
diff --git a/src/backend/port/ultrix4/dl.h b/src/backend/port/ultrix4/dl.h
index 7855db38f30..56eab754bf4 100644
--- a/src/backend/port/ultrix4/dl.h
+++ b/src/backend/port/ultrix4/dl.h
@@ -1,40 +1,40 @@
/*-------------------------------------------------------------------------
*
* dl.h--
- *
+ *
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: dl.h,v 1.3 1996/11/26 03:18:46 bryanh Exp $
+ * $Id: dl.h,v 1.4 1997/09/07 04:47:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * Ultrix 4.x Dynamic Loader Library Version 1.0
+ * Ultrix 4.x Dynamic Loader Library Version 1.0
*
- * dl.h--
- * header file for the Dynamic Loader Library
+ * dl.h--
+ * header file for the Dynamic Loader Library
*
*
- * Copyright (c) 1993 Andrew K. Yu, University of California at Berkeley
- * All rights reserved.
+ * Copyright (c) 1993 Andrew K. Yu, University of California at Berkeley
+ * All rights reserved.
*
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for educational, research, and non-profit purposes and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation. Permission
- * to incorporate this software into commercial products can be obtained
- * from the author. The University of California and the author make
- * no representations about the suitability of this software for any
- * purpose. It is provided "as is" without express or implied warranty.
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for educational, research, and non-profit purposes and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation. Permission
+ * to incorporate this software into commercial products can be obtained
+ * from the author. The University of California and the author make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
*
*/
#ifndef _DL_HEADER_
#define _DL_HEADER_
-#include <stdio.h> /* needed to declare FILE for ldfcn.h */
+#include <stdio.h> /* needed to declare FILE for ldfcn.h */
#include <filehdr.h>
#include <syms.h>
#include <ldfcn.h>
@@ -42,77 +42,82 @@
#include <scnhdr.h>
-typedef long CoreAddr;
+typedef long CoreAddr;
-typedef struct ScnInfo {
- CoreAddr addr; /* starting address of the section */
- SCNHDR hdr; /* section header */
- RELOC *relocEntries; /* relocation entries */
-} ScnInfo;
+typedef struct ScnInfo
+{
+ CoreAddr addr; /* starting address of the section */
+ SCNHDR hdr; /* section header */
+ RELOC *relocEntries; /* relocation entries */
+} ScnInfo;
-typedef enum {
- DL_NEEDRELOC, /* still need relocation */
- DL_RELOCATED, /* no relocation necessary */
- DL_INPROG /* relocation in progress */
-} dlRStatus;
+typedef enum
+{
+ DL_NEEDRELOC, /* still need relocation */
+ DL_RELOCATED, /* no relocation necessary */
+ DL_INPROG /* relocation in progress */
+} dlRStatus;
-typedef struct JmpTbl {
- char *block; /* the jump table memory block */
- struct JmpTbl *next; /* next block */
-} JmpTbl;
+typedef struct JmpTbl
+{
+ char *block; /* the jump table memory block */
+ struct JmpTbl *next; /* next block */
+} JmpTbl;
-typedef struct dlFile {
- char *filename; /* file name of the object file */
+typedef struct dlFile
+{
+ char *filename; /* file name of the object file */
- int textSize; /* used by mprotect */
- CoreAddr textAddress; /* start addr of text section */
- long textVaddr; /* vaddr of text section in obj file */
- CoreAddr rdataAddress; /* start addr of rdata section */
- long rdataVaddr; /* vaddr of text section in obj file */
- CoreAddr dataAddress; /* start addr of data section */
- long dataVaddr; /* vaddr of text section in obj file */
- CoreAddr bssAddress; /* start addr of bss section */
- long bssVaddr; /* vaddr of text section in obj file */
+ int textSize; /* used by mprotect */
+ CoreAddr textAddress;/* start addr of text section */
+ long textVaddr; /* vaddr of text section in obj file */
+ CoreAddr rdataAddress; /* start addr of rdata section */
+ long rdataVaddr; /* vaddr of text section in obj file */
+ CoreAddr dataAddress;/* start addr of data section */
+ long dataVaddr; /* vaddr of text section in obj file */
+ CoreAddr bssAddress; /* start addr of bss section */
+ long bssVaddr; /* vaddr of text section in obj file */
- int nsect; /* number of sections */
- ScnInfo *sect; /* details of each section (array) */
+ int nsect; /* number of sections */
+ ScnInfo *sect; /* details of each section (array) */
- int issExtMax; /* size of string space */
- char *extss; /* extern sym string space (in core) */
- int iextMax; /* maximum number of Symbols */
- pEXTR extsyms; /* extern syms */
+ int issExtMax; /* size of string space */
+ char *extss; /* extern sym string space (in core) */
+ int iextMax; /* maximum number of Symbols */
+ pEXTR extsyms; /* extern syms */
- dlRStatus relocStatus; /* what relocation needed? */
- int needReloc;
+ dlRStatus relocStatus;/* what relocation needed? */
+ int needReloc;
- JmpTbl *jmptable; /* the jump table for R_JMPADDR */
+ JmpTbl *jmptable; /* the jump table for R_JMPADDR */
- struct dlFile *next; /* next member of the archive */
-} dlFile;
+ struct dlFile *next; /* next member of the archive */
+} dlFile;
-typedef struct dlSymbol {
- char *name; /* name of the symbol */
- long addr; /* address of the symbol */
- dlFile *objFile; /* from which file */
-} dlSymbol;
+typedef struct dlSymbol
+{
+ char *name; /* name of the symbol */
+ long addr; /* address of the symbol */
+ dlFile *objFile; /* from which file */
+} dlSymbol;
/*
* prototypes for the dl* interface
*/
-extern void *dl_open(/* char *filename, int mode */);
-extern void *dl_sym(/* void *handle, char *name */);
-extern void dl_close(/* void *handle */);
-extern char *dl_error(/* void */);
+extern void *dl_open( /* char *filename, int mode */ );
+extern void *dl_sym( /* void *handle, char *name */ );
+extern void dl_close( /* void *handle */ );
+extern char *dl_error( /* void */ );
-#define DL_LAZY 0 /* lazy resolution */
-#define DL_NOW 1 /* immediate resolution */
+#define DL_LAZY 0 /* lazy resolution */
+#define DL_NOW 1 /* immediate resolution */
/*
* Miscellaneous utility routines:
*/
-extern char **dl_undefinedSymbols(/* int *count */);
-extern void dl_printAllSymbols(/* void *handle */);
-extern void dl_setLibraries(/* char *libs */);
+extern char **dl_undefinedSymbols( /* int *count */ );
+extern void dl_printAllSymbols( /* void *handle */ );
+extern void dl_setLibraries( /* char *libs */ );
-#endif /* _DL_HEADER_ */
+#endif /* _DL_HEADER_ */
diff --git a/src/backend/port/ultrix4/dynloader.c b/src/backend/port/ultrix4/dynloader.c
index 1acc54260a1..d896eebf901 100644
--- a/src/backend/port/ultrix4/dynloader.c
+++ b/src/backend/port/ultrix4/dynloader.c
@@ -1,15 +1,15 @@
/*-------------------------------------------------------------------------
*
* dynloader.c--
- * This dynamic loader uses Andrew Yu's libdl-1.0 package for Ultrix 4.x.
- * (Note that pg_dlsym and pg_dlclose are actually macros defined in
- * "port-protos.h".)
- *
+ * This dynamic loader uses Andrew Yu's libdl-1.0 package for Ultrix 4.x.
+ * (Note that pg_dlsym and pg_dlclose are actually macros defined in
+ * "port-protos.h".)
+ *
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/ultrix4/Attic/dynloader.c,v 1.3 1996/11/26 03:18:50 bryanh Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/ultrix4/Attic/dynloader.c,v 1.4 1997/09/07 04:47:21 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,49 +22,54 @@
#include "port-protos.h"
#include "utils/elog.h"
-extern char pg_pathname[];
+extern char pg_pathname[];
-void *
+void *
pg_dlopen(char *filename)
{
- static int dl_initialized= 0;
- void *handle;
+ static int dl_initialized = 0;
+ void *handle;
- /*
- * initializes the dynamic loader with the executable's pathname.
- * (only needs to do this the first time pg_dlopen is called.)
- */
- if (!dl_initialized) {
- if (!dl_init(pg_pathname)) {
- return NULL;
- }
/*
- * if there are undefined symbols, we want dl to search from the
- * following libraries also.
+ * initializes the dynamic loader with the executable's pathname.
+ * (only needs to do this the first time pg_dlopen is called.)
*/
- dl_setLibraries("/usr/lib/libm_G0.a:/usr/lib/libc_G0.a");
- dl_initialized= 1;
- }
+ if (!dl_initialized)
+ {
+ if (!dl_init(pg_pathname))
+ {
+ return NULL;
+ }
- /*
- * open the file. We do the symbol resolution right away so that we
- * will know if there are undefined symbols. (This is in fact the
- * same semantics as "ld -A". ie. you cannot have undefined symbols.
- */
- if ((handle=dl_open(filename, DL_NOW))==NULL) {
- int count;
- char **list= dl_undefinedSymbols(&count);
+ /*
+ * if there are undefined symbols, we want dl to search from the
+ * following libraries also.
+ */
+ dl_setLibraries("/usr/lib/libm_G0.a:/usr/lib/libc_G0.a");
+ dl_initialized = 1;
+ }
- /* list the undefined symbols, if any */
- if(count) {
- elog(NOTICE, "dl: Undefined:");
- while(*list) {
- elog(NOTICE, " %s", *list);
- list++;
- }
+ /*
+ * open the file. We do the symbol resolution right away so that we
+ * will know if there are undefined symbols. (This is in fact the same
+ * semantics as "ld -A". ie. you cannot have undefined symbols.
+ */
+ if ((handle = dl_open(filename, DL_NOW)) == NULL)
+ {
+ int count;
+ char **list = dl_undefinedSymbols(&count);
+
+ /* list the undefined symbols, if any */
+ if (count)
+ {
+ elog(NOTICE, "dl: Undefined:");
+ while (*list)
+ {
+ elog(NOTICE, " %s", *list);
+ list++;
+ }
+ }
}
- }
- return (void *)handle;
+ return (void *) handle;
}
-
diff --git a/src/backend/port/ultrix4/port-protos.h b/src/backend/port/ultrix4/port-protos.h
index 4d4346f16b5..25f49db393d 100644
--- a/src/backend/port/ultrix4/port-protos.h
+++ b/src/backend/port/ultrix4/port-protos.h
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * prototypes for Ultrix-specific routines
+ * prototypes for Ultrix-specific routines
*
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: port-protos.h,v 1.5 1997/02/13 09:53:57 scrappy Exp $
+ * $Id: port-protos.h,v 1.6 1997/09/07 04:47:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,8 +17,8 @@
* Externals in libc that need prototypes (or at least declarations)
*/
-extern char *ecvt(double, int, int*, int*);
-extern char *fcvt(double, int, int*, int*);
+extern char *ecvt(double, int, int *, int *);
+extern char *fcvt(double, int, int *, int *);
/* dynloader.c */
/*
@@ -27,21 +27,21 @@ extern char *fcvt(double, int, int*, int*);
* This dynamic loader uses Andrew Yu's libdl-1.0 package for Ultrix 4.x.
* (Note that pg_dlsym and pg_dlclose are actually macros defined in
* "port-protos.h".)
- */
+ */
#define pg_dlsym(h, f) ((func_ptr)dl_sym(h, f))
#define pg_dlclose(h) dl_close(h)
-#define pg_dlerror() dl_error()
-extern int dl_init(char *);
+#define pg_dlerror() dl_error()
+extern int dl_init(char *);
/* port.c */
-extern int syscall();
+extern int syscall();
-extern void init_address_fixup(void);
+extern void init_address_fixup(void);
/* strdup.c: strdup() is not part of libc on Ultrix */
-extern char* strdup(char const*);
+extern char *strdup(char const *);
/* inet_aton() is not part of libc on Ultrix. The following is from
backend/port/inet_aton.h
@@ -49,6 +49,6 @@ extern char* strdup(char const*);
struct in_addr;
int
-inet_aton(const char *cp, struct in_addr *addr);
+ inet_aton(const char *cp, struct in_addr * addr);
-#endif /* PORT_PORTOS_H */
+#endif /* PORT_PORTOS_H */
diff --git a/src/backend/port/ultrix4/port.c b/src/backend/port/ultrix4/port.c
index 4e6e19bdd0d..b009073f788 100644
--- a/src/backend/port/ultrix4/port.c
+++ b/src/backend/port/ultrix4/port.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * Ultrix-specific routines
+ * Ultrix-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/ultrix4/Attic/port.c,v 1.2 1997/02/13 09:53:59 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/ultrix4/Attic/port.c,v 1.3 1997/09/07 04:47:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,6 @@ void
init_address_fixup()
{
#ifdef NOFIXADE
- syscall(SYS_sysmips, MIPS_FIXADE, 0, NULL, NULL, NULL);
-#endif /* NOFIXADE */
+ syscall(SYS_sysmips, MIPS_FIXADE, 0, NULL, NULL, NULL);
+#endif /* NOFIXADE */
}
diff --git a/src/backend/port/ultrix4/strdup.c b/src/backend/port/ultrix4/strdup.c
index 882f0047e63..a738e1611ef 100644
--- a/src/backend/port/ultrix4/strdup.c
+++ b/src/backend/port/ultrix4/strdup.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* strdup.c--
- * copies a null-terminated string.
+ * copies a null-terminated string.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/port/ultrix4/Attic/strdup.c,v 1.2 1996/11/26 03:19:04 bryanh Exp $
+ * $Header: /cvsroot/pgsql/src/backend/port/ultrix4/Attic/strdup.c,v 1.3 1997/09/07 04:47:28 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,11 +17,11 @@
#include "port-protos.h"
-char *
-strdup(char const *string)
+char *
+strdup(char const * string)
{
- char *nstr;
+ char *nstr;
- nstr = strcpy((char *)palloc(strlen(string)+1), string);
- return nstr;
+ nstr = strcpy((char *) palloc(strlen(string) + 1), string);
+ return nstr;
}
diff --git a/src/backend/port/univel/frontend-port-protos.h b/src/backend/port/univel/frontend-port-protos.h
index b76feb9d6ca..9ca0100cb90 100644
--- a/src/backend/port/univel/frontend-port-protos.h
+++ b/src/backend/port/univel/frontend-port-protos.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for Intel x86/Intel SVR4
+ * port-specific prototypes for Intel x86/Intel SVR4
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -14,9 +14,9 @@
#define FPORT_PROTOS_H
/* port.c */
-extern long random(void);
-extern void srandom(int seed);
-extern int strcasecmp(char *s1,char *s2);
-extern int gethostname(char *name,int namelen);
+extern long random(void);
+extern void srandom(int seed);
+extern int strcasecmp(char *s1, char *s2);
+extern int gethostname(char *name, int namelen);
-#endif /* FPORT_PROTOS_H */
+#endif /* FPORT_PROTOS_H */
diff --git a/src/backend/port/univel/port-protos.h b/src/backend/port/univel/port-protos.h
index 8c5cfb0f019..c181edfc9ec 100644
--- a/src/backend/port/univel/port-protos.h
+++ b/src/backend/port/univel/port-protos.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* port-protos.h--
- * port-specific prototypes for Intel x86/Intel SVR4
+ * port-specific prototypes for Intel x86/Intel SVR4
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -14,27 +14,27 @@
#define PORT_PROTOS_H
#include <dlfcn.h>
-#include "fmgr.h" /* for func_ptr */
+#include "fmgr.h" /* for func_ptr */
#include "utils/dynamic_loader.h"
/* dynloader.c */
/*
* Dynamic Loader on Intel x86/Intel SVR4.
*
- * this dynamic loader uses the system dynamic loading interface for shared
+ * this dynamic loader uses the system dynamic loading interface for shared
* libraries (ie. dlopen/dlsym/dlclose). The user must specify a shared
* library as the file to be dynamically loaded.
*
*/
#define pg_dlopen(f) dlopen(f,RTLD_LAZY)
-#define pg_dlsym dlsym
-#define pg_dlclose dlclose
-#define pg_dlerror dlerror
+#define pg_dlsym dlsym
+#define pg_dlclose dlclose
+#define pg_dlerror dlerror
/* port.c */
-extern long random(void);
-extern void srandom(int seed);
-extern int strcasecmp(char *s1,char *s2);
-extern int gethostname(char *name,int namelen);
+extern long random(void);
+extern void srandom(int seed);
+extern int strcasecmp(char *s1, char *s2);
+extern int gethostname(char *name, int namelen);
-#endif /* PORT_PROTOS_H */
+#endif /* PORT_PROTOS_H */
diff --git a/src/backend/port/univel/port.c b/src/backend/port/univel/port.c
index 07daeba62c6..d4c7658859e 100644
--- a/src/backend/port/univel/port.c
+++ b/src/backend/port/univel/port.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* port.c--
- * Intel x86/Intel SVR4-specific routines
+ * Intel x86/Intel SVR4-specific routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/port/svr4/port.c,v 1.2 1995/03/17 06:40:19 andrew Exp
+ * /usr/local/devel/pglite/cvs/src/backend/port/svr4/port.c,v 1.2 1995/03/17 06:40:19 andrew Exp
*
*-------------------------------------------------------------------------
*/
-#include <math.h> /* for pow() prototype */
+#include <math.h> /* for pow() prototype */
#include <errno.h>
#include "rusagestub.h"
@@ -20,50 +20,54 @@
long
random()
{
- return(lrand48());
+ return (lrand48());
}
void
srandom(int seed)
{
- srand48((long int) seed);
+ srand48((long int) seed);
}
int
-getrusage(int who, struct rusage *rusage)
+getrusage(int who, struct rusage * rusage)
{
- struct tms tms;
- register int tick_rate = CLK_TCK; /* ticks per second */
- clock_t u, s;
-
- if (rusage == (struct rusage *) NULL) {
- errno = EFAULT;
- return(-1);
- }
- if (times(&tms) < 0) {
- /* errno set by times */
- return(-1);
- }
- switch (who) {
- case RUSAGE_SELF:
- u = tms.tms_utime;
- s = tms.tms_stime;
- break;
- case RUSAGE_CHILDREN:
- u = tms.tms_cutime;
- s = tms.tms_cstime;
- break;
- default:
- errno = EINVAL;
- return(-1);
- }
+ struct tms tms;
+ register int tick_rate = CLK_TCK; /* ticks per second */
+ clock_t u,
+ s;
+
+ if (rusage == (struct rusage *) NULL)
+ {
+ errno = EFAULT;
+ return (-1);
+ }
+ if (times(&tms) < 0)
+ {
+ /* errno set by times */
+ return (-1);
+ }
+ switch (who)
+ {
+ case RUSAGE_SELF:
+ u = tms.tms_utime;
+ s = tms.tms_stime;
+ break;
+ case RUSAGE_CHILDREN:
+ u = tms.tms_cutime;
+ s = tms.tms_cstime;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
#define TICK_TO_SEC(T, RATE) ((T)/(RATE))
-#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
- rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
- rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
- rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
- rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
- return(0);
+#define TICK_TO_USEC(T,RATE) (((T)%(RATE)*1000000)/RATE)
+ rusage->ru_utime.tv_sec = TICK_TO_SEC(u, tick_rate);
+ rusage->ru_utime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ rusage->ru_stime.tv_sec = TICK_TO_SEC(s, tick_rate);
+ rusage->ru_stime.tv_usec = TICK_TO_USEC(u, tick_rate);
+ return (0);
}
/*
@@ -79,15 +83,16 @@ getrusage(int who, struct rusage *rusage)
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87";
+
+#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <string.h>
/*
* This array is designed for mapping upper and lower case letter
- * together for a case independent comparison. The mappings are
+ * together for a case independent comparison. The mappings are
p * based upon ascii character sequences.
*/
static unsigned char charmap[] = {
@@ -128,34 +133,38 @@ static unsigned char charmap[] = {
int
strcasecmp(char *s1, char *s2)
{
- register unsigned char u1, u2;
+ register unsigned char u1,
+ u2;
- for (;;) {
+ for (;;)
+ {
u1 = (unsigned char) *s1++;
u2 = (unsigned char) *s2++;
- if (charmap[u1] != charmap[u2]) {
+ if (charmap[u1] != charmap[u2])
+ {
return charmap[u1] - charmap[u2];
}
- if (u1 == '\0') {
+ if (u1 == '\0')
+ {
return 0;
}
- }
+ }
}
#include <sys/utsname.h>
-int gethostname(char *name, int namelen)
+int
+gethostname(char *name, int namelen)
{
static struct utsname mname;
- static int called=0;
+ static int called = 0;
- if(!called)
+ if (!called)
{
called++;
uname(&mname);
}
- strncpy(name,mname.nodename,(SYS_NMLN<namelen?SYS_NMLN:namelen));
+ strncpy(name, mname.nodename, (SYS_NMLN < namelen ? SYS_NMLN : namelen));
- return(0);
+ return (0);
}
-
diff --git a/src/backend/port/univel/rusagestub.h b/src/backend/port/univel/rusagestub.h
index d2393eb792d..5eda998802e 100644
--- a/src/backend/port/univel/rusagestub.h
+++ b/src/backend/port/univel/rusagestub.h
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* rusagestub.h--
- * Stubs for getrusage(3).
+ * Stubs for getrusage(3).
*
*
* Copyright (c) 1994, Regents of the University of California
@@ -13,18 +13,19 @@
#ifndef RUSAGESTUB_H
#define RUSAGESTUB_H
-#include <sys/time.h> /* for struct timeval */
-#include <sys/times.h> /* for struct tms */
-#include <limits.h> /* for CLK_TCK */
+#include <sys/time.h> /* for struct timeval */
+#include <sys/times.h> /* for struct tms */
+#include <limits.h> /* for CLK_TCK */
-#define RUSAGE_SELF 0
-#define RUSAGE_CHILDREN -1
+#define RUSAGE_SELF 0
+#define RUSAGE_CHILDREN -1
-struct rusage {
- struct timeval ru_utime; /* user time used */
- struct timeval ru_stime; /* system time used */
+struct rusage
+{
+ struct timeval ru_utime; /* user time used */
+ struct timeval ru_stime; /* system time used */
};
-extern int getrusage(int who, struct rusage *rusage);
+extern int getrusage(int who, struct rusage * rusage);
-#endif /* RUSAGESTUB_H */
+#endif /* RUSAGESTUB_H */
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 9c13eae1957..c9979b76969 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1,45 +1,45 @@
/*-------------------------------------------------------------------------
*
* postmaster.c--
- * This program acts as a clearing house for requests to the
- * POSTGRES system. Frontend programs send a startup message
- * to the Postmaster and the postmaster uses the info in the
- * message to setup a backend process.
+ * This program acts as a clearing house for requests to the
+ * POSTGRES system. Frontend programs send a startup message
+ * to the Postmaster and the postmaster uses the info in the
+ * message to setup a backend process.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.53 1997/08/25 04:15:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.54 1997/09/07 04:47:43 momjian Exp $
*
* NOTES
*
* Initialization:
- * The Postmaster sets up a few shared memory data structures
- * for the backends. It should at the very least initialize the
- * lock manager.
+ * The Postmaster sets up a few shared memory data structures
+ * for the backends. It should at the very least initialize the
+ * lock manager.
*
* Synchronization:
- * The Postmaster shares memory with the backends and will have to lock
- * the shared memory it accesses. The Postmaster should never block
- * on messages from clients.
- *
+ * The Postmaster shares memory with the backends and will have to lock
+ * the shared memory it accesses. The Postmaster should never block
+ * on messages from clients.
+ *
* Garbage Collection:
- * The Postmaster cleans up after backends if they have an emergency
- * exit and/or core dump.
+ * The Postmaster cleans up after backends if they have an emergency
+ * exit and/or core dump.
*
* Communication:
*
*-------------------------------------------------------------------------
*/
- /* moved here to prevent double define */
-#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+ /* moved here to prevent double define */
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#ifdef HAVE_NETDB_H
-# include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
#ifndef MAXHOSTNAMELEN
-# define MAXHOSTNAMELEN 256
+#define MAXHOSTNAMELEN 256
#endif
#include "postgres.h"
@@ -49,20 +49,20 @@
#include <stdlib.h>
#if !defined(NO_UNISTD_H)
-# include <unistd.h>
-#endif /* !NO_UNISTD_H */
+#include <unistd.h>
+#endif /* !NO_UNISTD_H */
#include <ctype.h>
-#include <sys/types.h> /* for fd_set stuff */
-#include <sys/stat.h> /* for umask */
+#include <sys/types.h> /* for fd_set stuff */
+#include <sys/stat.h> /* for umask */
#include <sys/time.h>
#include <sys/socket.h>
#ifdef HAVE_LIMITS_H
-# include <limits.h>
-# define MAXINT INT_MAX
+#include <limits.h>
+#define MAXINT INT_MAX
#else
-# include <values.h>
-#endif
+#include <values.h>
+#endif
#include <sys/wait.h>
#include <errno.h>
@@ -70,8 +70,8 @@
#include <stdio.h>
#ifdef HAVE_SYS_SELECT_H
-# include <sys/select.h>
-#endif
+#include <sys/select.h>
+#endif
#include "storage/ipc.h"
#include "libpq/libpq.h"
@@ -85,137 +85,152 @@
#include "utils/mcxt.h"
#include "storage/proc.h"
#include "utils/elog.h"
-#include "port-protos.h" /* For gethostname() */
+#include "port-protos.h" /* For gethostname() */
#if defined(DBX_VERSION)
-# define FORK() (0)
+#define FORK() (0)
#else
-# ifndef HAVE_VFORK
-# define FORK() fork()
-# else
-# define FORK() vfork()
-# endif
+#ifndef HAVE_VFORK
+#define FORK() fork()
+#else
+#define FORK() vfork()
+#endif
#endif
#define LINGER_TIME 3
- /* Max time in seconds for socket to linger (close() to block) waiting
- for frontend to retrieve its message from us.
+
+ /*
+ * Max time in seconds for socket to linger (close() to block) waiting
+ * for frontend to retrieve its message from us.
*/
/*
* Info for garbage collection. Whenever a process dies, the Postmaster
- * cleans up after it. Currently, NO information is required for cleanup,
+ * cleans up after it. Currently, NO information is required for cleanup,
* but I left this structure around in case that changed.
*/
-typedef struct bkend {
- int pid; /* process id of backend */
-} Backend;
+typedef struct bkend
+{
+ int pid; /* process id of backend */
+} Backend;
/* list of active backends. For garbage collection only now. */
-static Dllist* BackendList;
+static Dllist *BackendList;
/* list of ports associated with still open, but incomplete connections */
-static Dllist* PortList;
+static Dllist *PortList;
-static short PostPortName = -1;
-static short ActiveBackends = FALSE;
-static int NextBackendId = MAXINT; /* XXX why? */
-static char *progname = (char *) NULL;
+static short PostPortName = -1;
+static short ActiveBackends = FALSE;
+static int NextBackendId = MAXINT; /* XXX why? */
+static char *progname = (char *) NULL;
/*
* Default Values
*/
-static char Execfile[MAXPATHLEN] = "";
+static char Execfile[MAXPATHLEN] = "";
-static int ServerSock = INVALID_SOCK; /* stream socket server */
+static int ServerSock = INVALID_SOCK; /* stream socket server */
/*
* Set by the -o option
*/
-static char ExtraOptions[ARGV_SIZE] = "";
+static char ExtraOptions[ARGV_SIZE] = "";
/*
* These globals control the behavior of the postmaster in case some
- * backend dumps core. Normally, it kills all peers of the dead backend
+ * backend dumps core. Normally, it kills all peers of the dead backend
* and reinitializes shared memory. By specifying -s or -n, we can have
* the postmaster stop (rather than kill) peers and not reinitialize
* shared data structures.
*/
-static int Reinit = 1;
-static int SendStop = 0;
+static int Reinit = 1;
+static int SendStop = 0;
-static int MultiplexedBackends = 0;
-static int MultiplexedBackendPort;
+static int MultiplexedBackends = 0;
+static int MultiplexedBackendPort;
-/*
+/*
* postmaster.c - function prototypes
*/
-static void pmdaemonize(void);
-static void ConnStartup(Port *port, int *status,
- char *errormsg, const int errormsg_len);
-static int ConnCreate(int serverFd, int *newFdP);
-static void reset_shared(short port);
-static void pmdie(SIGNAL_ARGS);
-static void reaper(SIGNAL_ARGS);
-static void dumpstatus(SIGNAL_ARGS);
-static void CleanupProc(int pid, int exitstatus);
-static int DoExec(StartupInfo *packet, int portFd);
-static void ExitPostmaster(int status);
-static void usage(const char *);
-static int ServerLoop(void);
-static int BackendStartup(StartupInfo *packet, Port *port, int *pidPtr);
-static void send_error_reply(Port *port, const char *errormsg);
-
-extern char *optarg;
-extern int optind, opterr;
+static void pmdaemonize(void);
+static void
+ConnStartup(Port * port, int *status,
+ char *errormsg, const int errormsg_len);
+static int ConnCreate(int serverFd, int *newFdP);
+static void reset_shared(short port);
+static void pmdie(SIGNAL_ARGS);
+static void reaper(SIGNAL_ARGS);
+static void dumpstatus(SIGNAL_ARGS);
+static void CleanupProc(int pid, int exitstatus);
+static int DoExec(StartupInfo * packet, int portFd);
+static void ExitPostmaster(int status);
+static void usage(const char *);
+static int ServerLoop(void);
+static int BackendStartup(StartupInfo * packet, Port * port, int *pidPtr);
+static void send_error_reply(Port * port, const char *errormsg);
+
+extern char *optarg;
+extern int optind,
+ opterr;
static void
-checkDataDir(const char *DataDir, bool *DataDirOK)
+checkDataDir(const char *DataDir, bool * DataDirOK)
{
- if (DataDir == NULL) {
- 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",
- progname);
- *DataDirOK = false;
- } else {
- char path[MAXPATHLEN];
- FILE *fp;
-
- sprintf(path, "%s%cbase%ctemplate1%cpg_class",
- DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR);
- fp = fopen(path, "r");
- if (fp == NULL) {
- fprintf(stderr, "%s does not find the database system. "
- "Expected to find it "
- "in the PGDATA directory \"%s\", but unable to open file "
- "with pathname \"%s\".\n\n",
- progname, DataDir, path);
- *DataDirOK = false;
- } else {
- char *reason;
- /* reason ValidatePgVersion failed. NULL if didn't */
-
- fclose(fp);
-
- ValidatePgVersion(DataDir, &reason);
- if (reason) {
- fprintf(stderr,
- "Database system in directory %s "
- "is not compatible with this version of "
- "Postgres, or we are unable to read the "
- "PG_VERSION file. "
- "Explanation from ValidatePgVersion: %s\n\n",
- DataDir, reason);
- free(reason);
- *DataDirOK = false;
- } else *DataDirOK = true;
- }
- }
+ if (DataDir == NULL)
+ {
+ 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",
+ progname);
+ *DataDirOK = false;
+ }
+ else
+ {
+ char path[MAXPATHLEN];
+ FILE *fp;
+
+ sprintf(path, "%s%cbase%ctemplate1%cpg_class",
+ DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR);
+ fp = fopen(path, "r");
+ if (fp == NULL)
+ {
+ fprintf(stderr, "%s does not find the database system. "
+ "Expected to find it "
+ "in the PGDATA directory \"%s\", but unable to open file "
+ "with pathname \"%s\".\n\n",
+ progname, DataDir, path);
+ *DataDirOK = false;
+ }
+ else
+ {
+ char *reason;
+
+ /* reason ValidatePgVersion failed. NULL if didn't */
+
+ fclose(fp);
+
+ ValidatePgVersion(DataDir, &reason);
+ if (reason)
+ {
+ fprintf(stderr,
+ "Database system in directory %s "
+ "is not compatible with this version of "
+ "Postgres, or we are unable to read the "
+ "PG_VERSION file. "
+ "Explanation from ValidatePgVersion: %s\n\n",
+ DataDir, reason);
+ free(reason);
+ *DataDirOK = false;
+ }
+ else
+ *DataDirOK = true;
+ }
+ }
}
@@ -223,533 +238,596 @@ checkDataDir(const char *DataDir, bool *DataDirOK)
int
PostmasterMain(int argc, char *argv[])
{
- extern int NBuffers; /* from buffer/bufmgr.c */
- extern bool IsPostmaster; /* from smgr/mm.c */
- int opt;
- char *hostName;
- int status;
- int silentflag = 0;
- char hostbuf[MAXHOSTNAMELEN];
- bool DataDirOK; /* We have a usable PGDATA value */
-
- progname = argv[0];
-
- IsPostmaster = true;
-
- /* for security, no dir or file created can be group or other accessible */
- umask((mode_t) 0077);
-
- if (!(hostName = getenv("PGHOST"))) {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
- DataDir = getenv("PGDATA"); /* default value */
-
- opterr = 0;
- while ((opt = getopt(argc, argv, "a:B:b:D:dm:Mno:p:Ss")) != EOF) {
- switch (opt) {
- case 'a':
- /* Set the authentication system. */
- be_setauthsvc(optarg);
- break;
- case 'B':
- /*
- * The number of buffers to create. Setting this
- * option means we have to start each backend with
- * a -B # to make sure they know how many buffers
- * were allocated.
- */
- NBuffers = atol(optarg);
- strcat(ExtraOptions, " -B ");
- strcat(ExtraOptions, optarg);
- break;
- case 'b':
- /* Set the backend executable file to use. */
- if (!ValidateBackend(optarg))
- strcpy(Execfile, optarg);
- else {
- fprintf(stderr, "%s: invalid backend \"%s\"\n",
- progname, optarg);
- exit(2);
- }
- break;
- case 'D':
- /* Set PGDATA from the command line. */
- DataDir = optarg;
- break;
- case 'd':
- /*
- * Turn on debugging for the postmaster and the backend
- * servers descended from it.
- */
- if ((optind < argc) && *argv[optind] != '-') {
- DebugLvl = atoi(argv[optind]);
- optind++;
- }
- else
- DebugLvl = 1;
- break;
- case 'm':
- MultiplexedBackends = 1;
- MultiplexedBackendPort = atoi(optarg);
- break;
- case 'M':
- /* ignore this flag. This may be passed in because the
- program was run as 'postgres -M' instead of 'postmaster' */
- break;
- case 'n':
- /* Don't reinit shared mem after abnormal exit */
- Reinit = 0;
- break;
- case 'o':
- /*
- * Other options to pass to the backend on the
- * command line -- useful only for debugging.
- */
- strcat(ExtraOptions, " ");
- strcat(ExtraOptions, optarg);
- break;
- case 'p':
- /* Set PGPORT by hand. */
- PostPortName = (short) atoi(optarg);
- break;
- case 'S':
- /*
- * Start in 'S'ilent mode (disassociate from controlling tty).
- * You may also think of this as 'S'ysV mode since it's most
- * badly needed on SysV-derived systems like SVR4 and HP-UX.
- */
- silentflag = 1;
- break;
- case 's':
- /*
- * In the event that some backend dumps core,
- * send SIGSTOP, rather than SIGUSR1, to all
- * its peers. This lets the wily post_hacker
- * collect core dumps from everyone.
- */
- SendStop = 1;
- break;
- default:
- /* usage() never returns */
- usage(progname);
- break;
- }
- }
- if (PostPortName == -1)
- PostPortName = pq_getport();
-
- checkDataDir(DataDir, &DataDirOK); /* issues error messages */
- if (!DataDirOK) {
- fprintf(stderr, "No data directory -- can't proceed.\n");
- exit(2);
- }
-
- if (!Execfile[0] && FindBackend(Execfile, argv[0]) < 0) {
- fprintf(stderr, "%s: could not find backend to execute...\n",
- argv[0]);
- exit(1);
- }
-
-
- status = StreamServerPort(hostName, PostPortName, &ServerSock);
- if (status != STATUS_OK) {
- fprintf(stderr, "%s: cannot create stream port\n",
- progname);
- exit(1);
- }
-
- /* set up shared memory and semaphores */
- EnableMemoryContext(TRUE);
- reset_shared(PostPortName);
-
- /*
- * Initialize the list of active backends. This list is only
- * used for garbage collecting the backend processes.
- */
- BackendList = DLNewList();
- PortList = DLNewList();
-
- if (silentflag)
- pmdaemonize();
-
- pqsignal(SIGINT, pmdie);
- pqsignal(SIGCHLD, reaper);
- pqsignal(SIGTTIN, SIG_IGN);
- pqsignal(SIGTTOU, SIG_IGN);
- pqsignal(SIGHUP, pmdie);
- pqsignal(SIGTERM, pmdie);
- pqsignal(SIGCONT, dumpstatus);
- pqsignal(SIGPIPE, SIG_IGN);
-
- status = ServerLoop();
-
- ExitPostmaster(status != STATUS_OK);
- return 0; /* not reached */
+ extern int NBuffers; /* from buffer/bufmgr.c */
+ extern bool IsPostmaster; /* from smgr/mm.c */
+ int opt;
+ char *hostName;
+ int status;
+ int silentflag = 0;
+ char hostbuf[MAXHOSTNAMELEN];
+ bool DataDirOK; /* We have a usable PGDATA value */
+
+ progname = argv[0];
+
+ IsPostmaster = true;
+
+ /*
+ * for security, no dir or file created can be group or other
+ * accessible
+ */
+ umask((mode_t) 0077);
+
+ if (!(hostName = getenv("PGHOST")))
+ {
+ if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
+ strcpy(hostbuf, "localhost");
+ hostName = hostbuf;
+ }
+
+ DataDir = getenv("PGDATA"); /* default value */
+
+ opterr = 0;
+ while ((opt = getopt(argc, argv, "a:B:b:D:dm:Mno:p:Ss")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'a':
+ /* Set the authentication system. */
+ be_setauthsvc(optarg);
+ break;
+ case 'B':
+
+ /*
+ * The number of buffers to create. Setting this option means
+ * we have to start each backend with a -B # to make sure they
+ * know how many buffers were allocated.
+ */
+ NBuffers = atol(optarg);
+ strcat(ExtraOptions, " -B ");
+ strcat(ExtraOptions, optarg);
+ break;
+ case 'b':
+ /* Set the backend executable file to use. */
+ if (!ValidateBackend(optarg))
+ strcpy(Execfile, optarg);
+ else
+ {
+ fprintf(stderr, "%s: invalid backend \"%s\"\n",
+ progname, optarg);
+ exit(2);
+ }
+ break;
+ case 'D':
+ /* Set PGDATA from the command line. */
+ DataDir = optarg;
+ break;
+ case 'd':
+
+ /*
+ * Turn on debugging for the postmaster and the backend
+ * servers descended from it.
+ */
+ if ((optind < argc) && *argv[optind] != '-')
+ {
+ DebugLvl = atoi(argv[optind]);
+ optind++;
+ }
+ else
+ DebugLvl = 1;
+ break;
+ case 'm':
+ MultiplexedBackends = 1;
+ MultiplexedBackendPort = atoi(optarg);
+ break;
+ case 'M':
+
+ /*
+ * ignore this flag. This may be passed in because the
+ * program was run as 'postgres -M' instead of 'postmaster'
+ */
+ break;
+ case 'n':
+ /* Don't reinit shared mem after abnormal exit */
+ Reinit = 0;
+ break;
+ case 'o':
+
+ /*
+ * Other options to pass to the backend on the command line --
+ * useful only for debugging.
+ */
+ strcat(ExtraOptions, " ");
+ strcat(ExtraOptions, optarg);
+ break;
+ case 'p':
+ /* Set PGPORT by hand. */
+ PostPortName = (short) atoi(optarg);
+ break;
+ case 'S':
+
+ /*
+ * Start in 'S'ilent mode (disassociate from controlling tty).
+ * You may also think of this as 'S'ysV mode since it's most
+ * badly needed on SysV-derived systems like SVR4 and HP-UX.
+ */
+ silentflag = 1;
+ break;
+ case 's':
+
+ /*
+ * In the event that some backend dumps core, send SIGSTOP,
+ * rather than SIGUSR1, to all its peers. This lets the wily
+ * post_hacker collect core dumps from everyone.
+ */
+ SendStop = 1;
+ break;
+ default:
+ /* usage() never returns */
+ usage(progname);
+ break;
+ }
+ }
+ if (PostPortName == -1)
+ PostPortName = pq_getport();
+
+ checkDataDir(DataDir, &DataDirOK); /* issues error messages */
+ if (!DataDirOK)
+ {
+ fprintf(stderr, "No data directory -- can't proceed.\n");
+ exit(2);
+ }
+
+ if (!Execfile[0] && FindBackend(Execfile, argv[0]) < 0)
+ {
+ fprintf(stderr, "%s: could not find backend to execute...\n",
+ argv[0]);
+ exit(1);
+ }
+
+
+ status = StreamServerPort(hostName, PostPortName, &ServerSock);
+ if (status != STATUS_OK)
+ {
+ fprintf(stderr, "%s: cannot create stream port\n",
+ progname);
+ exit(1);
+ }
+
+ /* set up shared memory and semaphores */
+ EnableMemoryContext(TRUE);
+ reset_shared(PostPortName);
+
+ /*
+ * Initialize the list of active backends. This list is only used for
+ * garbage collecting the backend processes.
+ */
+ BackendList = DLNewList();
+ PortList = DLNewList();
+
+ if (silentflag)
+ pmdaemonize();
+
+ pqsignal(SIGINT, pmdie);
+ pqsignal(SIGCHLD, reaper);
+ pqsignal(SIGTTIN, SIG_IGN);
+ pqsignal(SIGTTOU, SIG_IGN);
+ pqsignal(SIGHUP, pmdie);
+ pqsignal(SIGTERM, pmdie);
+ pqsignal(SIGCONT, dumpstatus);
+ pqsignal(SIGPIPE, SIG_IGN);
+
+ status = ServerLoop();
+
+ ExitPostmaster(status != STATUS_OK);
+ return 0; /* not reached */
}
static void
pmdaemonize(void)
{
- int i;
-
- if (fork())
- exit(0);
+ int i;
+
+ if (fork())
+ exit(0);
/* GH: If there's no setsid(), we hopefully don't need silent mode.
* Until there's a better solution.
*/
#ifdef HAVE_SETSID
- if (setsid() < 0) {
- fprintf(stderr, "%s: ", progname);
- perror("cannot disassociate from controlling TTY");
- exit(1);
- }
+ if (setsid() < 0)
+ {
+ fprintf(stderr, "%s: ", progname);
+ perror("cannot disassociate from controlling TTY");
+ exit(1);
+ }
#endif
- i = open(NULL_DEV, O_RDWR);
- dup2(i, 0);
- dup2(i, 1);
- dup2(i, 2);
- close(i);
+ i = open(NULL_DEV, O_RDWR);
+ dup2(i, 0);
+ dup2(i, 1);
+ dup2(i, 2);
+ close(i);
}
static void
usage(const char *progname)
{
- fprintf(stderr, "usage: %s [options..]\n", progname);
- fprintf(stderr, "\t-a authsys\tdo/do not permit use of an authentication system\n");
- fprintf(stderr, "\t-B nbufs\tset number of shared buffers\n");
- fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
- fprintf(stderr, "\t-d [1|2|3]\tset debugging level\n");
- fprintf(stderr, "\t-D datadir\tset data directory\n");
- fprintf(stderr, "\t-m \tstart up multiplexing backends\n");
- fprintf(stderr, "\t-n\t\tdon't reinitialize shared memory after abnormal exit\n");
- fprintf(stderr, "\t-o option\tpass 'option' to each backend servers\n");
- fprintf(stderr, "\t-p port\t\tspecify port for postmaster to listen on\n");
- fprintf(stderr, "\t-S\t\tsilent mode (disassociate from tty)\n");
- fprintf(stderr, "\t-s\t\tsend SIGSTOP to all backend servers if one dies\n");
- exit(1);
+ fprintf(stderr, "usage: %s [options..]\n", progname);
+ fprintf(stderr, "\t-a authsys\tdo/do not permit use of an authentication system\n");
+ fprintf(stderr, "\t-B nbufs\tset number of shared buffers\n");
+ fprintf(stderr, "\t-b backend\tuse a specific backend server executable\n");
+ fprintf(stderr, "\t-d [1|2|3]\tset debugging level\n");
+ fprintf(stderr, "\t-D datadir\tset data directory\n");
+ fprintf(stderr, "\t-m \tstart up multiplexing backends\n");
+ fprintf(stderr, "\t-n\t\tdon't reinitialize shared memory after abnormal exit\n");
+ fprintf(stderr, "\t-o option\tpass 'option' to each backend servers\n");
+ fprintf(stderr, "\t-p port\t\tspecify port for postmaster to listen on\n");
+ fprintf(stderr, "\t-S\t\tsilent mode (disassociate from tty)\n");
+ fprintf(stderr, "\t-s\t\tsend SIGSTOP to all backend servers if one dies\n");
+ exit(1);
}
static int
ServerLoop(void)
{
- int serverFd = ServerSock;
- fd_set rmask, basemask;
- int nSockets, nSelected, status, newFd;
- Dlelem *next, *curr;
- /* GH: For !HAVE_SIGPROCMASK (NEXTSTEP), TRH implemented
- * an alternative interface.
- */
+ int serverFd = ServerSock;
+ fd_set rmask,
+ basemask;
+ int nSockets,
+ nSelected,
+ status,
+ newFd;
+ Dlelem *next,
+ *curr;
+
+ /*
+ * GH: For !HAVE_SIGPROCMASK (NEXTSTEP), TRH implemented an
+ * alternative interface.
+ */
#ifdef HAVE_SIGPROCMASK
- sigset_t oldsigmask, newsigmask;
+ sigset_t oldsigmask,
+ newsigmask;
+
#else
- int orgsigmask = sigblock(0);
+ int orgsigmask = sigblock(0);
+
#endif
-
- nSockets = ServerSock + 1;
- FD_ZERO(&basemask);
- FD_SET(ServerSock, &basemask);
-
+
+ nSockets = ServerSock + 1;
+ FD_ZERO(&basemask);
+ FD_SET(ServerSock, &basemask);
+
#ifdef HAVE_SIGPROCMASK
- sigprocmask(0,0,&oldsigmask);
- sigemptyset(&newsigmask);
- sigaddset(&newsigmask,SIGCHLD);
+ sigprocmask(0, 0, &oldsigmask);
+ sigemptyset(&newsigmask);
+ sigaddset(&newsigmask, SIGCHLD);
#endif
- for (;;) {
+ for (;;)
+ {
#ifdef HAVE_SIGPROCMASK
- sigprocmask(SIG_SETMASK,&oldsigmask,0);
+ sigprocmask(SIG_SETMASK, &oldsigmask, 0);
#else
- sigsetmask(orgsigmask);
+ sigsetmask(orgsigmask);
#endif
- newFd = -1;
- memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
- if ((nSelected = select(nSockets, &rmask,
- (fd_set *) NULL,
- (fd_set *) NULL,
- (struct timeval *) NULL)) < 0) {
- if (errno == EINTR)
- continue;
- fprintf(stderr, "%s: ServerLoop: select failed\n",
- progname);
- return(STATUS_ERROR);
- }
- /* [TRH]
- * To avoid race conditions, block SIGCHLD signals while we are
- * handling the request. (both reaper() and ConnCreate()
- * manipulate the BackEnd list, and reaper() calls free() which is
- * usually non-reentrant.)
- */
+ newFd = -1;
+ memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
+ if ((nSelected = select(nSockets, &rmask,
+ (fd_set *) NULL,
+ (fd_set *) NULL,
+ (struct timeval *) NULL)) < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "%s: ServerLoop: select failed\n",
+ progname);
+ return (STATUS_ERROR);
+ }
+
+ /*
+ * [TRH] To avoid race conditions, block SIGCHLD signals while we
+ * are handling the request. (both reaper() and ConnCreate()
+ * manipulate the BackEnd list, and reaper() calls free() which is
+ * usually non-reentrant.)
+ */
#ifdef HAVE_SIGPROCMASK
- sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
+ sigprocmask(SIG_BLOCK, &newsigmask, &oldsigmask);
#else
- sigblock(sigmask(SIGCHLD)); /* XXX[TRH] portability */
+ sigblock(sigmask(SIGCHLD)); /* XXX[TRH] portability */
#endif
- if (DebugLvl > 1) {
- fprintf(stderr, "%s: ServerLoop: %d sockets pending\n",
- progname, nSelected);
- }
-
- /* new connection pending on our well-known port's socket */
- if (FD_ISSET(ServerSock, &rmask)) {
- /*
- * connect and make an addition to PortList. If
- * the connection dies and we notice it, just forget
- * about the whole thing.
- */
- if (ConnCreate(serverFd, &newFd) == STATUS_OK) {
- if (newFd >= nSockets)
- nSockets = newFd + 1;
- FD_SET(newFd, &rmask);
- FD_SET(newFd, &basemask);
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop: connect on %d\n",
- progname, newFd);
- }
- --nSelected;
- FD_CLR(ServerSock, &rmask);
- }
-
- if (DebugLvl > 1) {
- fprintf(stderr, "%s: ServerLoop:\tnSelected=%d\n",
- progname, nSelected);
- curr = DLGetHead(PortList);
- while (curr) {
- Port *port = DLE_VAL(curr);
-
- fprintf(stderr, "%s: ServerLoop:\t\tport %d%s pending\n",
- progname, port->sock,
- FD_ISSET(port->sock, &rmask)
- ? "" :
- " not");
- curr = DLGetSucc(curr);
- }
- }
-
- curr = DLGetHead(PortList);
-
- while (curr) {
- Port *port = (Port*)DLE_VAL(curr);
- int lastbytes = port->nBytes;
-
- if (FD_ISSET(port->sock, &rmask) && port->sock != newFd) {
- if (DebugLvl > 1)
- fprintf(stderr, "%s: ServerLoop:\t\thandling %d\n",
- progname, port->sock);
- --nSelected;
-
- /*
- * Read the incoming packet into its packet buffer.
- * Read the connection id out of the packet so we
- * know who the packet is from.
- */
- status = PacketReceive(port, &port->buf, NON_BLOCKING);
- switch (status) {
- case STATUS_OK: {
- int CSstatus; /* Completion status of ConnStartup */
- char errormsg[200]; /* error msg from ConnStartup */
-
- ConnStartup(port, &CSstatus, errormsg, sizeof(errormsg));
-
- if (CSstatus == STATUS_ERROR)
- send_error_reply(port, errormsg);
- ActiveBackends = TRUE;
- }
- /*FALLTHROUGH*/
- case STATUS_INVALID:
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop:\t\tdone with %d\n",
- progname, port->sock);
- break;
- case STATUS_BAD_PACKET:
- /*
- * This is a bogus client, kill the connection
- * and forget the whole thing.
- */
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop:\t\tbad packet format (reported packet size of %d read on port %d\n", progname, port->nBytes, port->sock);
- break;
- case STATUS_NOT_DONE:
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop:\t\tpartial packet (%d bytes actually read) on %d\n",
- progname, port->nBytes, port->sock);
- /*
- * If we've received at least a PacketHdr's worth of data
- * and we're still receiving data each time we read, we're
- * ok. If the client gives us less than a PacketHdr at
- * the beginning, just kill the connection and forget
- * about the whole thing.
- */
- if (lastbytes < port->nBytes) {
- if (DebugLvl)
- fprintf(stderr, "%s: ServerLoop:\t\tpartial packet on %d ok\n",
- progname, port->sock);
- curr = DLGetSucc(curr);
- continue;
- }
- break;
- case STATUS_ERROR: /* system call error - die */
- fprintf(stderr, "%s: ServerLoop:\t\terror receiving packet\n",
- progname);
- return(STATUS_ERROR);
- }
- FD_CLR(port->sock, &basemask);
- StreamClose(port->sock);
- next = DLGetSucc(curr);
- DLRemove(curr);
- free(port);
- DLFreeElem(curr);
- curr = next;
- continue;
- }
- curr = DLGetSucc(curr);
- }
- Assert(nSelected == 0);
- }
+ if (DebugLvl > 1)
+ {
+ fprintf(stderr, "%s: ServerLoop: %d sockets pending\n",
+ progname, nSelected);
+ }
+
+ /* new connection pending on our well-known port's socket */
+ if (FD_ISSET(ServerSock, &rmask))
+ {
+
+ /*
+ * connect and make an addition to PortList. If the
+ * connection dies and we notice it, just forget about the
+ * whole thing.
+ */
+ if (ConnCreate(serverFd, &newFd) == STATUS_OK)
+ {
+ if (newFd >= nSockets)
+ nSockets = newFd + 1;
+ FD_SET(newFd, &rmask);
+ FD_SET(newFd, &basemask);
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop: connect on %d\n",
+ progname, newFd);
+ }
+ --nSelected;
+ FD_CLR(ServerSock, &rmask);
+ }
+
+ if (DebugLvl > 1)
+ {
+ fprintf(stderr, "%s: ServerLoop:\tnSelected=%d\n",
+ progname, nSelected);
+ curr = DLGetHead(PortList);
+ while (curr)
+ {
+ Port *port = DLE_VAL(curr);
+
+ fprintf(stderr, "%s: ServerLoop:\t\tport %d%s pending\n",
+ progname, port->sock,
+ FD_ISSET(port->sock, &rmask)
+ ? "" :
+ " not");
+ curr = DLGetSucc(curr);
+ }
+ }
+
+ curr = DLGetHead(PortList);
+
+ while (curr)
+ {
+ Port *port = (Port *) DLE_VAL(curr);
+ int lastbytes = port->nBytes;
+
+ if (FD_ISSET(port->sock, &rmask) && port->sock != newFd)
+ {
+ if (DebugLvl > 1)
+ fprintf(stderr, "%s: ServerLoop:\t\thandling %d\n",
+ progname, port->sock);
+ --nSelected;
+
+ /*
+ * Read the incoming packet into its packet buffer. Read
+ * the connection id out of the packet so we know who the
+ * packet is from.
+ */
+ status = PacketReceive(port, &port->buf, NON_BLOCKING);
+ switch (status)
+ {
+ case STATUS_OK:
+ {
+ int CSstatus; /* Completion status of
+ * ConnStartup */
+ char errormsg[200]; /* error msg from
+ * ConnStartup */
+
+ ConnStartup(port, &CSstatus, errormsg, sizeof(errormsg));
+
+ if (CSstatus == STATUS_ERROR)
+ send_error_reply(port, errormsg);
+ ActiveBackends = TRUE;
+ }
+ /* FALLTHROUGH */
+ case STATUS_INVALID:
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop:\t\tdone with %d\n",
+ progname, port->sock);
+ break;
+ case STATUS_BAD_PACKET:
+
+ /*
+ * This is a bogus client, kill the connection and
+ * forget the whole thing.
+ */
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop:\t\tbad packet format (reported packet size of %d read on port %d\n", progname, port->nBytes, port->sock);
+ break;
+ case STATUS_NOT_DONE:
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop:\t\tpartial packet (%d bytes actually read) on %d\n",
+ progname, port->nBytes, port->sock);
+
+ /*
+ * If we've received at least a PacketHdr's worth of
+ * data and we're still receiving data each time we
+ * read, we're ok. If the client gives us less than a
+ * PacketHdr at the beginning, just kill the
+ * connection and forget about the whole thing.
+ */
+ if (lastbytes < port->nBytes)
+ {
+ if (DebugLvl)
+ fprintf(stderr, "%s: ServerLoop:\t\tpartial packet on %d ok\n",
+ progname, port->sock);
+ curr = DLGetSucc(curr);
+ continue;
+ }
+ break;
+ case STATUS_ERROR: /* system call error - die */
+ fprintf(stderr, "%s: ServerLoop:\t\terror receiving packet\n",
+ progname);
+ return (STATUS_ERROR);
+ }
+ FD_CLR(port->sock, &basemask);
+ StreamClose(port->sock);
+ next = DLGetSucc(curr);
+ DLRemove(curr);
+ free(port);
+ DLFreeElem(curr);
+ curr = next;
+ continue;
+ }
+ curr = DLGetSucc(curr);
+ }
+ Assert(nSelected == 0);
+ }
}
/*
- ConnStartup: get the startup packet from the front end (client),
- authenticate the user, and start up a backend.
+ ConnStartup: get the startup packet from the front end (client),
+ authenticate the user, and start up a backend.
- If all goes well, return *status == STATUS_OK.
- Otherwise, return *status == STATUS_ERROR and return a text string
- explaining why in the "errormsg_len" bytes at "errormsg",
+ If all goes well, return *status == STATUS_OK.
+ Otherwise, return *status == STATUS_ERROR and return a text string
+ explaining why in the "errormsg_len" bytes at "errormsg",
*/
static void
-ConnStartup(Port *port, int *status,
- char *errormsg, const int errormsg_len)
+ConnStartup(Port * port, int *status,
+ char *errormsg, const int errormsg_len)
{
- MsgType msgType;
- char namebuf[NAMEDATALEN];
- int pid;
- PacketBuf *p;
- StartupInfo sp;
- char *tmp;
-
- p = &port->buf;
-
- sp.database[0]='\0';
- sp.user[0]='\0';
- sp.options[0]='\0';
- sp.execFile[0]='\0';
- sp.tty[0]='\0';
-
- tmp= p->data;
- strncpy(sp.database,tmp,sizeof(sp.database));
- tmp += sizeof(sp.database);
- strncpy(sp.user,tmp, sizeof(sp.user));
- tmp += sizeof(sp.user);
- strncpy(sp.options,tmp, sizeof(sp.options));
- tmp += sizeof(sp.options);
- strncpy(sp.execFile,tmp, sizeof(sp.execFile));
- tmp += sizeof(sp.execFile);
- strncpy(sp.tty,tmp, sizeof(sp.tty));
-
- msgType = (MsgType) ntohl(port->buf.msgtype);
-
- strNcpy(namebuf, sp.user, NAMEDATALEN-1);
- if (!namebuf[0]) {
- strncpy(errormsg,
- "No Postgres username specified in startup packet.",
- errormsg_len);
- *status = STATUS_ERROR;
- } else {
- if (be_recvauth(msgType, port, namebuf, &sp) != STATUS_OK) {
- char buffer[200 + sizeof(namebuf)];
- sprintf(buffer,
- "Failed to authenticate client as Postgres user '%s' "
- "using %s: %s",
- namebuf, name_of_authentication_type(msgType), PQerrormsg);
- strncpy(errormsg, buffer, errormsg_len);
- *status = STATUS_ERROR;
- } else {
- if (BackendStartup(&sp, port, &pid) != STATUS_OK) {
- strncpy(errormsg, "Startup (fork) of backend failed.",
- errormsg_len);
- *status = STATUS_ERROR;
- } else {
- errormsg[0] = '\0'; /* just for robustness */
- *status = STATUS_OK;
- }
- }
- }
- if (*status == STATUS_ERROR)
- fprintf(stderr, "%s: ConnStartup: %s\n", progname, errormsg);
+ MsgType msgType;
+ char namebuf[NAMEDATALEN];
+ int pid;
+ PacketBuf *p;
+ StartupInfo sp;
+ char *tmp;
+
+ p = &port->buf;
+
+ sp.database[0] = '\0';
+ sp.user[0] = '\0';
+ sp.options[0] = '\0';
+ sp.execFile[0] = '\0';
+ sp.tty[0] = '\0';
+
+ tmp = p->data;
+ strncpy(sp.database, tmp, sizeof(sp.database));
+ tmp += sizeof(sp.database);
+ strncpy(sp.user, tmp, sizeof(sp.user));
+ tmp += sizeof(sp.user);
+ strncpy(sp.options, tmp, sizeof(sp.options));
+ tmp += sizeof(sp.options);
+ strncpy(sp.execFile, tmp, sizeof(sp.execFile));
+ tmp += sizeof(sp.execFile);
+ strncpy(sp.tty, tmp, sizeof(sp.tty));
+
+ msgType = (MsgType) ntohl(port->buf.msgtype);
+
+ strNcpy(namebuf, sp.user, NAMEDATALEN - 1);
+ if (!namebuf[0])
+ {
+ strncpy(errormsg,
+ "No Postgres username specified in startup packet.",
+ errormsg_len);
+ *status = STATUS_ERROR;
+ }
+ else
+ {
+ if (be_recvauth(msgType, port, namebuf, &sp) != STATUS_OK)
+ {
+ char buffer[200 + sizeof(namebuf)];
+
+ sprintf(buffer,
+ "Failed to authenticate client as Postgres user '%s' "
+ "using %s: %s",
+ namebuf, name_of_authentication_type(msgType), PQerrormsg);
+ strncpy(errormsg, buffer, errormsg_len);
+ *status = STATUS_ERROR;
+ }
+ else
+ {
+ if (BackendStartup(&sp, port, &pid) != STATUS_OK)
+ {
+ strncpy(errormsg, "Startup (fork) of backend failed.",
+ errormsg_len);
+ *status = STATUS_ERROR;
+ }
+ else
+ {
+ errormsg[0] = '\0'; /* just for robustness */
+ *status = STATUS_OK;
+ }
+ }
+ }
+ if (*status == STATUS_ERROR)
+ fprintf(stderr, "%s: ConnStartup: %s\n", progname, errormsg);
}
/*
- send_error_reply: send a reply to the front end telling it that
- the connection was a bust, and why.
-
- "port" tells to whom and how to send the reply. "errormsg" is
- the string of text telling what the problem was.
-
- It should be noted that we're executing a pretty messy protocol
- here. The postmaster does not reply when the connection is
- successful, but rather just hands the connection off to the
- backend and the backend waits for a query from the frontend.
- Thus, the frontend is not expecting any reply in regards to the
- connect request.
-
- But when the connection fails, we send this reply that starts
- with "E". The frontend only gets this reply when it sends its
- first query and waits for the reply. Nobody receives that query,
- but this reply is already in the pipe, so that's what the
- frontend sees.
-
- Note that the backend closes the socket immediately after sending
- the reply, so to give the frontend a fighting chance to see the
- error info, we set the socket to linger up to 3 seconds waiting
- for the frontend to retrieve the message. That's all the delay
- we can afford, since we have other clients to serve and the
- postmaster will be blocked the whole time. Also, if there is no
- message space in the socket for the reply (shouldn't be a
- problem) the postmaster will block until the frontend reads the
- reply.
+ send_error_reply: send a reply to the front end telling it that
+ the connection was a bust, and why.
+
+ "port" tells to whom and how to send the reply. "errormsg" is
+ the string of text telling what the problem was.
+
+ It should be noted that we're executing a pretty messy protocol
+ here. The postmaster does not reply when the connection is
+ successful, but rather just hands the connection off to the
+ backend and the backend waits for a query from the frontend.
+ Thus, the frontend is not expecting any reply in regards to the
+ connect request.
+
+ But when the connection fails, we send this reply that starts
+ with "E". The frontend only gets this reply when it sends its
+ first query and waits for the reply. Nobody receives that query,
+ but this reply is already in the pipe, so that's what the
+ frontend sees.
+
+ Note that the backend closes the socket immediately after sending
+ the reply, so to give the frontend a fighting chance to see the
+ error info, we set the socket to linger up to 3 seconds waiting
+ for the frontend to retrieve the message. That's all the delay
+ we can afford, since we have other clients to serve and the
+ postmaster will be blocked the whole time. Also, if there is no
+ message space in the socket for the reply (shouldn't be a
+ problem) the postmaster will block until the frontend reads the
+ reply.
*/
static void
-send_error_reply(Port *port, const char *errormsg)
+send_error_reply(Port * port, const char *errormsg)
{
- int rc; /* return code from sendto */
- char *reply;
- /* The literal reply string we put into the socket. This is a pointer
- to storage we malloc.
- */
- const struct linger linger_parm = {true, LINGER_TIME};
- /* A parameter for setsockopt() that tells it to have close() block for
- a while waiting for the frontend to read its outstanding messages.
- */
-
- reply = malloc(strlen(errormsg)+10);
-
- sprintf(reply, "E%s", errormsg);
-
- rc = send(port->sock, (Addr) reply, strlen(reply)+1, /* flags */ 0);
- if (rc < 0)
- fprintf(stderr,
- "%s: ServerLoop:\t\t"
- "Failed to send error reply to front end\n",
- progname);
- else if (rc < strlen(reply)+1)
- fprintf(stderr,
- "%s: ServerLoop:\t\t"
- "Only partial error reply sent to front end.\n",
- progname);
-
- free(reply);
- /* Now we have to make sure frontend has a chance to see what we
- just wrote.
- */
- rc = setsockopt(port->sock, SOL_SOCKET, SO_LINGER,
- &linger_parm, sizeof(linger_parm));
+ int rc; /* return code from sendto */
+ char *reply;
+
+ /*
+ * The literal reply string we put into the socket. This is a pointer
+ * to storage we malloc.
+ */
+ const struct linger linger_parm = {true, LINGER_TIME};
+
+ /*
+ * A parameter for setsockopt() that tells it to have close() block
+ * for a while waiting for the frontend to read its outstanding
+ * messages.
+ */
+
+ reply = malloc(strlen(errormsg) + 10);
+
+ sprintf(reply, "E%s", errormsg);
+
+ rc = send(port->sock, (Addr) reply, strlen(reply) + 1, /* flags */ 0);
+ if (rc < 0)
+ fprintf(stderr,
+ "%s: ServerLoop:\t\t"
+ "Failed to send error reply to front end\n",
+ progname);
+ else if (rc < strlen(reply) + 1)
+ fprintf(stderr,
+ "%s: ServerLoop:\t\t"
+ "Only partial error reply sent to front end.\n",
+ progname);
+
+ free(reply);
+
+ /*
+ * Now we have to make sure frontend has a chance to see what we just
+ * wrote.
+ */
+ rc = setsockopt(port->sock, SOL_SOCKET, SO_LINGER,
+ &linger_parm, sizeof(linger_parm));
}
@@ -759,26 +837,29 @@ send_error_reply(Port *port, const char *errormsg)
static int
ConnCreate(int serverFd, int *newFdP)
{
- int status;
- Port *port;
-
-
- if (!(port = (Port *) calloc(1, sizeof(Port)))) {
- fprintf(stderr, "%s: ConnCreate: malloc failed\n",
- progname);
- ExitPostmaster(1);
- }
-
- if ((status = StreamConnection(serverFd, port)) != STATUS_OK) {
- StreamClose(port->sock);
- free(port);
- }
- else {
- DLAddHead(PortList, DLNewElem(port));
- *newFdP = port->sock;
- }
-
- return (status);
+ int status;
+ Port *port;
+
+
+ if (!(port = (Port *) calloc(1, sizeof(Port))))
+ {
+ fprintf(stderr, "%s: ConnCreate: malloc failed\n",
+ progname);
+ ExitPostmaster(1);
+ }
+
+ if ((status = StreamConnection(serverFd, port)) != STATUS_OK)
+ {
+ StreamClose(port->sock);
+ free(port);
+ }
+ else
+ {
+ DLAddHead(PortList, DLNewElem(port));
+ *newFdP = port->sock;
+ }
+
+ return (status);
}
/*
@@ -787,11 +868,11 @@ ConnCreate(int serverFd, int *newFdP)
static void
reset_shared(short port)
{
- IPCKey key;
-
- key = SystemPortAddressCreateIPCKey((SystemPortAddress) port);
- CreateSharedMemoryAndSemaphores(key);
- ActiveBackends = FALSE;
+ IPCKey key;
+
+ key = SystemPortAddressCreateIPCKey((SystemPortAddress) port);
+ CreateSharedMemoryAndSemaphores(key);
+ ActiveBackends = FALSE;
}
/*
@@ -800,7 +881,7 @@ reset_shared(short port)
static void
pmdie(SIGNAL_ARGS)
{
- exitpg(0);
+ exitpg(0);
}
/*
@@ -811,25 +892,29 @@ reaper(SIGNAL_ARGS)
{
/* GH: replace waitpid for !HAVE_WAITPID. Does this work ? */
#ifdef HAVE_WAITPID
- int status; /* backend exit status */
+ int status; /* backend exit status */
+
#else
- union wait statusp; /* backend exit status */
+ union wait statusp; /* backend exit status */
+
#endif
- int pid; /* process id of dead backend */
-
- if (DebugLvl)
- fprintf(stderr, "%s: reaping dead processes...\n",
- progname);
+ int pid; /* process id of dead backend */
+
+ if (DebugLvl)
+ fprintf(stderr, "%s: reaping dead processes...\n",
+ progname);
#ifdef HAVE_WAITPID
- while((pid = waitpid(-1, &status, WNOHANG)) > 0) {
- CleanupProc(pid, status);
- pqsignal(SIGCHLD, reaper);
- }
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+ {
+ CleanupProc(pid, status);
+ pqsignal(SIGCHLD, reaper);
+ }
#else
- while((pid = wait3(&statusp, WNOHANG, NULL)) > 0) {
- CleanupProc(pid, statusp.w_status);
- pqsignal(SIGCHLD, reaper);
- }
+ while ((pid = wait3(&statusp, WNOHANG, NULL)) > 0)
+ {
+ CleanupProc(pid, statusp.w_status);
+ pqsignal(SIGCHLD, reaper);
+ }
#endif
}
@@ -842,189 +927,204 @@ reaper(SIGNAL_ARGS)
*/
static void
CleanupProc(int pid,
- int exitstatus) /* child's exit status. */
+ int exitstatus) /* child's exit status. */
{
- Dlelem *prev, *curr;
- Backend *bp;
- int sig;
-
- if (DebugLvl) {
- fprintf(stderr, "%s: CleanupProc: pid %d exited with status %d\n",
- progname, pid, exitstatus);
- }
- /*
- * -------------------------
- * If a backend dies in an ugly way (i.e. exit status not 0) then
- * we must signal all other backends to quickdie. If exit status
- * is zero we assume everything is hunky dory and simply remove the
- * backend from the active backend list.
- * -------------------------
- */
- if (!exitstatus) {
- curr = DLGetHead(BackendList);
- while (curr) {
- bp = (Backend*)DLE_VAL(curr);
- if (bp->pid == pid) {
- DLRemove(curr);
- free(bp);
- DLFreeElem(curr);
- break;
- }
- curr = DLGetSucc(curr);
- }
-
- ProcRemove(pid);
-
- return;
- }
-
- curr = DLGetHead(BackendList);
- while (curr) {
- bp = (Backend*)DLE_VAL(curr);
-
- /*
- * -----------------
- * SIGUSR1 is the special signal that sez exit without exitpg
- * and let the user know what's going on. ProcSemaphoreKill()
- * cleans up the backends semaphore. If SendStop is set (-s on
- * command line), then we send a SIGSTOP so that we can
- * core dumps from all backends by hand.
- * -----------------
- */
- sig = (SendStop) ? SIGSTOP : SIGUSR1;
- if (bp->pid != pid) {
- if (DebugLvl)
- fprintf(stderr, "%s: CleanupProc: sending %s to process %d\n",
- progname,
- (sig == SIGUSR1)
- ? "SIGUSR1" : "SIGSTOP",
- bp->pid);
- kill(bp->pid, sig);
- }
- ProcRemove(bp->pid);
-
- prev = DLGetPred(curr);
- DLRemove(curr);
- free(bp);
- DLFreeElem(curr);
- if (!prev) { /* removed head */
- curr = DLGetHead(BackendList);
- continue;
- }
- curr = DLGetSucc(prev);
- }
- /*
- * -------------
- * Quasi_exit means run all of the on_exitpg routines but don't
- * acutally call exit(). The on_exit list of routines to do is
- * also truncated.
- *
- * Nothing up my sleeve here, ActiveBackends means that since the
- * last time we recreated shared memory and sems another frontend
- * has requested and received a connection and I have forked off
- * another backend. This prevents me from reinitializing shared
- * stuff more than once for the set of backends that caused the
- * failure and were killed off.
- * ----------------
- */
- if (ActiveBackends == TRUE && Reinit) {
- if (DebugLvl)
- fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n",
- progname);
- quasi_exitpg();
- reset_shared(PostPortName);
- }
+ Dlelem *prev,
+ *curr;
+ Backend *bp;
+ int sig;
+
+ if (DebugLvl)
+ {
+ fprintf(stderr, "%s: CleanupProc: pid %d exited with status %d\n",
+ progname, pid, exitstatus);
+ }
+
+ /*
+ * ------------------------- If a backend dies in an ugly way (i.e.
+ * exit status not 0) then we must signal all other backends to
+ * quickdie. If exit status is zero we assume everything is hunky
+ * dory and simply remove the backend from the active backend list.
+ * -------------------------
+ */
+ if (!exitstatus)
+ {
+ curr = DLGetHead(BackendList);
+ while (curr)
+ {
+ bp = (Backend *) DLE_VAL(curr);
+ if (bp->pid == pid)
+ {
+ DLRemove(curr);
+ free(bp);
+ DLFreeElem(curr);
+ break;
+ }
+ curr = DLGetSucc(curr);
+ }
+
+ ProcRemove(pid);
+
+ return;
+ }
+
+ curr = DLGetHead(BackendList);
+ while (curr)
+ {
+ bp = (Backend *) DLE_VAL(curr);
+
+ /*
+ * ----------------- SIGUSR1 is the special signal that sez exit
+ * without exitpg and let the user know what's going on.
+ * ProcSemaphoreKill() cleans up the backends semaphore. If
+ * SendStop is set (-s on command line), then we send a SIGSTOP so
+ * that we can core dumps from all backends by hand.
+ * -----------------
+ */
+ sig = (SendStop) ? SIGSTOP : SIGUSR1;
+ if (bp->pid != pid)
+ {
+ if (DebugLvl)
+ fprintf(stderr, "%s: CleanupProc: sending %s to process %d\n",
+ progname,
+ (sig == SIGUSR1)
+ ? "SIGUSR1" : "SIGSTOP",
+ bp->pid);
+ kill(bp->pid, sig);
+ }
+ ProcRemove(bp->pid);
+
+ prev = DLGetPred(curr);
+ DLRemove(curr);
+ free(bp);
+ DLFreeElem(curr);
+ if (!prev)
+ { /* removed head */
+ curr = DLGetHead(BackendList);
+ continue;
+ }
+ curr = DLGetSucc(prev);
+ }
+
+ /*
+ * ------------- Quasi_exit means run all of the on_exitpg routines
+ * but don't acutally call exit(). The on_exit list of routines to do
+ * is also truncated.
+ *
+ * Nothing up my sleeve here, ActiveBackends means that since the last
+ * time we recreated shared memory and sems another frontend has
+ * requested and received a connection and I have forked off another
+ * backend. This prevents me from reinitializing shared stuff more
+ * than once for the set of backends that caused the failure and were
+ * killed off. ----------------
+ */
+ if (ActiveBackends == TRUE && Reinit)
+ {
+ if (DebugLvl)
+ fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n",
+ progname);
+ quasi_exitpg();
+ reset_shared(PostPortName);
+ }
}
/*
* BackendStartup -- start backend process
*
* returns: STATUS_ERROR if the fork/exec failed, STATUS_OK
- * otherwise.
+ * otherwise.
*
*/
static int
-BackendStartup(StartupInfo *packet, /* client's startup packet */
- Port *port,
- int *pidPtr)
+BackendStartup(StartupInfo * packet, /* client's startup packet */
+ Port * port,
+ int *pidPtr)
{
- Backend* bn; /* for backend cleanup */
- int pid, i;
- static char envEntry[4][2 * ARGV_SIZE];
-
- for (i = 0; i < 4; ++i) {
- memset(envEntry[i], 0, 2*ARGV_SIZE);
- }
- /*
- * Set up the necessary environment variables for the backend
- * This should really be some sort of message....
- */
- sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
- putenv(envEntry[0]);
- sprintf(envEntry[1], "POSTID=%d", NextBackendId);
- putenv(envEntry[1]);
- sprintf(envEntry[2], "PG_USER=%s", packet->user);
- putenv(envEntry[2]);
- if (!getenv("PGDATA")) {
- sprintf(envEntry[3], "PGDATA=%s", DataDir);
- putenv(envEntry[3]);
- }
- if (DebugLvl > 2) {
- char **p;
- extern char **environ;
-
- fprintf(stderr, "%s: BackendStartup: environ dump:\n",
- progname);
- fprintf(stderr, "-----------------------------------------\n");
- for (p = environ; *p; ++p)
- fprintf(stderr, "\t%s\n", *p);
- fprintf(stderr, "-----------------------------------------\n");
- }
-
- if ((pid = FORK()) == 0) { /* child */
- if (DoExec(packet, port->sock))
- fprintf(stderr, "%s child[%d]: BackendStartup: execv failed\n",
- progname, pid);
- /* use _exit to keep from double-flushing stdio */
- _exit(1);
- }
-
- /* in parent */
- if (pid < 0) {
- fprintf(stderr, "%s: BackendStartup: fork failed\n",
- progname);
- return(STATUS_ERROR);
- }
-
- if (DebugLvl)
- fprintf(stderr, "%s: BackendStartup: pid %d user %s db %s socket %d\n",
- progname, pid, packet->user,
- (packet->database[0] == '\0' ? packet->user : packet->database),
- port->sock);
-
- /* adjust backend counter */
- /* XXX Don't know why this is done, but for now backend needs it */
- NextBackendId -= 1;
-
- /*
- * Everything's been successful, it's safe to add this backend to our
- * list of backends.
- */
- if (!(bn = (Backend *) calloc(1, sizeof (Backend)))) {
- fprintf(stderr, "%s: BackendStartup: malloc failed\n",
- progname);
- ExitPostmaster(1);
- }
-
- bn->pid = pid;
- DLAddHead(BackendList,DLNewElem(bn));
-
- if (MultiplexedBackends)
- MultiplexedBackendPort++;
-
- *pidPtr = pid;
-
- return(STATUS_OK);
+ Backend *bn; /* for backend cleanup */
+ int pid,
+ i;
+ static char envEntry[4][2 * ARGV_SIZE];
+
+ for (i = 0; i < 4; ++i)
+ {
+ memset(envEntry[i], 0, 2 * ARGV_SIZE);
+ }
+
+ /*
+ * Set up the necessary environment variables for the backend This
+ * should really be some sort of message....
+ */
+ sprintf(envEntry[0], "POSTPORT=%d", PostPortName);
+ putenv(envEntry[0]);
+ sprintf(envEntry[1], "POSTID=%d", NextBackendId);
+ putenv(envEntry[1]);
+ sprintf(envEntry[2], "PG_USER=%s", packet->user);
+ putenv(envEntry[2]);
+ if (!getenv("PGDATA"))
+ {
+ sprintf(envEntry[3], "PGDATA=%s", DataDir);
+ putenv(envEntry[3]);
+ }
+ if (DebugLvl > 2)
+ {
+ char **p;
+ extern char **environ;
+
+ fprintf(stderr, "%s: BackendStartup: environ dump:\n",
+ progname);
+ fprintf(stderr, "-----------------------------------------\n");
+ for (p = environ; *p; ++p)
+ fprintf(stderr, "\t%s\n", *p);
+ fprintf(stderr, "-----------------------------------------\n");
+ }
+
+ if ((pid = FORK()) == 0)
+ { /* child */
+ if (DoExec(packet, port->sock))
+ fprintf(stderr, "%s child[%d]: BackendStartup: execv failed\n",
+ progname, pid);
+ /* use _exit to keep from double-flushing stdio */
+ _exit(1);
+ }
+
+ /* in parent */
+ if (pid < 0)
+ {
+ fprintf(stderr, "%s: BackendStartup: fork failed\n",
+ progname);
+ return (STATUS_ERROR);
+ }
+
+ if (DebugLvl)
+ fprintf(stderr, "%s: BackendStartup: pid %d user %s db %s socket %d\n",
+ progname, pid, packet->user,
+ (packet->database[0] == '\0' ? packet->user : packet->database),
+ port->sock);
+
+ /* adjust backend counter */
+ /* XXX Don't know why this is done, but for now backend needs it */
+ NextBackendId -= 1;
+
+ /*
+ * Everything's been successful, it's safe to add this backend to our
+ * list of backends.
+ */
+ if (!(bn = (Backend *) calloc(1, sizeof(Backend))))
+ {
+ fprintf(stderr, "%s: BackendStartup: malloc failed\n",
+ progname);
+ ExitPostmaster(1);
+ }
+
+ bn->pid = pid;
+ DLAddHead(BackendList, DLNewElem(bn));
+
+ if (MultiplexedBackends)
+ MultiplexedBackendPort++;
+
+ *pidPtr = pid;
+
+ return (STATUS_OK);
}
/*
@@ -1040,19 +1140,20 @@ BackendStartup(StartupInfo *packet, /* client's startup packet */
static void
split_opts(char **argv, int *argcp, char *s)
{
- int i = *argcp;
-
- while (s && *s) {
- while (isspace(*s))
- ++s;
- if (*s)
- argv[i++] = s;
- while (*s && !isspace(*s))
- ++s;
- if (isspace(*s))
- *s++ = '\0';
- }
- *argcp = i;
+ int i = *argcp;
+
+ while (s && *s)
+ {
+ while (isspace(*s))
+ ++s;
+ if (*s)
+ argv[i++] = s;
+ while (*s && !isspace(*s))
+ ++s;
+ if (isspace(*s))
+ *s++ = '\0';
+ }
+ *argcp = i;
}
/*
@@ -1063,88 +1164,93 @@ split_opts(char **argv, int *argcp, char *s)
* its thread back. (This is vfork() we're talking about. If we're using
* fork() because we don't have vfork(), then we don't really care.)
*
- * returns:
- * Shouldn't return at all.
- * If execv() fails, return status.
+ * returns:
+ * Shouldn't return at all.
+ * If execv() fails, return status.
*/
static int
-DoExec(StartupInfo *packet, int portFd)
+DoExec(StartupInfo * packet, int portFd)
{
- char execbuf[MAXPATHLEN];
- char portbuf[ARGV_SIZE];
- char mbbuf[ARGV_SIZE];
- char debugbuf[ARGV_SIZE];
- char ttybuf[ARGV_SIZE + 1];
- char argbuf[(2 * ARGV_SIZE) + 1];
- /*
- * each argument takes at least three chars, so we can't
- * have more than ARGV_SIZE arguments in (2 * ARGV_SIZE)
- * chars (i.e., packet->options plus ExtraOptions)...
- */
- char *av[ARGV_SIZE];
- char dbbuf[ARGV_SIZE + 1];
- int ac = 0;
- int i;
-
- strncpy(execbuf, Execfile, MAXPATHLEN-1);
- av[ac++] = execbuf;
-
- /* Tell the backend it is being called from the postmaster */
- av[ac++] = "-p";
-
- /*
- * Pass the requested debugging level along to the backend. We
- * decrement by one; level one debugging in the postmaster traces
- * postmaster connection activity, and levels two and higher
- * are passed along to the backend. This allows us to watch only
- * the postmaster or the postmaster and the backend.
- */
-
- if (DebugLvl > 1) {
- sprintf(debugbuf, "-d%d", DebugLvl);
- av[ac++] = debugbuf;
- }
- else
- av[ac++] = "-Q";
-
- /* Pass the requested debugging output file */
- if (packet->tty[0]) {
- strncpy(ttybuf, packet->tty, ARGV_SIZE);
- av[ac++] = "-o";
- av[ac++] = ttybuf;
- }
-
- /* tell the multiplexed backend to start on a certain port */
- if (MultiplexedBackends) {
- sprintf(mbbuf, "-m %d", MultiplexedBackendPort);
- av[ac++] = mbbuf;
- }
- /* Tell the backend the descriptor of the fe/be socket */
- sprintf(portbuf, "-P%d", portFd);
- av[ac++] = portbuf;
-
- strNcpy(argbuf, packet->options, ARGV_SIZE);
- strncat(argbuf, ExtraOptions, ARGV_SIZE);
- argbuf[(2 * ARGV_SIZE)] = '\0';
- split_opts(av, &ac, argbuf);
-
- if (packet->database[0])
- strNcpy(dbbuf, packet->database, ARGV_SIZE);
- else
- strNcpy(dbbuf, packet->user, NAMEDATALEN-1);
- av[ac++] = dbbuf;
-
- av[ac] = (char *) NULL;
-
- if (DebugLvl > 1) {
- fprintf(stderr, "%s child[%ld]: execv(",
- progname, (long)getpid());
- for (i = 0; i < ac; ++i)
- fprintf(stderr, "%s, ", av[i]);
- fprintf(stderr, ")\n");
- }
-
- return(execv(av[0], av));
+ char execbuf[MAXPATHLEN];
+ char portbuf[ARGV_SIZE];
+ char mbbuf[ARGV_SIZE];
+ char debugbuf[ARGV_SIZE];
+ char ttybuf[ARGV_SIZE + 1];
+ char argbuf[(2 * ARGV_SIZE) + 1];
+
+ /*
+ * each argument takes at least three chars, so we can't have more
+ * than ARGV_SIZE arguments in (2 * ARGV_SIZE) chars (i.e.,
+ * packet->options plus ExtraOptions)...
+ */
+ char *av[ARGV_SIZE];
+ char dbbuf[ARGV_SIZE + 1];
+ int ac = 0;
+ int i;
+
+ strncpy(execbuf, Execfile, MAXPATHLEN - 1);
+ av[ac++] = execbuf;
+
+ /* Tell the backend it is being called from the postmaster */
+ av[ac++] = "-p";
+
+ /*
+ * Pass the requested debugging level along to the backend. We
+ * decrement by one; level one debugging in the postmaster traces
+ * postmaster connection activity, and levels two and higher are
+ * passed along to the backend. This allows us to watch only the
+ * postmaster or the postmaster and the backend.
+ */
+
+ if (DebugLvl > 1)
+ {
+ sprintf(debugbuf, "-d%d", DebugLvl);
+ av[ac++] = debugbuf;
+ }
+ else
+ av[ac++] = "-Q";
+
+ /* Pass the requested debugging output file */
+ if (packet->tty[0])
+ {
+ strncpy(ttybuf, packet->tty, ARGV_SIZE);
+ av[ac++] = "-o";
+ av[ac++] = ttybuf;
+ }
+
+ /* tell the multiplexed backend to start on a certain port */
+ if (MultiplexedBackends)
+ {
+ sprintf(mbbuf, "-m %d", MultiplexedBackendPort);
+ av[ac++] = mbbuf;
+ }
+ /* Tell the backend the descriptor of the fe/be socket */
+ sprintf(portbuf, "-P%d", portFd);
+ av[ac++] = portbuf;
+
+ strNcpy(argbuf, packet->options, ARGV_SIZE);
+ strncat(argbuf, ExtraOptions, ARGV_SIZE);
+ argbuf[(2 * ARGV_SIZE)] = '\0';
+ split_opts(av, &ac, argbuf);
+
+ if (packet->database[0])
+ strNcpy(dbbuf, packet->database, ARGV_SIZE);
+ else
+ strNcpy(dbbuf, packet->user, NAMEDATALEN - 1);
+ av[ac++] = dbbuf;
+
+ av[ac] = (char *) NULL;
+
+ if (DebugLvl > 1)
+ {
+ fprintf(stderr, "%s child[%ld]: execv(",
+ progname, (long) getpid());
+ for (i = 0; i < ac; ++i)
+ fprintf(stderr, "%s, ", av[i]);
+ fprintf(stderr, ")\n");
+ }
+
+ return (execv(av[0], av));
}
/*
@@ -1153,34 +1259,31 @@ DoExec(StartupInfo *packet, int portFd)
static void
ExitPostmaster(int status)
{
- /* should cleanup shared memory and kill all backends */
-
- /*
- * Not sure of the semantics here. When the Postmaster dies,
- * should the backends all be killed? probably not.
- */
- if (ServerSock != INVALID_SOCK)
- close(ServerSock);
- exitpg(status);
+ /* should cleanup shared memory and kill all backends */
+
+ /*
+ * Not sure of the semantics here. When the Postmaster dies, should
+ * the backends all be killed? probably not.
+ */
+ if (ServerSock != INVALID_SOCK)
+ close(ServerSock);
+ exitpg(status);
}
static void
dumpstatus(SIGNAL_ARGS)
{
- Dlelem *curr = DLGetHead(PortList);
-
- while (curr) {
- Port *port = DLE_VAL(curr);
-
- fprintf(stderr, "%s: dumpstatus:\n", progname);
- fprintf(stderr, "\tsock %d: nBytes=%d, laddr=0x%lx, raddr=0x%lx\n",
- port->sock, port->nBytes,
- (long int) port->laddr.sin_addr.s_addr,
- (long int) port->raddr.sin_addr.s_addr);
- curr = DLGetSucc(curr);
- }
+ Dlelem *curr = DLGetHead(PortList);
+
+ while (curr)
+ {
+ Port *port = DLE_VAL(curr);
+
+ fprintf(stderr, "%s: dumpstatus:\n", progname);
+ fprintf(stderr, "\tsock %d: nBytes=%d, laddr=0x%lx, raddr=0x%lx\n",
+ port->sock, port->nBytes,
+ (long int) port->laddr.sin_addr.s_addr,
+ (long int) port->raddr.sin_addr.s_addr);
+ curr = DLGetSucc(curr);
+ }
}
-
-
-
-
diff --git a/src/backend/regex/engine.c b/src/backend/regex/engine.c
index 3c323586d6b..6e0e7012140 100644
--- a/src/backend/regex/engine.c
+++ b/src/backend/regex/engine.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
@@ -10,22 +10,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)
@@ -34,7 +34,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)engine.c 8.5 (Berkeley) 3/20/94
+ * @(#)engine.c 8.5 (Berkeley) 3/20/94
*/
/*
@@ -45,150 +45,157 @@
*/
#ifdef SNAMES
-#define matcher smatcher
-#define fast sfast
-#define slow sslow
-#define dissect sdissect
-#define backref sbackref
-#define step sstep
-#define print sprint
-#define at sat
-#define match smat
+#define matcher smatcher
+#define fast sfast
+#define slow sslow
+#define dissect sdissect
+#define backref sbackref
+#define step sstep
+#define print sprint
+#define at sat
+#define match smat
#endif
#ifdef LNAMES
-#define matcher lmatcher
-#define fast lfast
-#define slow lslow
-#define dissect ldissect
-#define backref lbackref
-#define step lstep
-#define print lprint
-#define at lat
-#define match lmat
+#define matcher lmatcher
+#define fast lfast
+#define slow lslow
+#define dissect ldissect
+#define backref lbackref
+#define step lstep
+#define print lprint
+#define at lat
+#define match lmat
#endif
/* another structure passed up and down to avoid zillions of parameters */
-struct match {
+struct match
+{
struct re_guts *g;
- int eflags;
- regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
- char *offp; /* offsets work from here */
- char *beginp; /* start of string -- virtual NUL precedes */
- char *endp; /* end of string -- virtual NUL here */
- char *coldp; /* can be no match starting before here */
- char **lastpos; /* [nplus+1] */
- STATEVARS;
- states st; /* current states */
- states fresh; /* states for a fresh start */
- states tmp; /* temporary */
- states empty; /* empty set of states */
+ int eflags;
+ regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
+ char *offp; /* offsets work from here */
+ char *beginp; /* start of string -- virtual NUL precedes */
+ char *endp; /* end of string -- virtual NUL here */
+ char *coldp; /* can be no match starting before here */
+ char **lastpos; /* [nplus+1] */
+ STATEVARS;
+ states st; /* current states */
+ states fresh; /* states for a fresh start */
+ states tmp; /* temporary */
+ states empty; /* empty set of states */
};
/* ========= begin header generated by ./mkh ========= */
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
/* === engine.c === */
-static int
-matcher(struct re_guts *g, char *string, size_t nmatch,
- regmatch_t pmatch[], int eflags);
-static char *
-dissect(struct match *m, char *start, char *stop,
- sopno startst, sopno stopst);
-static char *
-backref(struct match *m, char *start, char *stop,
- sopno startst, sopno stopst, sopno lev);
-static char *
-fast(struct match *m, char *start, char *stop,
- sopno startst, sopno stopst);
-static char *
-slow(struct match *m, char *start, char *stop, sopno startst, sopno stopst);
-static states
-step(struct re_guts *g, sopno start,
- sopno stop, states bef, int ch, states aft);
-#define BOL (OUT+1)
-#define EOL (BOL+1)
-#define BOLEOL (BOL+2)
-#define NOTHING (BOL+3)
-#define BOW (BOL+4)
-#define EOW (BOL+5)
-#define CODEMAX (BOL+5) /* highest code used */
-#define NONCHAR(c) ((c) > CHAR_MAX)
-#define NNONCHAR (CODEMAX-CHAR_MAX)
+ static int
+ matcher(struct re_guts * g, char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags);
+ static char *
+ dissect(struct match * m, char *start, char *stop,
+ sopno startst, sopno stopst);
+ static char *
+ backref(struct match * m, char *start, char *stop,
+ sopno startst, sopno stopst, sopno lev);
+ static char *
+ fast(struct match * m, char *start, char *stop,
+ sopno startst, sopno stopst);
+ static char *
+ slow(struct match * m, char *start, char *stop, sopno startst, sopno stopst);
+ static states
+ step(struct re_guts * g, sopno start,
+ sopno stop, states bef, int ch, states aft);
+#define BOL (OUT+1)
+#define EOL (BOL+1)
+#define BOLEOL (BOL+2)
+#define NOTHING (BOL+3)
+#define BOW (BOL+4)
+#define EOW (BOL+5)
+#define CODEMAX (BOL+5) /* highest code used */
+#define NONCHAR(c) ((c) > CHAR_MAX)
+#define NNONCHAR (CODEMAX-CHAR_MAX)
#ifdef REDEBUG
-static void
-print(struct match *m, char *caption, states st, int ch, FILE *d);
+ static void
+ print(struct match * m, char *caption, states st, int ch, FILE * d);
#endif
#ifdef REDEBUG
-static void
-at(struct match *m, char *title, char *start, char *stop,
- sopno startst, sopno stopst);
+ static void
+ at(struct match * m, char *title, char *start, char *stop,
+ sopno startst, sopno stopst);
#endif
#ifdef REDEBUG
-static char *
-pchar(int ch);
+ static char *
+ pchar(int ch);
#endif
#ifdef __cplusplus
}
+
#endif
/* ========= end header generated by ./mkh ========= */
#ifdef REDEBUG
-#define SP(t, s, c) print(m, t, s, c, stdout)
-#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
-#define NOTE(str) { if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
+#define SP(t, s, c) print(m, t, s, c, stdout)
+#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
+#define NOTE(str) { if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
#else
-#define SP(t, s, c) /* nothing */
-#define AT(t, p1, p2, s1, s2) /* nothing */
-#define NOTE(s) /* nothing */
+#define SP(t, s, c) /* nothing */
+#define AT(t, p1, p2, s1, s2) /* nothing */
+#define NOTE(s) /* nothing */
#endif
/*
- matcher - the actual matching engine
== static int matcher(register struct re_guts *g, char *string, \
- == size_t nmatch, regmatch_t pmatch[], int eflags);
+ == size_t nmatch, regmatch_t pmatch[], int eflags);
*/
-static int /* 0 success, REG_NOMATCH failure */
+static int /* 0 success, REG_NOMATCH failure */
matcher(g, string, nmatch, pmatch, eflags)
register struct re_guts *g;
-char *string;
-size_t nmatch;
-regmatch_t pmatch[];
-int eflags;
+char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
{
- register char *endp;
- register int i;
- struct match mv;
+ register char *endp;
+ register int i;
+ struct match mv;
register struct match *m = &mv;
- register char *dp;
- register const sopno gf = g->firststate+1; /* +1 for OEND */
+ register char *dp;
+ register const sopno gf = g->firststate + 1; /* +1 for OEND */
register const sopno gl = g->laststate;
- char *start;
- char *stop;
+ char *start;
+ char *stop;
/* simplify the situation where possible */
- if (g->cflags&REG_NOSUB)
+ if (g->cflags & REG_NOSUB)
nmatch = 0;
- if (eflags&REG_STARTEND) {
+ if (eflags & REG_STARTEND)
+ {
start = string + pmatch[0].rm_so;
stop = string + pmatch[0].rm_eo;
- } else {
+ }
+ else
+ {
start = string;
stop = start + strlen(start);
}
if (stop < start)
- return(REG_INVARG);
+ return (REG_INVARG);
/* prescreening; this does wonders for this rather slow code */
- if (g->must != NULL) {
+ if (g->must != NULL)
+ {
for (dp = start; dp < stop; dp++)
if (*dp == g->must[0] && stop - dp >= g->mlen &&
- memcmp(dp, g->must, (size_t)g->mlen) == 0)
+ memcmp(dp, g->must, (size_t) g->mlen) == 0)
break;
- if (dp == stop) /* we didn't find g->must */
- return(REG_NOMATCH);
+ if (dp == stop) /* we didn't find g->must */
+ return (REG_NOMATCH);
}
/* match struct setup */
@@ -207,18 +214,21 @@ int eflags;
CLEAR(m->empty);
/* this loop does only one repetition except for backrefs */
- for (;;) {
+ for (;;)
+ {
endp = fast(m, start, stop, gf, gl);
- if (endp == NULL) { /* a miss */
+ if (endp == NULL)
+ { /* a miss */
STATETEARDOWN(m);
- return(REG_NOMATCH);
+ return (REG_NOMATCH);
}
if (nmatch == 0 && !g->backrefs)
- break; /* no further info needed */
+ break; /* no further info needed */
/* where? */
assert(m->coldp != NULL);
- for (;;) {
+ for (;;)
+ {
NOTE("finding start");
endp = slow(m, m->coldp, stop, gf, gl);
if (endp != NULL)
@@ -227,32 +237,37 @@ int eflags;
m->coldp++;
}
if (nmatch == 1 && !g->backrefs)
- break; /* no further info needed */
+ break; /* no further info needed */
/* oh my, he wants the subexpressions... */
if (m->pmatch == NULL)
- m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
- sizeof(regmatch_t));
- if (m->pmatch == NULL) {
+ m->pmatch = (regmatch_t *) malloc((m->g->nsub + 1) *
+ sizeof(regmatch_t));
+ if (m->pmatch == NULL)
+ {
STATETEARDOWN(m);
- return(REG_ESPACE);
+ return (REG_ESPACE);
}
for (i = 1; i <= m->g->nsub; i++)
m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
- if (!g->backrefs && !(m->eflags&REG_BACKR)) {
+ if (!g->backrefs && !(m->eflags & REG_BACKR))
+ {
NOTE("dissecting");
dp = dissect(m, m->coldp, endp, gf, gl);
- } else {
+ }
+ else
+ {
+ if (g->nplus > 0 && m->lastpos == NULL)
+ m->lastpos = (char **) malloc((g->nplus + 1) *
+ sizeof(char *));
if (g->nplus > 0 && m->lastpos == NULL)
- m->lastpos = (char **)malloc((g->nplus+1) *
- sizeof(char *));
- if (g->nplus > 0 && m->lastpos == NULL) {
+ {
free(m->pmatch);
STATETEARDOWN(m);
- return(REG_ESPACE);
+ return (REG_ESPACE);
}
NOTE("backref dissect");
- dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno) 0);
}
if (dp != NULL)
break;
@@ -260,25 +275,27 @@ int eflags;
/* uh-oh... we couldn't find a subexpression-level match */
assert(g->backrefs); /* must be back references doing it */
assert(g->nplus == 0 || m->lastpos != NULL);
- for (;;) {
+ for (;;)
+ {
if (dp != NULL || endp <= m->coldp)
- break; /* defeat */
+ break; /* defeat */
NOTE("backoff");
- endp = slow(m, m->coldp, endp-1, gf, gl);
+ endp = slow(m, m->coldp, endp - 1, gf, gl);
if (endp == NULL)
- break; /* defeat */
+ break; /* defeat */
/* try it on a shorter possibility */
#ifndef NDEBUG
- for (i = 1; i <= m->g->nsub; i++) {
+ for (i = 1; i <= m->g->nsub; i++)
+ {
assert(m->pmatch[i].rm_so == -1);
assert(m->pmatch[i].rm_eo == -1);
}
#endif
NOTE("backoff dissect");
- dp = backref(m, m->coldp, endp, gf, gl, (sopno)0);
+ dp = backref(m, m->coldp, endp, gf, gl, (sopno) 0);
}
assert(dp == NULL || dp == endp);
- if (dp != NULL) /* found a shorter one */
+ if (dp != NULL) /* found a shorter one */
break;
/* despite initial appearances, there is no match here */
@@ -288,62 +305,67 @@ int eflags;
}
/* fill in the details if requested */
- if (nmatch > 0) {
+ if (nmatch > 0)
+ {
pmatch[0].rm_so = m->coldp - m->offp;
pmatch[0].rm_eo = endp - m->offp;
}
- if (nmatch > 1) {
+ if (nmatch > 1)
+ {
assert(m->pmatch != NULL);
for (i = 1; i < nmatch; i++)
if (i <= m->g->nsub)
pmatch[i] = m->pmatch[i];
- else {
+ else
+ {
pmatch[i].rm_so = -1;
pmatch[i].rm_eo = -1;
}
}
if (m->pmatch != NULL)
- free((char *)m->pmatch);
+ free((char *) m->pmatch);
if (m->lastpos != NULL)
- free((char *)m->lastpos);
+ free((char *) m->lastpos);
STATETEARDOWN(m);
- return(0);
+ return (0);
}
/*
- dissect - figure out what matched what, no back references
== static char *dissect(register struct match *m, char *start, \
- == char *stop, sopno startst, sopno stopst);
+ == char *stop, sopno startst, sopno stopst);
*/
-static char * /* == stop (success) always */
+static char * /* == stop (success) always */
dissect(m, start, stop, startst, stopst)
register struct match *m;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
{
- register int i;
- register sopno ss; /* start sop of current subRE */
- register sopno es; /* end sop of current subRE */
- register char *sp; /* start of string matched by it */
- register char *stp; /* string matched by it cannot pass here */
- register char *rest; /* start of rest of string */
- register char *tail; /* string unmatched by rest of RE */
- register sopno ssub; /* start sop of subsubRE */
- register sopno esub; /* end sop of subsubRE */
- register char *ssp; /* start of string matched by subsubRE */
- register char *sep; /* end of string matched by subsubRE */
- register char *oldssp; /* previous ssp */
- register char *dp;
+ register int i;
+ register sopno ss; /* start sop of current subRE */
+ register sopno es; /* end sop of current subRE */
+ register char *sp; /* start of string matched by it */
+ register char *stp; /* string matched by it cannot pass here */
+ register char *rest; /* start of rest of string */
+ register char *tail; /* string unmatched by rest of RE */
+ register sopno ssub; /* start sop of subsubRE */
+ register sopno esub; /* end sop of subsubRE */
+ register char *ssp; /* start of string matched by subsubRE */
+ register char *sep; /* end of string matched by subsubRE */
+ register char *oldssp; /* previous ssp */
+ register char *dp;
AT("diss", start, stop, startst, stopst);
sp = start;
- for (ss = startst; ss < stopst; ss = es) {
+ for (ss = startst; ss < stopst; ss = es)
+ {
/* identify end of subRE */
es = ss;
- switch (OP(m->g->strip[es])) {
+ switch (OP(m->g->strip[es]))
+ {
case OPLUS_:
case OQUEST_:
es += OPND(m->g->strip[es]);
@@ -356,7 +378,8 @@ sopno stopst;
es++;
/* figure out what it matched */
- switch (OP(m->g->strip[ss])) {
+ switch (OP(m->g->strip[ss]))
+ {
case OEND:
assert(nope);
break;
@@ -376,10 +399,11 @@ sopno stopst;
case O_BACK:
assert(nope);
break;
- /* cases where length of match is hard to find */
+ /* cases where length of match is hard to find */
case OQUEST_:
stp = stop;
- for (;;) {
+ for (;;)
+ {
/* how long could this one be? */
rest = slow(m, sp, stp, ss, es);
assert(rest != NULL); /* it did match */
@@ -389,21 +413,25 @@ sopno stopst;
break; /* yes! */
/* no -- try a shorter match for this one */
stp = rest - 1;
- assert(stp >= sp); /* it did work */
+ assert(stp >= sp); /* it did work */
}
ssub = ss + 1;
esub = es - 1;
/* did innards match? */
- if (slow(m, sp, rest, ssub, esub) != NULL) {
+ if (slow(m, sp, rest, ssub, esub) != NULL)
+ {
dp = dissect(m, sp, rest, ssub, esub);
assert(dp == rest);
- } else /* no */
+ }
+ else
+/* no */
assert(sp == rest);
sp = rest;
break;
case OPLUS_:
stp = stop;
- for (;;) {
+ for (;;)
+ {
/* how long could this one be? */
rest = slow(m, sp, stp, ss, es);
assert(rest != NULL); /* it did match */
@@ -413,25 +441,27 @@ sopno stopst;
break; /* yes! */
/* no -- try a shorter match for this one */
stp = rest - 1;
- assert(stp >= sp); /* it did work */
+ assert(stp >= sp); /* it did work */
}
ssub = ss + 1;
esub = es - 1;
ssp = sp;
oldssp = ssp;
- for (;;) { /* find last match of innards */
+ for (;;)
+ { /* find last match of innards */
sep = slow(m, ssp, rest, ssub, esub);
if (sep == NULL || sep == ssp)
- break; /* failed or matched null */
+ break; /* failed or matched null */
oldssp = ssp; /* on to next try */
ssp = sep;
}
- if (sep == NULL) {
+ if (sep == NULL)
+ {
/* last successful match */
sep = ssp;
ssp = oldssp;
}
- assert(sep == rest); /* must exhaust substring */
+ assert(sep == rest);/* must exhaust substring */
assert(slow(m, ssp, sep, ssub, esub) == rest);
dp = dissect(m, ssp, sep, ssub, esub);
assert(dp == sep);
@@ -439,7 +469,8 @@ sopno stopst;
break;
case OCH_:
stp = stop;
- for (;;) {
+ for (;;)
+ {
/* how long could this one be? */
rest = slow(m, sp, stp, ss, es);
assert(rest != NULL); /* it did match */
@@ -449,14 +480,15 @@ sopno stopst;
break; /* yes! */
/* no -- try a shorter match for this one */
stp = rest - 1;
- assert(stp >= sp); /* it did work */
+ assert(stp >= sp); /* it did work */
}
ssub = ss + 1;
esub = ss + OPND(m->g->strip[ss]) - 1;
assert(OP(m->g->strip[esub]) == OOR1);
- for (;;) { /* find first matching branch */
+ for (;;)
+ { /* find first matching branch */
if (slow(m, sp, rest, ssub, esub) == rest)
- break; /* it matched all of it */
+ break; /* it matched all of it */
/* that one missed, try next one */
assert(OP(m->g->strip[esub]) == OOR1);
esub++;
@@ -489,42 +521,42 @@ sopno stopst;
assert(0 < i && i <= m->g->nsub);
m->pmatch[i].rm_eo = sp - m->offp;
break;
- default: /* uh oh */
+ default: /* uh oh */
assert(nope);
break;
}
}
assert(sp == stop);
- return(sp);
+ return (sp);
}
/*
- backref - figure out what matched what, figuring in back references
== static char *backref(register struct match *m, char *start, \
- == char *stop, sopno startst, sopno stopst, sopno lev);
+ == char *stop, sopno startst, sopno stopst, sopno lev);
*/
-static char * /* == stop (success) or NULL (failure) */
+static char * /* == stop (success) or NULL (failure) */
backref(m, start, stop, startst, stopst, lev)
register struct match *m;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
-sopno lev; /* PLUS nesting level */
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
+sopno lev; /* PLUS nesting level */
{
- register int i;
- register sopno ss; /* start sop of current subRE */
- register char *sp; /* start of string matched by it */
- register sopno ssub; /* start sop of subsubRE */
- register sopno esub; /* end sop of subsubRE */
- register char *ssp; /* start of string matched by subsubRE */
- register char *dp;
+ register int i;
+ register sopno ss; /* start sop of current subRE */
+ register char *sp; /* start of string matched by it */
+ register sopno ssub; /* start sop of subsubRE */
+ register sopno esub; /* end sop of subsubRE */
+ register char *ssp; /* start of string matched by subsubRE */
+ register char *dp;
register size_t len;
- register int hard;
- register sop s;
+ register int hard;
+ register sop s;
register regoff_t offsave;
- register cset *cs;
+ register cset *cs;
AT("back", start, stop, startst, stopst);
sp = start;
@@ -532,135 +564,144 @@ sopno lev; /* PLUS nesting level */
/* get as far as we can with easy stuff */
hard = 0;
for (ss = startst; !hard && ss < stopst; ss++)
- switch (OP(s = m->g->strip[ss])) {
+ switch (OP(s = m->g->strip[ss]))
+ {
case OCHAR:
- if (sp == stop || *sp++ != (char)OPND(s))
- return(NULL);
+ if (sp == stop || *sp++ != (char) OPND(s))
+ return (NULL);
break;
case OANY:
if (sp == stop)
- return(NULL);
+ return (NULL);
sp++;
break;
case OANYOF:
cs = &m->g->sets[OPND(s)];
if (sp == stop || !CHIN(cs, *sp++))
- return(NULL);
+ return (NULL);
break;
case OBOL:
- if ( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
- (sp < m->endp && *(sp-1) == '\n' &&
- (m->g->cflags&REG_NEWLINE)) )
- { /* yes */ }
+ if ((sp == m->beginp && !(m->eflags & REG_NOTBOL)) ||
+ (sp < m->endp && *(sp - 1) == '\n' &&
+ (m->g->cflags & REG_NEWLINE)))
+ { /* yes */
+ }
else
- return(NULL);
+ return (NULL);
break;
case OEOL:
- if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
- (sp < m->endp && *sp == '\n' &&
- (m->g->cflags&REG_NEWLINE)) )
- { /* yes */ }
+ if ((sp == m->endp && !(m->eflags & REG_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags & REG_NEWLINE)))
+ { /* yes */
+ }
else
- return(NULL);
+ return (NULL);
break;
case OBOW:
- if (( (sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
- (sp < m->endp && *(sp-1) == '\n' &&
- (m->g->cflags&REG_NEWLINE)) ||
- (sp > m->beginp &&
- !ISWORD(*(sp-1))) ) &&
- (sp < m->endp && ISWORD(*sp)) )
- { /* yes */ }
+ if (((sp == m->beginp && !(m->eflags & REG_NOTBOL)) ||
+ (sp < m->endp && *(sp - 1) == '\n' &&
+ (m->g->cflags & REG_NEWLINE)) ||
+ (sp > m->beginp &&
+ !ISWORD(*(sp - 1)))) &&
+ (sp < m->endp && ISWORD(*sp)))
+ { /* yes */
+ }
else
- return(NULL);
+ return (NULL);
break;
case OEOW:
- if (( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
- (sp < m->endp && *sp == '\n' &&
- (m->g->cflags&REG_NEWLINE)) ||
- (sp < m->endp && !ISWORD(*sp)) ) &&
- (sp > m->beginp && ISWORD(*(sp-1))) )
- { /* yes */ }
+ if (((sp == m->endp && !(m->eflags & REG_NOTEOL)) ||
+ (sp < m->endp && *sp == '\n' &&
+ (m->g->cflags & REG_NEWLINE)) ||
+ (sp < m->endp && !ISWORD(*sp))) &&
+ (sp > m->beginp && ISWORD(*(sp - 1))))
+ { /* yes */
+ }
else
- return(NULL);
+ return (NULL);
break;
case O_QUEST:
break;
- case OOR1: /* matches null but needs to skip */
+ case OOR1: /* matches null but needs to skip */
ss++;
s = m->g->strip[ss];
- do {
+ do
+ {
assert(OP(s) == OOR2);
ss += OPND(s);
} while (OP(s = m->g->strip[ss]) != O_CH);
/* note that the ss++ gets us past the O_CH */
break;
- default: /* have to make a choice */
+ default: /* have to make a choice */
hard = 1;
break;
}
- if (!hard) { /* that was it! */
+ if (!hard)
+ { /* that was it! */
if (sp != stop)
- return(NULL);
- return(sp);
+ return (NULL);
+ return (sp);
}
- ss--; /* adjust for the for's final increment */
+ ss--; /* adjust for the for's final increment */
/* the hard stuff */
AT("hard", sp, stop, ss, stopst);
s = m->g->strip[ss];
- switch (OP(s)) {
- case OBACK_: /* the vilest depths */
+ switch (OP(s))
+ {
+ case OBACK_: /* the vilest depths */
i = OPND(s);
assert(0 < i && i <= m->g->nsub);
if (m->pmatch[i].rm_eo == -1)
- return(NULL);
+ return (NULL);
assert(m->pmatch[i].rm_so != -1);
len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
assert(stop - m->beginp >= len);
if (sp > stop - len)
- return(NULL); /* not enough left to match */
+ return (NULL); /* not enough left to match */
ssp = m->offp + m->pmatch[i].rm_so;
if (memcmp(sp, ssp, len) != 0)
- return(NULL);
+ return (NULL);
while (m->g->strip[ss] != SOP(O_BACK, i))
ss++;
- return(backref(m, sp+len, stop, ss+1, stopst, lev));
+ return (backref(m, sp + len, stop, ss + 1, stopst, lev));
break;
- case OQUEST_: /* to null or not */
- dp = backref(m, sp, stop, ss+1, stopst, lev);
+ case OQUEST_: /* to null or not */
+ dp = backref(m, sp, stop, ss + 1, stopst, lev);
if (dp != NULL)
- return(dp); /* not */
- return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev));
+ return (dp); /* not */
+ return (backref(m, sp, stop, ss + OPND(s) + 1, stopst, lev));
break;
case OPLUS_:
assert(m->lastpos != NULL);
- assert(lev+1 <= m->g->nplus);
- m->lastpos[lev+1] = sp;
- return(backref(m, sp, stop, ss+1, stopst, lev+1));
+ assert(lev + 1 <= m->g->nplus);
+ m->lastpos[lev + 1] = sp;
+ return (backref(m, sp, stop, ss + 1, stopst, lev + 1));
break;
case O_PLUS:
- if (sp == m->lastpos[lev]) /* last pass matched null */
- return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ if (sp == m->lastpos[lev]) /* last pass matched null */
+ return (backref(m, sp, stop, ss + 1, stopst, lev - 1));
/* try another pass */
m->lastpos[lev] = sp;
- dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev);
+ dp = backref(m, sp, stop, ss - OPND(s) + 1, stopst, lev);
if (dp == NULL)
- return(backref(m, sp, stop, ss+1, stopst, lev-1));
+ return (backref(m, sp, stop, ss + 1, stopst, lev - 1));
else
- return(dp);
+ return (dp);
break;
- case OCH_: /* find the right one, if any */
+ case OCH_: /* find the right one, if any */
ssub = ss + 1;
esub = ss + OPND(s) - 1;
assert(OP(m->g->strip[esub]) == OOR1);
- for (;;) { /* find first matching branch */
+ for (;;)
+ { /* find first matching branch */
dp = backref(m, sp, stop, ssub, esub, lev);
if (dp != NULL)
- return(dp);
+ return (dp);
/* that one missed, try next one */
if (OP(m->g->strip[esub]) == O_CH)
- return(NULL); /* there is none */
+ return (NULL); /* there is none */
esub++;
assert(OP(m->g->strip[esub]) == OOR2);
ssub = esub + 1;
@@ -671,29 +712,29 @@ sopno lev; /* PLUS nesting level */
assert(OP(m->g->strip[esub]) == O_CH);
}
break;
- case OLPAREN: /* must undo assignment if rest fails */
+ case OLPAREN: /* must undo assignment if rest fails */
i = OPND(s);
assert(0 < i && i <= m->g->nsub);
offsave = m->pmatch[i].rm_so;
m->pmatch[i].rm_so = sp - m->offp;
- dp = backref(m, sp, stop, ss+1, stopst, lev);
+ dp = backref(m, sp, stop, ss + 1, stopst, lev);
if (dp != NULL)
- return(dp);
+ return (dp);
m->pmatch[i].rm_so = offsave;
- return(NULL);
+ return (NULL);
break;
- case ORPAREN: /* must undo assignment if rest fails */
+ case ORPAREN: /* must undo assignment if rest fails */
i = OPND(s);
assert(0 < i && i <= m->g->nsub);
offsave = m->pmatch[i].rm_eo;
m->pmatch[i].rm_eo = sp - m->offp;
- dp = backref(m, sp, stop, ss+1, stopst, lev);
+ dp = backref(m, sp, stop, ss + 1, stopst, lev);
if (dp != NULL)
- return(dp);
+ return (dp);
m->pmatch[i].rm_eo = offsave;
- return(NULL);
+ return (NULL);
break;
- default: /* uh oh */
+ default: /* uh oh */
assert(nope);
break;
}
@@ -707,25 +748,26 @@ sopno lev; /* PLUS nesting level */
/*
- fast - step through the string at top speed
== static char *fast(register struct match *m, char *start, \
- == char *stop, sopno startst, sopno stopst);
+ == char *stop, sopno startst, sopno stopst);
*/
-static char * /* where tentative match ended, or NULL */
+static char * /* where tentative match ended, or NULL */
fast(m, start, stop, startst, stopst)
register struct match *m;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
{
register states st = m->st;
register states fresh = m->fresh;
register states tmp = m->tmp;
- register char *p = start;
- register int c = (start == m->beginp) ? OUT : *(start-1);
- register int lastc; /* previous c */
- register int flagch;
- register int i;
- register char *coldp; /* last p after which no match was underway */
+ register char *p = start;
+ register int c = (start == m->beginp) ? OUT : *(start - 1);
+ register int lastc; /* previous c */
+ register int flagch;
+ register int i;
+ register char *coldp; /* last p after which no match was
+ * underway */
CLEAR(st);
SET1(st, startst);
@@ -733,7 +775,8 @@ sopno stopst;
ASSIGN(fresh, st);
SP("start", st, *p);
coldp = NULL;
- for (;;) {
+ for (;;)
+ {
/* next character */
lastc = c;
c = (p == m->endp) ? OUT : *p;
@@ -743,39 +786,45 @@ sopno stopst;
/* is there an EOL and/or BOL between lastc and c? */
flagch = '\0';
i = 0;
- if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
- (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+ if ((lastc == '\n' && m->g->cflags & REG_NEWLINE) ||
+ (lastc == OUT && !(m->eflags & REG_NOTBOL)))
+ {
flagch = BOL;
i = m->g->nbol;
}
- if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
- (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+ if ((c == '\n' && m->g->cflags & REG_NEWLINE) ||
+ (c == OUT && !(m->eflags & REG_NOTEOL)))
+ {
flagch = (flagch == BOL) ? BOLEOL : EOL;
i += m->g->neol;
}
- if (i != 0) {
+ if (i != 0)
+ {
for (; i > 0; i--)
st = step(m->g, startst, stopst, st, flagch, st);
SP("boleol", st, c);
}
/* how about a word boundary? */
- if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
- (c != OUT && ISWORD(c)) ) {
+ if ((flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)))
+ {
flagch = BOW;
}
- if ( (lastc != OUT && ISWORD(lastc)) &&
- (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ if ((lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))))
+ {
flagch = EOW;
}
- if (flagch == BOW || flagch == EOW) {
+ if (flagch == BOW || flagch == EOW)
+ {
st = step(m->g, startst, stopst, st, flagch, st);
SP("boweow", st, c);
}
/* are we done? */
if (ISSET(st, stopst) || p == stop)
- break; /* NOTE BREAK OUT */
+ break; /* NOTE BREAK OUT */
/* no, we must deal with this character */
ASSIGN(tmp, st);
@@ -790,33 +839,33 @@ sopno stopst;
assert(coldp != NULL);
m->coldp = coldp;
if (ISSET(st, stopst))
- return(p+1);
+ return (p + 1);
else
- return(NULL);
+ return (NULL);
}
/*
- slow - step through the string more deliberately
== static char *slow(register struct match *m, char *start, \
- == char *stop, sopno startst, sopno stopst);
+ == char *stop, sopno startst, sopno stopst);
*/
-static char * /* where it ended */
+static char * /* where it ended */
slow(m, start, stop, startst, stopst)
register struct match *m;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
{
register states st = m->st;
register states empty = m->empty;
register states tmp = m->tmp;
- register char *p = start;
- register int c = (start == m->beginp) ? OUT : *(start-1);
- register int lastc; /* previous c */
- register int flagch;
- register int i;
- register char *matchp; /* last p at which a match ended */
+ register char *p = start;
+ register int c = (start == m->beginp) ? OUT : *(start - 1);
+ register int lastc; /* previous c */
+ register int flagch;
+ register int i;
+ register char *matchp; /* last p at which a match ended */
AT("slow", start, stop, startst, stopst);
CLEAR(st);
@@ -824,7 +873,8 @@ sopno stopst;
SP("sstart", st, *p);
st = step(m->g, startst, stopst, st, NOTHING, st);
matchp = NULL;
- for (;;) {
+ for (;;)
+ {
/* next character */
lastc = c;
c = (p == m->endp) ? OUT : *p;
@@ -832,32 +882,38 @@ sopno stopst;
/* is there an EOL and/or BOL between lastc and c? */
flagch = '\0';
i = 0;
- if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
- (lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
+ if ((lastc == '\n' && m->g->cflags & REG_NEWLINE) ||
+ (lastc == OUT && !(m->eflags & REG_NOTBOL)))
+ {
flagch = BOL;
i = m->g->nbol;
}
- if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
- (c == OUT && !(m->eflags&REG_NOTEOL)) ) {
+ if ((c == '\n' && m->g->cflags & REG_NEWLINE) ||
+ (c == OUT && !(m->eflags & REG_NOTEOL)))
+ {
flagch = (flagch == BOL) ? BOLEOL : EOL;
i += m->g->neol;
}
- if (i != 0) {
+ if (i != 0)
+ {
for (; i > 0; i--)
st = step(m->g, startst, stopst, st, flagch, st);
SP("sboleol", st, c);
}
/* how about a word boundary? */
- if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
- (c != OUT && ISWORD(c)) ) {
+ if ((flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
+ (c != OUT && ISWORD(c)))
+ {
flagch = BOW;
}
- if ( (lastc != OUT && ISWORD(lastc)) &&
- (flagch == EOL || (c != OUT && !ISWORD(c))) ) {
+ if ((lastc != OUT && ISWORD(lastc)) &&
+ (flagch == EOL || (c != OUT && !ISWORD(c))))
+ {
flagch = EOW;
}
- if (flagch == BOW || flagch == EOW) {
+ if (flagch == BOW || flagch == EOW)
+ {
st = step(m->g, startst, stopst, st, flagch, st);
SP("sboweow", st, c);
}
@@ -866,7 +922,7 @@ sopno stopst;
if (ISSET(st, stopst))
matchp = p;
if (EQ(st, empty) || p == stop)
- break; /* NOTE BREAK OUT */
+ break; /* NOTE BREAK OUT */
/* no, we must deal with this character */
ASSIGN(tmp, st);
@@ -878,50 +934,52 @@ sopno stopst;
p++;
}
- return(matchp);
+ return (matchp);
}
/*
- step - map set of states reachable before char to set reachable after
== static states step(register struct re_guts *g, sopno start, sopno stop, \
- == register states bef, int ch, register states aft);
- == #define BOL (OUT+1)
- == #define EOL (BOL+1)
- == #define BOLEOL (BOL+2)
- == #define NOTHING (BOL+3)
- == #define BOW (BOL+4)
- == #define EOW (BOL+5)
- == #define CODEMAX (BOL+5) // highest code used
- == #define NONCHAR(c) ((c) > CHAR_MAX)
- == #define NNONCHAR (CODEMAX-CHAR_MAX)
+ == register states bef, int ch, register states aft);
+ == #define BOL (OUT+1)
+ == #define EOL (BOL+1)
+ == #define BOLEOL (BOL+2)
+ == #define NOTHING (BOL+3)
+ == #define BOW (BOL+4)
+ == #define EOW (BOL+5)
+ == #define CODEMAX (BOL+5) // highest code used
+ == #define NONCHAR(c) ((c) > CHAR_MAX)
+ == #define NNONCHAR (CODEMAX-CHAR_MAX)
*/
-static states
+static states
step(g, start, stop, bef, ch, aft)
register struct re_guts *g;
-sopno start; /* start state within strip */
-sopno stop; /* state after stop state within strip */
-register states bef; /* states reachable before */
-int ch; /* character or NONCHAR code */
-register states aft; /* states already known reachable after */
+sopno start; /* start state within strip */
+sopno stop; /* state after stop state within strip */
+register states bef; /* states reachable before */
+int ch; /* character or NONCHAR code */
+register states aft; /* states already known reachable after */
{
- register cset *cs;
- register sop s;
- register sopno pc;
+ register cset *cs;
+ register sop s;
+ register sopno pc;
register onestate here; /* note, macros know this name */
- register sopno look;
- register int i;
+ register sopno look;
+ register int i;
- for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
+ for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here))
+ {
s = g->strip[pc];
- switch (OP(s)) {
+ switch (OP(s))
+ {
case OEND:
- assert(pc == stop-1);
+ assert(pc == stop - 1);
break;
case OCHAR:
/* only characters can match */
- assert(!NONCHAR(ch) || ch != (char)OPND(s));
- if (ch == (char)OPND(s))
+ assert(!NONCHAR(ch) || ch != (char) OPND(s));
+ if (ch == (char) OPND(s))
FWD(aft, bef, 1);
break;
case OBOL:
@@ -949,65 +1007,68 @@ register states aft; /* states already known reachable after */
if (!NONCHAR(ch) && CHIN(cs, ch))
FWD(aft, bef, 1);
break;
- case OBACK_: /* ignored here */
+ case OBACK_: /* ignored here */
case O_BACK:
FWD(aft, aft, 1);
break;
- case OPLUS_: /* forward, this is just an empty */
+ case OPLUS_: /* forward, this is just an empty */
FWD(aft, aft, 1);
break;
- case O_PLUS: /* both forward and back */
+ case O_PLUS: /* both forward and back */
FWD(aft, aft, 1);
i = ISSETBACK(aft, OPND(s));
BACK(aft, aft, OPND(s));
- if (!i && ISSETBACK(aft, OPND(s))) {
+ if (!i && ISSETBACK(aft, OPND(s)))
+ {
/* oho, must reconsider loop body */
pc -= OPND(s) + 1;
INIT(here, pc);
}
break;
- case OQUEST_: /* two branches, both forward */
+ case OQUEST_: /* two branches, both forward */
FWD(aft, aft, 1);
FWD(aft, aft, OPND(s));
break;
- case O_QUEST: /* just an empty */
+ case O_QUEST: /* just an empty */
FWD(aft, aft, 1);
break;
- case OLPAREN: /* not significant here */
+ case OLPAREN: /* not significant here */
case ORPAREN:
FWD(aft, aft, 1);
break;
- case OCH_: /* mark the first two branches */
+ case OCH_: /* mark the first two branches */
FWD(aft, aft, 1);
- assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ assert(OP(g->strip[pc + OPND(s)]) == OOR2);
FWD(aft, aft, OPND(s));
break;
- case OOR1: /* done a branch, find the O_CH */
- if (ISSTATEIN(aft, here)) {
+ case OOR1: /* done a branch, find the O_CH */
+ if (ISSTATEIN(aft, here))
+ {
for (look = 1;
- OP(s = g->strip[pc+look]) != O_CH;
- look += OPND(s))
+ OP(s = g->strip[pc + look]) != O_CH;
+ look += OPND(s))
assert(OP(s) == OOR2);
FWD(aft, aft, look);
}
break;
- case OOR2: /* propagate OCH_'s marking */
+ case OOR2: /* propagate OCH_'s marking */
FWD(aft, aft, 1);
- if (OP(g->strip[pc+OPND(s)]) != O_CH) {
- assert(OP(g->strip[pc+OPND(s)]) == OOR2);
+ if (OP(g->strip[pc + OPND(s)]) != O_CH)
+ {
+ assert(OP(g->strip[pc + OPND(s)]) == OOR2);
FWD(aft, aft, OPND(s));
}
break;
- case O_CH: /* just empty */
+ case O_CH: /* just empty */
FWD(aft, aft, 1);
break;
- default: /* ooooops... */
+ default: /* ooooops... */
assert(nope);
break;
}
}
- return(aft);
+ return (aft);
}
#ifdef REDEBUG
@@ -1015,84 +1076,86 @@ register states aft; /* states already known reachable after */
- print - print a set of states
== #ifdef REDEBUG
== static void print(struct match *m, char *caption, states st, \
- == int ch, FILE *d);
+ == int ch, FILE *d);
== #endif
*/
static void
print(m, caption, st, ch, d)
-struct match *m;
-char *caption;
-states st;
-int ch;
-FILE *d;
+struct match *m;
+char *caption;
+states st;
+int ch;
+FILE *d;
{
register struct re_guts *g = m->g;
- register int i;
- register int first = 1;
+ register int i;
+ register int first = 1;
- if (!(m->eflags&REG_TRACE))
+ if (!(m->eflags & REG_TRACE))
return;
fprintf(d, "%s", caption);
if (ch != '\0')
fprintf(d, " %s", pchar(ch));
for (i = 0; i < g->nstates; i++)
- if (ISSET(st, i)) {
+ if (ISSET(st, i))
+ {
fprintf(d, "%s%d", (first) ? "\t" : ", ", i);
first = 0;
}
fprintf(d, "\n");
}
-/*
+/*
- at - print current situation
== #ifdef REDEBUG
== static void at(struct match *m, char *title, char *start, char *stop, \
- == sopno startst, sopno stopst);
+ == sopno startst, sopno stopst);
== #endif
*/
static void
at(m, title, start, stop, startst, stopst)
-struct match *m;
-char *title;
-char *start;
-char *stop;
-sopno startst;
-sopno stopst;
+struct match *m;
+char *title;
+char *start;
+char *stop;
+sopno startst;
+sopno stopst;
{
- if (!(m->eflags&REG_TRACE))
+ if (!(m->eflags & REG_TRACE))
return;
printf("%s %s-", title, pchar(*start));
printf("%s ", pchar(*stop));
- printf("%ld-%ld\n", (long)startst, (long)stopst);
+ printf("%ld-%ld\n", (long) startst, (long) stopst);
}
#ifndef PCHARDONE
-#define PCHARDONE /* never again */
+#define PCHARDONE /* never again */
/*
- pchar - make a character printable
== #ifdef REDEBUG
== static char *pchar(int ch);
== #endif
*
- * Is this identical to regchar() over in debug.c? Well, yes. But a
+ * Is this identical to regchar() over in debug.c? Well, yes. But a
* duplicate here avoids having a debugging-capable regexec.o tied to
- * a matching debug.o, and this is convenient. It all disappears in
+ * a matching debug.o, and this is convenient. It all disappears in
* the non-debug compilation anyway, so it doesn't matter much.
*/
-static char * /* -> representation */
+static char * /* -> representation */
pchar(ch)
-int ch;
+int ch;
{
- static char pbuf[10];
+ static char pbuf[10];
if (isprint(ch) || ch == ' ')
sprintf(pbuf, "%c", ch);
else
sprintf(pbuf, "\\%o", ch);
- return(pbuf);
+ return (pbuf);
}
+
#endif
#endif
diff --git a/src/backend/regex/regcomp.c b/src/backend/regex/regcomp.c
index 364573e2b5b..dcb95173c06 100644
--- a/src/backend/regex/regcomp.c
+++ b/src/backend/regex/regcomp.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
@@ -10,22 +10,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)
@@ -34,12 +34,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)regcomp.c 8.5 (Berkeley) 3/20/94
+ * @(#)regcomp.c 8.5 (Berkeley) 3/20/94
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)regcomp.c 8.5 (Berkeley) 3/20/94";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)regcomp.c 8.5 (Berkeley) 3/20/94";
+
+#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <stdio.h>
@@ -49,7 +50,7 @@ static char sccsid[] = "@(#)regcomp.c 8.5 (Berkeley) 3/20/94";
#include <stdlib.h>
#include <assert.h>
-#include <regex/regex.h>
+#include <regex/regex.h>
#include <regex/utils.h>
#include <regex/regex2.h>
#include <regex/cclass.h>
@@ -59,167 +60,179 @@ static char sccsid[] = "@(#)regcomp.c 8.5 (Berkeley) 3/20/94";
* parse structure, passed up and down to avoid global variables and
* other clumsinesses
*/
-struct parse {
- char *next; /* next character in RE */
- char *end; /* end of string (-> NUL normally) */
- int error; /* has an error been seen? */
- sop *strip; /* malloced strip */
- sopno ssize; /* malloced strip size (allocated) */
- sopno slen; /* malloced strip length (used) */
- int ncsalloc; /* number of csets allocated */
+struct parse
+{
+ char *next; /* next character in RE */
+ char *end; /* end of string (-> NUL normally) */
+ int error; /* has an error been seen? */
+ sop *strip; /* malloced strip */
+ sopno ssize; /* malloced strip size (allocated) */
+ sopno slen; /* malloced strip length (used) */
+ int ncsalloc; /* number of csets allocated */
struct re_guts *g;
-# define NPAREN 10 /* we need to remember () 1-9 for back refs */
- sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
- sopno pend[NPAREN]; /* -> ) ([0] unused) */
+#define NPAREN 10 /* we need to remember () 1-9 for back
+ * refs */
+ sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
+ sopno pend[NPAREN]; /* -> ) ([0] unused) */
};
/* ========= begin header generated by ./mkh ========= */
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
/* === regcomp.c === */
-static void p_ere(struct parse *p, int stop);
-static void p_ere_exp(struct parse *p);
-static void p_str(struct parse *p);
-static void p_bre(struct parse *p, int end1, int end2);
-static int p_simp_re(struct parse *p, int starordinary);
-static int p_count(struct parse *p);
-static void p_bracket(struct parse *p);
-static void p_b_term(struct parse *p, cset *cs);
-static void p_b_cclass(struct parse *p, cset *cs);
-static void p_b_eclass(struct parse *p, cset *cs);
-static char p_b_symbol(struct parse *p);
-static char p_b_coll_elem(struct parse *p, int endc);
-static char othercase(int ch);
-static void bothcases(struct parse *p, int ch);
-static void ordinary(struct parse *p, int ch);
-static void nonnewline(struct parse *p);
-static void repeat(struct parse *p, sopno start, int from, int to);
-static int seterr(struct parse *p, int e);
-static cset *allocset(struct parse *p);
-static void freeset(struct parse *p, cset *cs);
-static int freezeset(struct parse *p, cset *cs);
-static int firstch(struct parse *p, cset *cs);
-static int nch(struct parse *p, cset *cs);
-static void mcadd(struct parse *p, cset *cs, char *cp);
-static void mcinvert(struct parse *p, cset *cs);
-static void mccase(struct parse *p, cset *cs);
-static int isinsets(struct re_guts *g, int c);
-static int samesets(struct re_guts *g, int c1, int c2);
-static void categorize(struct parse *p, struct re_guts *g);
-static sopno dupl(struct parse *p, sopno start, sopno finish);
-static void doemit(struct parse *p, sop op, size_t opnd);
-static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos);
-static void dofwd(struct parse *p, sopno pos, sop value);
-static void enlarge(struct parse *p, sopno size);
-static void stripsnug(struct parse *p, struct re_guts *g);
-static void findmust(struct parse *p, struct re_guts *g);
-static sopno pluscount(struct parse *p, struct re_guts *g);
+ static void p_ere(struct parse * p, int stop);
+ static void p_ere_exp(struct parse * p);
+ static void p_str(struct parse * p);
+ static void p_bre(struct parse * p, int end1, int end2);
+ static int p_simp_re(struct parse * p, int starordinary);
+ static int p_count(struct parse * p);
+ static void p_bracket(struct parse * p);
+ static void p_b_term(struct parse * p, cset * cs);
+ static void p_b_cclass(struct parse * p, cset * cs);
+ static void p_b_eclass(struct parse * p, cset * cs);
+ static char p_b_symbol(struct parse * p);
+ static char p_b_coll_elem(struct parse * p, int endc);
+ static char othercase(int ch);
+ static void bothcases(struct parse * p, int ch);
+ static void ordinary(struct parse * p, int ch);
+ static void nonnewline(struct parse * p);
+ static void repeat(struct parse * p, sopno start, int from, int to);
+ static int seterr(struct parse * p, int e);
+ static cset *allocset(struct parse * p);
+ static void freeset(struct parse * p, cset * cs);
+ static int freezeset(struct parse * p, cset * cs);
+ static int firstch(struct parse * p, cset * cs);
+ static int nch(struct parse * p, cset * cs);
+ static void mcadd(struct parse * p, cset * cs, char *cp);
+ static void mcinvert(struct parse * p, cset * cs);
+ static void mccase(struct parse * p, cset * cs);
+ static int isinsets(struct re_guts * g, int c);
+ static int samesets(struct re_guts * g, int c1, int c2);
+ static void categorize(struct parse * p, struct re_guts * g);
+ static sopno dupl(struct parse * p, sopno start, sopno finish);
+ static void doemit(struct parse * p, sop op, size_t opnd);
+ static void doinsert(struct parse * p, sop op, size_t opnd, sopno pos);
+ static void dofwd(struct parse * p, sopno pos, sop value);
+ static void enlarge(struct parse * p, sopno size);
+ static void stripsnug(struct parse * p, struct re_guts * g);
+ static void findmust(struct parse * p, struct re_guts * g);
+ static sopno pluscount(struct parse * p, struct re_guts * g);
#ifdef __cplusplus
}
+
#endif
/* ========= end header generated by ./mkh ========= */
-static char nuls[10]; /* place to point scanner in event of error */
+static char nuls[10]; /* place to point scanner in event of
+ * error */
/*
* macros for use with parse structure
- * BEWARE: these know that the parse structure is named `p' !!!
+ * BEWARE: these know that the parse structure is named `p' !!!
*/
-#define PEEK() (*p->next)
-#define PEEK2() (*(p->next+1))
-#define MORE() (p->next < p->end)
-#define MORE2() (p->next+1 < p->end)
-#define SEE(c) (MORE() && PEEK() == (c))
-#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
-#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
-#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
-#define NEXT() (p->next++)
-#define NEXT2() (p->next += 2)
-#define NEXTn(n) (p->next += (n))
-#define GETNEXT() (*p->next++)
-#define SETERROR(e) seterr(p, (e))
-#define REQUIRE(co, e) if (!(co)) SETERROR(e)
-#define MUSTSEE(c, e) REQUIRE(MORE() && PEEK() == (c), e)
-#define MUSTEAT(c, e) REQUIRE(MORE() && GETNEXT() == (c), e)
-#define MUSTNOTSEE(c, e) REQUIRE(!MORE() || PEEK() != (c), e)
-#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
-#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
-#define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
-#define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
-#define HERE() (p->slen)
-#define THERE() (p->slen - 1)
-#define THERETHERE() (p->slen - 2)
-#define DROP(n) (p->slen -= (n))
+#define PEEK() (*p->next)
+#define PEEK2() (*(p->next+1))
+#define MORE() (p->next < p->end)
+#define MORE2() (p->next+1 < p->end)
+#define SEE(c) (MORE() && PEEK() == (c))
+#define SEETWO(a, b) (MORE() && MORE2() && PEEK() == (a) && PEEK2() == (b))
+#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
+#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
+#define NEXT() (p->next++)
+#define NEXT2() (p->next += 2)
+#define NEXTn(n) (p->next += (n))
+#define GETNEXT() (*p->next++)
+#define SETERROR(e) seterr(p, (e))
+#define REQUIRE(co, e) if (!(co)) SETERROR(e)
+#define MUSTSEE(c, e) REQUIRE(MORE() && PEEK() == (c), e)
+#define MUSTEAT(c, e) REQUIRE(MORE() && GETNEXT() == (c), e)
+#define MUSTNOTSEE(c, e) REQUIRE(!MORE() || PEEK() != (c), e)
+#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
+#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
+#define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
+#define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
+#define HERE() (p->slen)
+#define THERE() (p->slen - 1)
+#define THERETHERE() (p->slen - 2)
+#define DROP(n) (p->slen -= (n))
#ifndef NDEBUG
-static int never = 0; /* for use in asserts; shuts lint up */
+static int never = 0; /* for use in asserts; shuts lint up */
+
#else
-#define never 0 /* some <assert.h>s have bugs too */
+#define never 0 /* some <assert.h>s have bugs too */
#endif
/*
- regcomp - interface for parser and compilation
= extern int regcomp(regex_t *, const char *, int);
- = #define REG_BASIC 0000
- = #define REG_EXTENDED 0001
- = #define REG_ICASE 0002
- = #define REG_NOSUB 0004
- = #define REG_NEWLINE 0010
- = #define REG_NOSPEC 0020
- = #define REG_PEND 0040
- = #define REG_DUMP 0200
+ = #define REG_BASIC 0000
+ = #define REG_EXTENDED 0001
+ = #define REG_ICASE 0002
+ = #define REG_NOSUB 0004
+ = #define REG_NEWLINE 0010
+ = #define REG_NOSPEC 0020
+ = #define REG_PEND 0040
+ = #define REG_DUMP 0200
*/
-int /* 0 success, otherwise REG_something */
+int /* 0 success, otherwise REG_something */
pg95_regcomp(preg, pattern, cflags)
-regex_t *preg;
-const char *pattern;
-int cflags;
+regex_t *preg;
+const char *pattern;
+int cflags;
{
- struct parse pa;
+ struct parse pa;
register struct re_guts *g;
register struct parse *p = &pa;
- register int i;
+ register int i;
register size_t len;
+
#ifdef REDEBUG
-# define GOODFLAGS(f) (f)
+#define GOODFLAGS(f) (f)
#else
-# define GOODFLAGS(f) ((f)&~REG_DUMP)
+#define GOODFLAGS(f) ((f)&~REG_DUMP)
#endif
cflags = GOODFLAGS(cflags);
- if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
- return(REG_INVARG);
+ if ((cflags & REG_EXTENDED) && (cflags & REG_NOSPEC))
+ return (REG_INVARG);
- if (cflags&REG_PEND) {
+ if (cflags & REG_PEND)
+ {
if (preg->re_endp < pattern)
- return(REG_INVARG);
+ return (REG_INVARG);
len = preg->re_endp - pattern;
- } else
- len = strlen((char *)pattern);
+ }
+ else
+ len = strlen((char *) pattern);
/* do the mallocs early so failure handling is easy */
- g = (struct re_guts *)malloc(sizeof(struct re_guts) +
- (NC-1)*sizeof(cat_t));
+ g = (struct re_guts *) malloc(sizeof(struct re_guts) +
+ (NC - 1) * sizeof(cat_t));
if (g == NULL)
- return(REG_ESPACE);
- p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
- p->strip = (sop *)malloc(p->ssize * sizeof(sop));
+ return (REG_ESPACE);
+ p->ssize = len / (size_t) 2 *(size_t) 3 + (size_t) 1; /* ugh */
+
+ p->strip = (sop *) malloc(p->ssize * sizeof(sop));
p->slen = 0;
- if (p->strip == NULL) {
- free((char *)g);
- return(REG_ESPACE);
+ if (p->strip == NULL)
+ {
+ free((char *) g);
+ return (REG_ESPACE);
}
/* set things up */
p->g = g;
- p->next = (char *)pattern; /* convenience; we do not modify it */
+ p->next = (char *) pattern; /* convenience; we do not modify it */
p->end = p->next + len;
p->error = 0;
p->ncsalloc = 0;
- for (i = 0; i < NPAREN; i++) {
+ for (i = 0; i < NPAREN; i++)
+ {
p->pbegin[i] = 0;
p->pend[i] = 0;
}
@@ -234,17 +247,17 @@ int cflags;
g->must = NULL;
g->mlen = 0;
g->nsub = 0;
- g->ncategories = 1; /* category 0 is "everything else" */
+ g->ncategories = 1; /* category 0 is "everything else" */
g->categories = &g->catspace[-(CHAR_MIN)];
- memset((char *)g->catspace, 0, NC*sizeof(cat_t));
+ memset((char *) g->catspace, 0, NC * sizeof(cat_t));
g->backrefs = 0;
/* do it */
EMIT(OEND, 0);
g->firststate = THERE();
- if (cflags&REG_EXTENDED)
+ if (cflags & REG_EXTENDED)
p_ere(p, OUT);
- else if (cflags&REG_NOSPEC)
+ else if (cflags & REG_NOSPEC)
p_str(p);
else
p_bre(p, OUT, OUT);
@@ -262,14 +275,14 @@ int cflags;
preg->re_magic = MAGIC1;
#ifndef REDEBUG
/* not debugging, so can't rely on the assert() in regexec() */
- if (g->iflags&BAD)
+ if (g->iflags & BAD)
SETERROR(REG_ASSERT);
#endif
/* win or lose, we're done */
- if (p->error != 0) /* lose */
+ if (p->error != 0) /* lose */
pg95_regfree(preg);
- return(p->error);
+ return (p->error);
}
/*
@@ -279,26 +292,28 @@ int cflags;
static void
p_ere(p, stop)
register struct parse *p;
-int stop; /* character this ERE should end at */
+int stop; /* character this ERE should end at */
{
- register char c;
- register sopno prevback = 0;
- register sopno prevfwd = 0;
- register sopno conc;
- register int first = 1; /* is this the first alternative? */
-
- for (;;) {
+ register char c;
+ register sopno prevback = 0;
+ register sopno prevfwd = 0;
+ register sopno conc;
+ register int first = 1; /* is this the first alternative? */
+
+ for (;;)
+ {
/* do a bunch of concatenated expressions */
conc = HERE();
while (MORE() && (c = PEEK()) != '|' && c != stop)
p_ere_exp(p);
- REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */
+ REQUIRE(HERE() != conc, REG_EMPTY); /* require nonempty */
if (!EAT('|'))
- break; /* NOTE BREAK OUT */
+ break; /* NOTE BREAK OUT */
- if (first) {
- INSERT(OCH_, conc); /* offset is wrong */
+ if (first)
+ {
+ INSERT(OCH_, conc); /* offset is wrong */
prevfwd = conc;
prevback = conc;
first = 0;
@@ -310,7 +325,8 @@ int stop; /* character this ERE should end at */
EMIT(OOR2, 0); /* offset is very wrong */
}
- if (!first) { /* tail-end fixups */
+ if (!first)
+ { /* tail-end fixups */
AHEAD(prevfwd);
ASTERN(O_CH, prevback);
}
@@ -326,18 +342,19 @@ static void
p_ere_exp(p)
register struct parse *p;
{
- register char c;
- register sopno pos;
- register int count;
- register int count2;
- register sopno subno;
- int wascaret = 0;
-
- assert(MORE()); /* caller should have ensured this */
+ register char c;
+ register sopno pos;
+ register int count;
+ register int count2;
+ register sopno subno;
+ int wascaret = 0;
+
+ assert(MORE()); /* caller should have ensured this */
c = GETNEXT();
pos = HERE();
- switch (c) {
+ switch (c)
+ {
case '(':
REQUIRE(MORE(), REG_EPAREN);
p->g->nsub++;
@@ -347,7 +364,8 @@ register struct parse *p;
EMIT(OLPAREN, subno);
if (!SEE(')'))
p_ere(p, ')');
- if (subno < NPAREN) {
+ if (subno < NPAREN)
+ {
p->pend[subno] = HERE();
assert(p->pend[subno] != 0);
}
@@ -355,13 +373,13 @@ register struct parse *p;
MUSTEAT(')', REG_EPAREN);
break;
#ifndef POSIX_MISTAKE
- case ')': /* happens only if no current unmatched ( */
+ case ')': /* happens only if no current unmatched ( */
+
/*
- * You may ask, why the ifndef? Because I didn't notice
- * this until slightly too late for 1003.2, and none of the
- * other 1003.2 regular-expression reviewers noticed it at
- * all. So an unmatched ) is legal POSIX, at least until
- * we can get it fixed.
+ * You may ask, why the ifndef? Because I didn't notice this
+ * until slightly too late for 1003.2, and none of the other
+ * 1003.2 regular-expression reviewers noticed it at all. So an
+ * unmatched ) is legal POSIX, at least until we can get it fixed.
*/
SETERROR(REG_EPAREN);
break;
@@ -386,7 +404,7 @@ register struct parse *p;
SETERROR(REG_BADRPT);
break;
case '.':
- if (p->g->cflags&REG_NEWLINE)
+ if (p->g->cflags & REG_NEWLINE)
nonnewline(p);
else
EMIT(OANY, 0);
@@ -399,7 +417,8 @@ register struct parse *p;
c = GETNEXT();
ordinary(p, c);
break;
- case '{': /* okay as ordinary except if digit follows */
+ case '{': /* okay as ordinary except if digit
+ * follows */
REQUIRE(!MORE() || !isdigit(PEEK()), REG_BADRPT);
/* FALLTHROUGH */
default:
@@ -411,14 +430,15 @@ register struct parse *p;
return;
c = PEEK();
/* we call { a repetition if followed by a digit */
- if (!( c == '*' || c == '+' || c == '?' ||
- (c == '{' && MORE2() && isdigit(PEEK2())) ))
- return; /* no repetition, we're done */
+ if (!(c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit(PEEK2()))))
+ return; /* no repetition, we're done */
NEXT();
REQUIRE(!wascaret, REG_BADRPT);
- switch (c) {
- case '*': /* implemented as +? */
+ switch (c)
+ {
+ case '*': /* implemented as +? */
/* this case does not require the (y|) trick, noKLUDGE */
INSERT(OPLUS_, pos);
ASTERN(O_PLUS, pos);
@@ -433,23 +453,30 @@ register struct parse *p;
/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
INSERT(OCH_, pos); /* offset slightly wrong */
ASTERN(OOR1, pos); /* this one's right */
- AHEAD(pos); /* fix the OCH_ */
+ AHEAD(pos); /* fix the OCH_ */
EMIT(OOR2, 0); /* offset very wrong... */
AHEAD(THERE()); /* ...so fix it */
ASTERN(O_CH, THERETHERE());
break;
case '{':
count = p_count(p);
- if (EAT(',')) {
- if (isdigit(PEEK())) {
+ if (EAT(','))
+ {
+ if (isdigit(PEEK()))
+ {
count2 = p_count(p);
REQUIRE(count <= count2, REG_BADBR);
- } else /* single number with comma */
+ }
+ else
+/* single number with comma */
count2 = INFINITY;
- } else /* just a single number */
+ }
+ else
+/* just a single number */
count2 = count;
repeat(p, pos, count, count2);
- if (!EAT('}')) { /* error heuristics */
+ if (!EAT('}'))
+ { /* error heuristics */
while (MORE() && PEEK() != '}')
NEXT();
REQUIRE(MORE(), REG_EBRACE);
@@ -461,8 +488,8 @@ register struct parse *p;
if (!MORE())
return;
c = PEEK();
- if (!( c == '*' || c == '+' || c == '?' ||
- (c == '{' && MORE2() && isdigit(PEEK2())) ) )
+ if (!(c == '*' || c == '+' || c == '?' ||
+ (c == '{' && MORE2() && isdigit(PEEK2()))))
return;
SETERROR(REG_BADRPT);
}
@@ -483,72 +510,78 @@ register struct parse *p;
/*
- p_bre - BRE parser top level, anchoring and concatenation
== static void p_bre(register struct parse *p, register int end1, \
- == register int end2);
+ == register int end2);
* Giving end1 as OUT essentially eliminates the end1/end2 check.
*
* This implementation is a bit of a kludge, in that a trailing $ is first
* taken as an ordinary character and then revised to be an anchor. The
* only undesirable side effect is that '$' gets included as a character
- * category in such cases. This is fairly harmless; not worth fixing.
+ * category in such cases. This is fairly harmless; not worth fixing.
* The amount of lookahead needed to avoid this kludge is excessive.
*/
static void
p_bre(p, end1, end2)
register struct parse *p;
-register int end1; /* first terminating character */
-register int end2; /* second terminating character */
+register int end1; /* first terminating character */
+register int end2; /* second terminating character */
{
- register sopno start = HERE();
- register int first = 1; /* first subexpression? */
- register int wasdollar = 0;
+ register sopno start = HERE();
+ register int first = 1; /* first subexpression? */
+ register int wasdollar = 0;
- if (EAT('^')) {
+ if (EAT('^'))
+ {
EMIT(OBOL, 0);
p->g->iflags |= USEBOL;
p->g->nbol++;
}
- while (MORE() && !SEETWO(end1, end2)) {
+ while (MORE() && !SEETWO(end1, end2))
+ {
wasdollar = p_simp_re(p, first);
first = 0;
}
- if (wasdollar) { /* oops, that was a trailing anchor */
+ if (wasdollar)
+ { /* oops, that was a trailing anchor */
DROP(1);
EMIT(OEOL, 0);
p->g->iflags |= USEEOL;
p->g->neol++;
}
- REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */
+ REQUIRE(HERE() != start, REG_EMPTY); /* require nonempty */
}
/*
- p_simp_re - parse a simple RE, an atom possibly followed by a repetition
== static int p_simp_re(register struct parse *p, int starordinary);
*/
-static int /* was the simple RE an unbackslashed $? */
+static int /* was the simple RE an unbackslashed $? */
p_simp_re(p, starordinary)
register struct parse *p;
-int starordinary; /* is a leading * an ordinary character? */
+int starordinary; /* is a leading * an ordinary character? */
{
- register int c;
- register int count;
- register int count2;
- register sopno pos;
- register int i;
- register sopno subno;
-# define BACKSL (1<<CHAR_BIT)
+ register int c;
+ register int count;
+ register int count2;
+ register sopno pos;
+ register int i;
+ register sopno subno;
- pos = HERE(); /* repetion op, if any, covers from here */
+#define BACKSL (1<<CHAR_BIT)
- assert(MORE()); /* caller should have ensured this */
+ pos = HERE(); /* repetion op, if any, covers from here */
+
+ assert(MORE()); /* caller should have ensured this */
c = GETNEXT();
- if (c == '\\') {
+ if (c == '\\')
+ {
REQUIRE(MORE(), REG_EESCAPE);
- c = BACKSL | (unsigned char)GETNEXT();
+ c = BACKSL | (unsigned char) GETNEXT();
}
- switch (c) {
+ switch (c)
+ {
case '.':
- if (p->g->cflags&REG_NEWLINE)
+ if (p->g->cflags & REG_NEWLINE)
nonnewline(p);
else
EMIT(OANY, 0);
@@ -556,10 +589,10 @@ int starordinary; /* is a leading * an ordinary character? */
case '[':
p_bracket(p);
break;
- case BACKSL|'{':
+ case BACKSL | '{':
SETERROR(REG_BADRPT);
break;
- case BACKSL|'(':
+ case BACKSL | '(':
p->g->nsub++;
subno = p->g->nsub;
if (subno < NPAREN)
@@ -568,37 +601,40 @@ int starordinary; /* is a leading * an ordinary character? */
/* the MORE here is an error heuristic */
if (MORE() && !SEETWO('\\', ')'))
p_bre(p, '\\', ')');
- if (subno < NPAREN) {
+ if (subno < NPAREN)
+ {
p->pend[subno] = HERE();
assert(p->pend[subno] != 0);
}
EMIT(ORPAREN, subno);
REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
break;
- case BACKSL|')': /* should not get here -- must be user */
- case BACKSL|'}':
+ case BACKSL | ')': /* should not get here -- must be user */
+ case BACKSL | '}':
SETERROR(REG_EPAREN);
break;
- case BACKSL|'1':
- case BACKSL|'2':
- case BACKSL|'3':
- case BACKSL|'4':
- case BACKSL|'5':
- case BACKSL|'6':
- case BACKSL|'7':
- case BACKSL|'8':
- case BACKSL|'9':
- i = (c&~BACKSL) - '0';
+ case BACKSL | '1':
+ case BACKSL | '2':
+ case BACKSL | '3':
+ case BACKSL | '4':
+ case BACKSL | '5':
+ case BACKSL | '6':
+ case BACKSL | '7':
+ case BACKSL | '8':
+ case BACKSL | '9':
+ i = (c & ~BACKSL) - '0';
assert(i < NPAREN);
- if (p->pend[i] != 0) {
+ if (p->pend[i] != 0)
+ {
assert(i <= p->g->nsub);
EMIT(OBACK_, i);
assert(p->pbegin[i] != 0);
assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
assert(OP(p->strip[p->pend[i]]) == ORPAREN);
- dupl(p, p->pbegin[i]+1, p->pend[i]);
+ dupl(p, p->pbegin[i] + 1, p->pend[i]);
EMIT(O_BACK, i);
- } else
+ }
+ else
SETERROR(REG_ESUBREG);
p->g->backrefs = 1;
break;
@@ -606,57 +642,69 @@ int starordinary; /* is a leading * an ordinary character? */
REQUIRE(starordinary, REG_BADRPT);
/* FALLTHROUGH */
default:
- ordinary(p, c &~ BACKSL);
+ ordinary(p, c & ~BACKSL);
break;
}
- if (EAT('*')) { /* implemented as +? */
+ if (EAT('*'))
+ { /* implemented as +? */
/* this case does not require the (y|) trick, noKLUDGE */
INSERT(OPLUS_, pos);
ASTERN(O_PLUS, pos);
INSERT(OQUEST_, pos);
ASTERN(O_QUEST, pos);
- } else if (EATTWO('\\', '{')) {
+ }
+ else if (EATTWO('\\', '{'))
+ {
count = p_count(p);
- if (EAT(',')) {
- if (MORE() && isdigit(PEEK())) {
+ if (EAT(','))
+ {
+ if (MORE() && isdigit(PEEK()))
+ {
count2 = p_count(p);
REQUIRE(count <= count2, REG_BADBR);
- } else /* single number with comma */
+ }
+ else
+/* single number with comma */
count2 = INFINITY;
- } else /* just a single number */
+ }
+ else
+/* just a single number */
count2 = count;
repeat(p, pos, count, count2);
- if (!EATTWO('\\', '}')) { /* error heuristics */
+ if (!EATTWO('\\', '}'))
+ { /* error heuristics */
while (MORE() && !SEETWO('\\', '}'))
NEXT();
REQUIRE(MORE(), REG_EBRACE);
SETERROR(REG_BADBR);
}
- } else if (c == (unsigned char)'$') /* $ (but not \$) ends it */
- return(1);
+ }
+ else if (c == (unsigned char) '$') /* $ (but not \$) ends it */
+ return (1);
- return(0);
+ return (0);
}
/*
- p_count - parse a repetition count
== static int p_count(register struct parse *p);
*/
-static int /* the value */
+static int /* the value */
p_count(p)
register struct parse *p;
{
- register int count = 0;
- register int ndigits = 0;
+ register int count = 0;
+ register int ndigits = 0;
- while (MORE() && isdigit(PEEK()) && count <= DUPMAX) {
- count = count*10 + (GETNEXT() - '0');
+ while (MORE() && isdigit(PEEK()) && count <= DUPMAX)
+ {
+ count = count * 10 + (GETNEXT() - '0');
ndigits++;
}
REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
- return(count);
+ return (count);
}
/*
@@ -670,23 +718,25 @@ static void
p_bracket(p)
register struct parse *p;
{
- register cset *cs = allocset(p);
- register int invert = 0;
+ register cset *cs = allocset(p);
+ register int invert = 0;
/* Dept of Truly Sickening Special-Case Kludges */
- if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0) {
+ if (p->next + 5 < p->end && strncmp(p->next, "[:<:]]", 6) == 0)
+ {
EMIT(OBOW, 0);
NEXTn(6);
return;
}
- if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0) {
+ if (p->next + 5 < p->end && strncmp(p->next, "[:>:]]", 6) == 0)
+ {
EMIT(OEOW, 0);
NEXTn(6);
return;
}
if (EAT('^'))
- invert++; /* make note to invert set at end */
+ invert++; /* make note to invert set at end */
if (EAT(']'))
CHadd(cs, ']');
else if (EAT('-'))
@@ -697,15 +747,17 @@ register struct parse *p;
CHadd(cs, '-');
MUSTEAT(']', REG_EBRACK);
- if (p->error != 0) /* don't mess things up further */
+ if (p->error != 0) /* don't mess things up further */
return;
- if (p->g->cflags&REG_ICASE) {
- register int i;
- register int ci;
+ if (p->g->cflags & REG_ICASE)
+ {
+ register int i;
+ register int ci;
for (i = p->g->csetsize - 1; i >= 0; i--)
- if (CHIN(cs, i) && isalpha(i)) {
+ if (CHIN(cs, i) && isalpha(i))
+ {
ci = othercase(i);
if (ci != i)
CHadd(cs, ci);
@@ -713,26 +765,29 @@ register struct parse *p;
if (cs->multis != NULL)
mccase(p, cs);
}
- if (invert) {
- register int i;
+ if (invert)
+ {
+ register int i;
for (i = p->g->csetsize - 1; i >= 0; i--)
if (CHIN(cs, i))
CHsub(cs, i);
else
CHadd(cs, i);
- if (p->g->cflags&REG_NEWLINE)
+ if (p->g->cflags & REG_NEWLINE)
CHsub(cs, '\n');
if (cs->multis != NULL)
mcinvert(p, cs);
}
- assert(cs->multis == NULL); /* xxx */
+ assert(cs->multis == NULL); /* xxx */
- if (nch(p, cs) == 1) { /* optimize singleton sets */
+ if (nch(p, cs) == 1)
+ { /* optimize singleton sets */
ordinary(p, firstch(p, cs));
freeset(p, cs);
- } else
+ }
+ else
EMIT(OANYOF, freezeset(p, cs));
}
@@ -743,28 +798,31 @@ register struct parse *p;
static void
p_b_term(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- register char c;
- register char start, finish;
- register int i;
+ register char c;
+ register char start,
+ finish;
+ register int i;
/* classify what we've got */
- switch ((MORE()) ? PEEK() : '\0') {
+ switch ((MORE()) ? PEEK() : '\0')
+ {
case '[':
c = (MORE2()) ? PEEK2() : '\0';
break;
case '-':
SETERROR(REG_ERANGE);
- return; /* NOTE RETURN */
+ return; /* NOTE RETURN */
break;
default:
c = '\0';
break;
}
- switch (c) {
- case ':': /* character class */
+ switch (c)
+ {
+ case ':': /* character class */
NEXT2();
REQUIRE(MORE(), REG_EBRACK);
c = PEEK();
@@ -773,7 +831,7 @@ register cset *cs;
REQUIRE(MORE(), REG_EBRACK);
REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
break;
- case '=': /* equivalence class */
+ case '=': /* equivalence class */
NEXT2();
REQUIRE(MORE(), REG_EBRACK);
c = PEEK();
@@ -782,17 +840,19 @@ register cset *cs;
REQUIRE(MORE(), REG_EBRACK);
REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
break;
- default: /* symbol, ordinary character, or range */
+ default: /* symbol, ordinary character, or range */
/* xxx revision needed for multichar stuff */
start = p_b_symbol(p);
- if (SEE('-') && MORE2() && PEEK2() != ']') {
+ if (SEE('-') && MORE2() && PEEK2() != ']')
+ {
/* range */
NEXT();
if (EAT('-'))
finish = '-';
else
finish = p_b_symbol(p);
- } else
+ }
+ else
finish = start;
/* xxx what about signed chars here... */
REQUIRE(start <= finish, REG_ERANGE);
@@ -809,13 +869,13 @@ register cset *cs;
static void
p_b_cclass(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- register char *sp = p->next;
+ register char *sp = p->next;
register struct cclass *cp;
register size_t len;
- register char *u;
- register char c;
+ register char *u;
+ register char c;
while (MORE() && isalpha(PEEK()))
NEXT();
@@ -823,7 +883,8 @@ register cset *cs;
for (cp = cclasses; cp->name != NULL; cp++)
if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
break;
- if (cp->name == NULL) {
+ if (cp->name == NULL)
+ {
/* oops, didn't find it */
SETERROR(REG_ECTYPE);
return;
@@ -845,9 +906,9 @@ register cset *cs;
static void
p_b_eclass(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- register char c;
+ register char c;
c = p_b_coll_elem(p, '=');
CHadd(cs, c);
@@ -857,66 +918,68 @@ register cset *cs;
- p_b_symbol - parse a character or [..]ed multicharacter collating symbol
== static char p_b_symbol(register struct parse *p);
*/
-static char /* value of symbol */
+static char /* value of symbol */
p_b_symbol(p)
register struct parse *p;
{
- register char value;
+ register char value;
REQUIRE(MORE(), REG_EBRACK);
if (!EATTWO('[', '.'))
- return(GETNEXT());
+ return (GETNEXT());
/* collating symbol */
value = p_b_coll_elem(p, '.');
REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
- return(value);
+ return (value);
}
/*
- p_b_coll_elem - parse a collating-element name and look it up
== static char p_b_coll_elem(register struct parse *p, int endc);
*/
-static char /* value of collating element */
+static char /* value of collating element */
p_b_coll_elem(p, endc)
register struct parse *p;
-int endc; /* name ended by endc,']' */
+int endc; /* name ended by endc,']' */
{
- register char *sp = p->next;
+ register char *sp = p->next;
register struct cname *cp;
- register int len;
+ register int len;
while (MORE() && !SEETWO(endc, ']'))
NEXT();
- if (!MORE()) {
+ if (!MORE())
+ {
SETERROR(REG_EBRACK);
- return(0);
+ return (0);
}
len = p->next - sp;
for (cp = cnames; cp->name != NULL; cp++)
if (strncmp(cp->name, sp, len) == 0 && cp->name[len] == '\0')
- return(cp->code); /* known name */
+ return (cp->code); /* known name */
if (len == 1)
- return(*sp); /* single character */
- SETERROR(REG_ECOLLATE); /* neither */
- return(0);
+ return (*sp); /* single character */
+ SETERROR(REG_ECOLLATE); /* neither */
+ return (0);
}
/*
- othercase - return the case counterpart of an alphabetic
== static char othercase(int ch);
*/
-static char /* if no counterpart, return ch */
+static char /* if no counterpart, return ch */
othercase(ch)
-int ch;
+int ch;
{
assert(isalpha(ch));
if (isupper(ch))
- return(tolower(ch));
+ return (tolower(ch));
else if (islower(ch))
- return(toupper(ch));
- else /* peculiar, but could happen */
- return(ch);
+ return (toupper(ch));
+ else
+/* peculiar, but could happen */
+ return (ch);
}
/*
@@ -928,20 +991,20 @@ int ch;
static void
bothcases(p, ch)
register struct parse *p;
-int ch;
+int ch;
{
- register char *oldnext = p->next;
- register char *oldend = p->end;
- char bracket[3];
+ register char *oldnext = p->next;
+ register char *oldend = p->end;
+ char bracket[3];
- assert(othercase(ch) != ch); /* p_bracket() would recurse */
+ assert(othercase(ch) != ch);/* p_bracket() would recurse */
p->next = bracket;
- p->end = bracket+2;
+ p->end = bracket + 2;
bracket[0] = ch;
bracket[1] = ']';
bracket[2] = '\0';
p_bracket(p);
- assert(p->next == bracket+2);
+ assert(p->next == bracket + 2);
p->next = oldnext;
p->end = oldend;
}
@@ -953,14 +1016,15 @@ int ch;
static void
ordinary(p, ch)
register struct parse *p;
-register int ch;
+register int ch;
{
register cat_t *cap = p->g->categories;
- if ((p->g->cflags&REG_ICASE) && isalpha(ch) && othercase(ch) != ch)
+ if ((p->g->cflags & REG_ICASE) && isalpha(ch) && othercase(ch) != ch)
bothcases(p, ch);
- else {
- EMIT(OCHAR, (unsigned char)ch);
+ else
+ {
+ EMIT(OCHAR, (unsigned char) ch);
if (cap[ch] == 0)
cap[ch] = p->g->ncategories++;
}
@@ -976,18 +1040,18 @@ static void
nonnewline(p)
register struct parse *p;
{
- register char *oldnext = p->next;
- register char *oldend = p->end;
- char bracket[4];
+ register char *oldnext = p->next;
+ register char *oldend = p->end;
+ char bracket[4];
p->next = bracket;
- p->end = bracket+3;
+ p->end = bracket + 3;
bracket[0] = '^';
bracket[1] = '\n';
bracket[2] = ']';
bracket[3] = '\0';
p_bracket(p);
- assert(p->next == bracket+3);
+ assert(p->next == bracket + 3);
p->next = oldnext;
p->end = oldend;
}
@@ -999,42 +1063,45 @@ register struct parse *p;
static void
repeat(p, start, from, to)
register struct parse *p;
-sopno start; /* operand from here to end of strip */
-int from; /* repeated from this number */
-int to; /* to this number of times (maybe INFINITY) */
+sopno start; /* operand from here to end of strip */
+int from; /* repeated from this number */
+int to; /* to this number of times (maybe
+ * INFINITY) */
{
- register sopno finish = HERE();
-# define N 2
-# define INF 3
-# define REP(f, t) ((f)*8 + (t))
-# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
- register sopno copy;
-
- if (p->error != 0) /* head off possible runaway recursion */
+ register sopno finish = HERE();
+
+#define N 2
+#define INF 3
+#define REP(f, t) ((f)*8 + (t))
+#define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
+ register sopno copy;
+
+ if (p->error != 0) /* head off possible runaway recursion */
return;
assert(from <= to);
- switch (REP(MAP(from), MAP(to))) {
- case REP(0, 0): /* must be user doing this */
- DROP(finish-start); /* drop the operand */
+ switch (REP(MAP(from), MAP(to)))
+ {
+ case REP(0, 0): /* must be user doing this */
+ DROP(finish - start); /* drop the operand */
break;
- case REP(0, 1): /* as x{1,1}? */
- case REP(0, N): /* as x{1,n}? */
- case REP(0, INF): /* as x{1,}? */
+ case REP(0, 1): /* as x{1,1}? */
+ case REP(0, N): /* as x{1,n}? */
+ case REP(0, INF): /* as x{1,}? */
/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
- INSERT(OCH_, start); /* offset is wrong... */
- repeat(p, start+1, 1, to);
+ INSERT(OCH_, start); /* offset is wrong... */
+ repeat(p, start + 1, 1, to);
ASTERN(OOR1, start);
AHEAD(start); /* ... fix it */
EMIT(OOR2, 0);
AHEAD(THERE());
ASTERN(O_CH, THERETHERE());
break;
- case REP(1, 1): /* trivial case */
+ case REP(1, 1): /* trivial case */
/* done */
break;
- case REP(1, N): /* as x?x{1,n-1} */
+ case REP(1, N): /* as x?x{1,n-1} */
/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
INSERT(OCH_, start);
ASTERN(OOR1, start);
@@ -1042,23 +1109,23 @@ int to; /* to this number of times (maybe INFINITY) */
EMIT(OOR2, 0); /* offset very wrong... */
AHEAD(THERE()); /* ...so fix it */
ASTERN(O_CH, THERETHERE());
- copy = dupl(p, start+1, finish+1);
- assert(copy == finish+4);
- repeat(p, copy, 1, to-1);
+ copy = dupl(p, start + 1, finish + 1);
+ assert(copy == finish + 4);
+ repeat(p, copy, 1, to - 1);
break;
- case REP(1, INF): /* as x+ */
+ case REP(1, INF): /* as x+ */
INSERT(OPLUS_, start);
ASTERN(O_PLUS, start);
break;
- case REP(N, N): /* as xx{m-1,n-1} */
+ case REP(N, N): /* as xx{m-1,n-1} */
copy = dupl(p, start, finish);
- repeat(p, copy, from-1, to-1);
+ repeat(p, copy, from - 1, to - 1);
break;
- case REP(N, INF): /* as xx{n-1,INF} */
+ case REP(N, INF): /* as xx{n-1,INF} */
copy = dupl(p, start, finish);
- repeat(p, copy, from-1, to);
+ repeat(p, copy, from - 1, to);
break;
- default: /* "can't happen" */
+ default: /* "can't happen" */
SETERROR(REG_ASSERT); /* just in case */
break;
}
@@ -1068,71 +1135,74 @@ int to; /* to this number of times (maybe INFINITY) */
- seterr - set an error condition
== static int seterr(register struct parse *p, int e);
*/
-static int /* useless but makes type checking happy */
+static int /* useless but makes type checking happy */
seterr(p, e)
register struct parse *p;
-int e;
+int e;
{
- if (p->error == 0) /* keep earliest error condition */
+ if (p->error == 0) /* keep earliest error condition */
p->error = e;
- p->next = nuls; /* try to bring things to a halt */
+ p->next = nuls; /* try to bring things to a halt */
p->end = nuls;
- return(0); /* make the return value well-defined */
+ return (0); /* make the return value well-defined */
}
/*
- allocset - allocate a set of characters for []
== static cset *allocset(register struct parse *p);
*/
-static cset *
+static cset *
allocset(p)
register struct parse *p;
{
- register int no = p->g->ncsets++;
+ register int no = p->g->ncsets++;
register size_t nc;
register size_t nbytes;
- register cset *cs;
- register size_t css = (size_t)p->g->csetsize;
- register int i;
+ register cset *cs;
+ register size_t css = (size_t) p->g->csetsize;
+ register int i;
- if (no >= p->ncsalloc) { /* need another column of space */
+ if (no >= p->ncsalloc)
+ { /* need another column of space */
p->ncsalloc += CHAR_BIT;
nc = p->ncsalloc;
assert(nc % CHAR_BIT == 0);
nbytes = nc / CHAR_BIT * css;
if (p->g->sets == NULL)
- p->g->sets = (cset *)malloc(nc * sizeof(cset));
+ p->g->sets = (cset *) malloc(nc * sizeof(cset));
else
- p->g->sets = (cset *)realloc((char *)p->g->sets,
- nc * sizeof(cset));
+ p->g->sets = (cset *) realloc((char *) p->g->sets,
+ nc * sizeof(cset));
if (p->g->setbits == NULL)
- p->g->setbits = (uch *)malloc(nbytes);
- else {
- p->g->setbits = (uch *)realloc((char *)p->g->setbits,
- nbytes);
+ p->g->setbits = (uch *) malloc(nbytes);
+ else
+ {
+ p->g->setbits = (uch *) realloc((char *) p->g->setbits,
+ nbytes);
/* xxx this isn't right if setbits is now NULL */
for (i = 0; i < no; i++)
- p->g->sets[i].ptr = p->g->setbits + css*(i/CHAR_BIT);
+ p->g->sets[i].ptr = p->g->setbits + css * (i / CHAR_BIT);
}
if (p->g->sets != NULL && p->g->setbits != NULL)
- memset((char *)p->g->setbits + (nbytes - css),
- 0, css);
- else {
+ memset((char *) p->g->setbits + (nbytes - css),
+ 0, css);
+ else
+ {
no = 0;
SETERROR(REG_ESPACE);
/* caller's responsibility not to do set ops */
}
}
- assert(p->g->sets != NULL); /* xxx */
+ assert(p->g->sets != NULL); /* xxx */
cs = &p->g->sets[no];
- cs->ptr = p->g->setbits + css*((no)/CHAR_BIT);
+ cs->ptr = p->g->setbits + css * ((no) / CHAR_BIT);
cs->mask = 1 << ((no) % CHAR_BIT);
cs->hash = 0;
cs->smultis = 0;
cs->multis = NULL;
- return(cs);
+ return (cs);
}
/*
@@ -1142,15 +1212,15 @@ register struct parse *p;
static void
freeset(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- register int i;
- register cset *top = &p->g->sets[p->g->ncsets];
- register size_t css = (size_t)p->g->csetsize;
+ register int i;
+ register cset *top = &p->g->sets[p->g->ncsets];
+ register size_t css = (size_t) p->g->csetsize;
for (i = 0; i < css; i++)
CHsub(cs, i);
- if (cs == top-1) /* recover only the easy case */
+ if (cs == top - 1) /* recover only the easy case */
p->g->ncsets--;
}
@@ -1160,24 +1230,25 @@ register cset *cs;
*
* The main task here is merging identical sets. This is usually a waste
* of time (although the hash code minimizes the overhead), but can win
- * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash
+ * big if REG_ICASE is being used. REG_ICASE, by the way, is why the hash
* is done using addition rather than xor -- all ASCII [aA] sets xor to
* the same value!
*/
-static int /* set number */
+static int /* set number */
freezeset(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- register uch h = cs->hash;
- register int i;
- register cset *top = &p->g->sets[p->g->ncsets];
- register cset *cs2;
- register size_t css = (size_t)p->g->csetsize;
+ register uch h = cs->hash;
+ register int i;
+ register cset *top = &p->g->sets[p->g->ncsets];
+ register cset *cs2;
+ register size_t css = (size_t) p->g->csetsize;
/* look for an earlier one which is the same */
for (cs2 = &p->g->sets[0]; cs2 < top; cs2++)
- if (cs2->hash == h && cs2 != cs) {
+ if (cs2->hash == h && cs2 != cs)
+ {
/* maybe */
for (i = 0; i < css; i++)
if (!!CHIN(cs2, i) != !!CHIN(cs, i))
@@ -1186,31 +1257,32 @@ register cset *cs;
break; /* yes */
}
- if (cs2 < top) { /* found one */
+ if (cs2 < top)
+ { /* found one */
freeset(p, cs);
cs = cs2;
}
- return((int)(cs - p->g->sets));
+ return ((int) (cs - p->g->sets));
}
/*
- firstch - return first character in a set (which must have at least one)
== static int firstch(register struct parse *p, register cset *cs);
*/
-static int /* character; there is no "none" value */
+static int /* character; there is no "none" value */
firstch(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- register int i;
- register size_t css = (size_t)p->g->csetsize;
+ register int i;
+ register size_t css = (size_t) p->g->csetsize;
for (i = 0; i < css; i++)
if (CHIN(cs, i))
- return((char)i);
+ return ((char) i);
assert(never);
- return(0); /* arbitrary */
+ return (0); /* arbitrary */
}
/*
@@ -1220,28 +1292,28 @@ register cset *cs;
static int
nch(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- register int i;
- register size_t css = (size_t)p->g->csetsize;
- register int n = 0;
+ register int i;
+ register size_t css = (size_t) p->g->csetsize;
+ register int n = 0;
for (i = 0; i < css; i++)
if (CHIN(cs, i))
n++;
- return(n);
+ return (n);
}
/*
- mcadd - add a collating element to a cset
== static void mcadd(register struct parse *p, register cset *cs, \
- == register char *cp);
+ == register char *cp);
*/
static void
mcadd(p, cs, cp)
register struct parse *p;
-register cset *cs;
-register char *cp;
+register cset *cs;
+register char *cp;
{
register size_t oldend = cs->smultis;
@@ -1250,7 +1322,8 @@ register char *cp;
cs->multis = malloc(cs->smultis);
else
cs->multis = realloc(cs->multis, cs->smultis);
- if (cs->multis == NULL) {
+ if (cs->multis == NULL)
+ {
SETERROR(REG_ESPACE);
return;
}
@@ -1269,22 +1342,22 @@ mcsub(cs, cp)
register cset *cs;
register char *cp;
{
- register char *fp = mcfind(cs, cp);
- register size_t len = strlen(fp);
-
- assert(fp != NULL);
- memmove(fp, fp + len + 1,
- cs->smultis - (fp + len + 1 - cs->multis));
- cs->smultis -= len;
-
- if (cs->smultis == 0) {
- free(cs->multis);
- cs->multis = NULL;
- return;
- }
+ register char *fp = mcfind(cs, cp);
+ register size_t len = strlen(fp);
+
+ assert(fp != NULL);
+ memmove(fp, fp + len + 1,
+ cs->smultis - (fp + len + 1 - cs->multis));
+ cs->smultis -= len;
+
+ if (cs->smultis == 0) {
+ free(cs->multis);
+ cs->multis = NULL;
+ return;
+ }
- cs->multis = realloc(cs->multis, cs->smultis);
- assert(cs->multis != NULL);
+ cs->multis = realloc(cs->multis, cs->smultis);
+ assert(cs->multis != NULL);
}
*/
@@ -1298,7 +1371,7 @@ mcin(cs, cp)
register cset *cs;
register char *cp;
{
- return(mcfind(cs, cp) != NULL);
+ return(mcfind(cs, cp) != NULL);
}
*/
@@ -1312,14 +1385,14 @@ mcfind(cs, cp)
register cset *cs;
register char *cp;
{
- register char *p;
+ register char *p;
- if (cs->multis == NULL)
+ if (cs->multis == NULL)
+ return(NULL);
+ for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
+ if (strcmp(cp, p) == 0)
+ return(p);
return(NULL);
- for (p = cs->multis; *p != '\0'; p += strlen(p) + 1)
- if (strcmp(cp, p) == 0)
- return(p);
- return(NULL);
}
*/
/*
@@ -1332,9 +1405,9 @@ register char *cp;
static void
mcinvert(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- assert(cs->multis == NULL); /* xxx */
+ assert(cs->multis == NULL); /* xxx */
}
/*
@@ -1347,51 +1420,51 @@ register cset *cs;
static void
mccase(p, cs)
register struct parse *p;
-register cset *cs;
+register cset *cs;
{
- assert(cs->multis == NULL); /* xxx */
+ assert(cs->multis == NULL); /* xxx */
}
/*
- isinsets - is this character in any sets?
== static int isinsets(register struct re_guts *g, int c);
*/
-static int /* predicate */
+static int /* predicate */
isinsets(g, c)
register struct re_guts *g;
-int c;
+int c;
{
- register uch *col;
- register int i;
- register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
- register unsigned uc = (unsigned char)c;
+ register uch *col;
+ register int i;
+ register int ncols = (g->ncsets + (CHAR_BIT - 1)) / CHAR_BIT;
+ register unsigned uc = (unsigned char) c;
for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
if (col[uc] != 0)
- return(1);
- return(0);
+ return (1);
+ return (0);
}
/*
- samesets - are these two characters in exactly the same sets?
== static int samesets(register struct re_guts *g, int c1, int c2);
*/
-static int /* predicate */
+static int /* predicate */
samesets(g, c1, c2)
register struct re_guts *g;
-int c1;
-int c2;
+int c1;
+int c2;
{
- register uch *col;
- register int i;
- register int ncols = (g->ncsets+(CHAR_BIT-1)) / CHAR_BIT;
- register unsigned uc1 = (unsigned char)c1;
- register unsigned uc2 = (unsigned char)c2;
+ register uch *col;
+ register int i;
+ register int ncols = (g->ncsets + (CHAR_BIT - 1)) / CHAR_BIT;
+ register unsigned uc1 = (unsigned char) c1;
+ register unsigned uc2 = (unsigned char) c2;
for (i = 0, col = g->setbits; i < ncols; i++, col += g->csetsize)
if (col[uc1] != col[uc2])
- return(0);
- return(1);
+ return (0);
+ return (1);
}
/*
@@ -1400,23 +1473,24 @@ int c2;
*/
static void
categorize(p, g)
-struct parse *p;
+struct parse *p;
register struct re_guts *g;
{
register cat_t *cats = g->categories;
- register int c;
- register int c2;
- register cat_t cat;
+ register int c;
+ register int c2;
+ register cat_t cat;
/* avoid making error situations worse */
if (p->error != 0)
return;
for (c = CHAR_MIN; c <= CHAR_MAX; c++)
- if (cats[c] == 0 && isinsets(g, c)) {
+ if (cats[c] == 0 && isinsets(g, c))
+ {
cat = g->ncategories++;
cats[c] = cat;
- for (c2 = c+1; c2 <= CHAR_MAX; c2++)
+ for (c2 = c + 1; c2 <= CHAR_MAX; c2++)
if (cats[c2] == 0 && samesets(g, c, c2))
cats[c2] = cat;
}
@@ -1426,24 +1500,24 @@ register struct re_guts *g;
- dupl - emit a duplicate of a bunch of sops
== static sopno dupl(register struct parse *p, sopno start, sopno finish);
*/
-static sopno /* start of duplicate */
+static sopno /* start of duplicate */
dupl(p, start, finish)
register struct parse *p;
-sopno start; /* from here */
-sopno finish; /* to this less one */
+sopno start; /* from here */
+sopno finish; /* to this less one */
{
- register sopno ret = HERE();
- register sopno len = finish - start;
+ register sopno ret = HERE();
+ register sopno len = finish - start;
assert(finish >= start);
if (len == 0)
- return(ret);
- enlarge(p, p->ssize + len); /* this many unexpected additions */
+ return (ret);
+ enlarge(p, p->ssize + len); /* this many unexpected additions */
assert(p->ssize >= p->slen + len);
- memcpy((char *)(p->strip + p->slen),
- (char *)(p->strip + start), (size_t)len*sizeof(sop));
+ memcpy((char *) (p->strip + p->slen),
+ (char *) (p->strip + start), (size_t) len * sizeof(sop));
p->slen += len;
- return(ret);
+ return (ret);
}
/*
@@ -1457,19 +1531,19 @@ sopno finish; /* to this less one */
static void
doemit(p, op, opnd)
register struct parse *p;
-sop op;
-size_t opnd;
+sop op;
+size_t opnd;
{
/* avoid making error situations worse */
if (p->error != 0)
return;
/* deal with oversize operands ("can't happen", more or less) */
- assert(opnd < 1<<OPSHIFT);
+ assert(opnd < 1 << OPSHIFT);
/* deal with undersized strip */
if (p->slen >= p->ssize)
- enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */
+ enlarge(p, (p->ssize + 1) / 2 * 3); /* +50% */
assert(p->slen < p->ssize);
/* finally, it's all reduced to the easy case */
@@ -1483,36 +1557,39 @@ size_t opnd;
static void
doinsert(p, op, opnd, pos)
register struct parse *p;
-sop op;
-size_t opnd;
-sopno pos;
+sop op;
+size_t opnd;
+sopno pos;
{
- register sopno sn;
- register sop s;
- register int i;
+ register sopno sn;
+ register sop s;
+ register int i;
/* avoid making error situations worse */
if (p->error != 0)
return;
sn = HERE();
- EMIT(op, opnd); /* do checks, ensure space */
- assert(HERE() == sn+1);
+ EMIT(op, opnd); /* do checks, ensure space */
+ assert(HERE() == sn + 1);
s = p->strip[sn];
/* adjust paren pointers */
assert(pos > 0);
- for (i = 1; i < NPAREN; i++) {
- if (p->pbegin[i] >= pos) {
+ for (i = 1; i < NPAREN; i++)
+ {
+ if (p->pbegin[i] >= pos)
+ {
p->pbegin[i]++;
}
- if (p->pend[i] >= pos) {
+ if (p->pend[i] >= pos)
+ {
p->pend[i]++;
}
}
- memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
- (HERE()-pos-1)*sizeof(sop));
+ memmove((char *) &p->strip[pos + 1], (char *) &p->strip[pos],
+ (HERE() - pos - 1) * sizeof(sop));
p->strip[pos] = s;
}
@@ -1523,14 +1600,14 @@ sopno pos;
static void
dofwd(p, pos, value)
register struct parse *p;
-register sopno pos;
-sop value;
+register sopno pos;
+sop value;
{
/* avoid making error situations worse */
if (p->error != 0)
return;
- assert(value < 1<<OPSHIFT);
+ assert(value < 1 << OPSHIFT);
p->strip[pos] = OP(p->strip[pos]) | value;
}
@@ -1541,15 +1618,16 @@ sop value;
static void
enlarge(p, size)
register struct parse *p;
-register sopno size;
+register sopno size;
{
- register sop *sp;
+ register sop *sp;
if (p->ssize >= size)
return;
- sp = (sop *)realloc(p->strip, size*sizeof(sop));
- if (sp == NULL) {
+ sp = (sop *) realloc(p->strip, size * sizeof(sop));
+ if (sp == NULL)
+ {
SETERROR(REG_ESPACE);
return;
}
@@ -1567,8 +1645,9 @@ register struct parse *p;
register struct re_guts *g;
{
g->nstates = p->slen;
- g->strip = (sop *)realloc((char *)p->strip, p->slen * sizeof(sop));
- if (g->strip == NULL) {
+ g->strip = (sop *) realloc((char *) p->strip, p->slen * sizeof(sop));
+ if (g->strip == NULL)
+ {
SETERROR(REG_ESPACE);
g->strip = p->strip;
}
@@ -1586,16 +1665,16 @@ register struct re_guts *g;
*/
static void
findmust(p, g)
-struct parse *p;
+struct parse *p;
register struct re_guts *g;
{
- register sop *scan;
- sop *start = 0;
- register sop *newstart = 0;
- register sopno newlen;
- register sop s;
- register char *cp;
- register sopno i;
+ register sop *scan;
+ sop *start = 0;
+ register sop *newstart = 0;
+ register sopno newlen;
+ register sop s;
+ register char *cp;
+ register sopno i;
/* avoid making error situations worse */
if (p->error != 0)
@@ -1604,34 +1683,39 @@ register struct re_guts *g;
/* find the longest OCHAR sequence in strip */
newlen = 0;
scan = g->strip + 1;
- do {
+ do
+ {
s = *scan++;
- switch (OP(s)) {
- case OCHAR: /* sequence member */
- if (newlen == 0) /* new sequence */
+ switch (OP(s))
+ {
+ case OCHAR: /* sequence member */
+ if (newlen == 0) /* new sequence */
newstart = scan - 1;
newlen++;
break;
- case OPLUS_: /* things that don't break one */
+ case OPLUS_: /* things that don't break one */
case OLPAREN:
case ORPAREN:
break;
- case OQUEST_: /* things that must be skipped */
+ case OQUEST_: /* things that must be skipped */
case OCH_:
scan--;
- do {
+ do
+ {
scan += OPND(s);
s = *scan;
/* assert() interferes w debug printouts */
if (OP(s) != O_QUEST && OP(s) != O_CH &&
- OP(s) != OOR2) {
+ OP(s) != OOR2)
+ {
g->iflags |= BAD;
return;
}
} while (OP(s) != O_QUEST && OP(s) != O_CH);
/* fallthrough */
- default: /* things that break a sequence */
- if (newlen > g->mlen) { /* ends one */
+ default: /* things that break a sequence */
+ if (newlen > g->mlen)
+ { /* ends one */
start = newstart;
g->mlen = newlen;
}
@@ -1640,48 +1724,52 @@ register struct re_guts *g;
}
} while (OP(s) != OEND);
- if (g->mlen == 0) /* there isn't one */
+ if (g->mlen == 0) /* there isn't one */
return;
/* turn it into a character string */
- g->must = malloc((size_t)g->mlen + 1);
- if (g->must == NULL) { /* argh; just forget it */
+ g->must = malloc((size_t) g->mlen + 1);
+ if (g->must == NULL)
+ { /* argh; just forget it */
g->mlen = 0;
return;
}
cp = g->must;
scan = start;
- for (i = g->mlen; i > 0; i--) {
+ for (i = g->mlen; i > 0; i--)
+ {
while (OP(s = *scan++) != OCHAR)
continue;
assert(cp < g->must + g->mlen);
- *cp++ = (char)OPND(s);
+ *cp++ = (char) OPND(s);
}
assert(cp == g->must + g->mlen);
- *cp++ = '\0'; /* just on general principles */
+ *cp++ = '\0'; /* just on general principles */
}
/*
- pluscount - count + nesting
== static sopno pluscount(register struct parse *p, register struct re_guts *g);
*/
-static sopno /* nesting depth */
+static sopno /* nesting depth */
pluscount(p, g)
-struct parse *p;
+struct parse *p;
register struct re_guts *g;
{
- register sop *scan;
- register sop s;
- register sopno plusnest = 0;
- register sopno maxnest = 0;
+ register sop *scan;
+ register sop s;
+ register sopno plusnest = 0;
+ register sopno maxnest = 0;
if (p->error != 0)
- return(0); /* there may not be an OEND */
+ return (0); /* there may not be an OEND */
scan = g->strip + 1;
- do {
+ do
+ {
s = *scan++;
- switch (OP(s)) {
+ switch (OP(s))
+ {
case OPLUS_:
plusnest++;
break;
@@ -1694,5 +1782,5 @@ register struct re_guts *g;
} while (OP(s) != OEND);
if (plusnest != 0)
g->iflags |= BAD;
- return(maxnest);
+ return (maxnest);
}
diff --git a/src/backend/regex/regerror.c b/src/backend/regex/regerror.c
index 7d1d06cbc90..9e6e0e02179 100644
--- a/src/backend/regex/regerror.c
+++ b/src/backend/regex/regerror.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
@@ -10,22 +10,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)
@@ -34,12 +34,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)regerror.c 8.4 (Berkeley) 3/20/94
+ * @(#)regerror.c 8.4 (Berkeley) 3/20/94
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)regerror.c 8.4 (Berkeley) 3/20/94";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)regerror.c 8.4 (Berkeley) 3/20/94";
+
+#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <stdio.h>
@@ -54,58 +55,97 @@ static char sccsid[] = "@(#)regerror.c 8.4 (Berkeley) 3/20/94";
/* ========= begin header generated by ./mkh ========= */
#ifdef __cplusplus
-extern "C" {
+extern "C"
+{
#endif
/* === regerror.c === */
-static char *regatoi(const regex_t *preg, char *localbuf);
+ static char *regatoi(const regex_t * preg, char *localbuf);
#ifdef __cplusplus
}
+
#endif
/* ========= end header generated by ./mkh ========= */
/*
- = #define REG_NOMATCH 1
- = #define REG_BADPAT 2
- = #define REG_ECOLLATE 3
- = #define REG_ECTYPE 4
- = #define REG_EESCAPE 5
- = #define REG_ESUBREG 6
- = #define REG_EBRACK 7
- = #define REG_EPAREN 8
- = #define REG_EBRACE 9
- = #define REG_BADBR 10
- = #define REG_ERANGE 11
- = #define REG_ESPACE 12
- = #define REG_BADRPT 13
- = #define REG_EMPTY 14
- = #define REG_ASSERT 15
- = #define REG_INVARG 16
- = #define REG_ATOI 255 // convert name to number (!)
- = #define REG_ITOA 0400 // convert number to name (!)
+ = #define REG_NOMATCH 1
+ = #define REG_BADPAT 2
+ = #define REG_ECOLLATE 3
+ = #define REG_ECTYPE 4
+ = #define REG_EESCAPE 5
+ = #define REG_ESUBREG 6
+ = #define REG_EBRACK 7
+ = #define REG_EPAREN 8
+ = #define REG_EBRACE 9
+ = #define REG_BADBR 10
+ = #define REG_ERANGE 11
+ = #define REG_ESPACE 12
+ = #define REG_BADRPT 13
+ = #define REG_EMPTY 14
+ = #define REG_ASSERT 15
+ = #define REG_INVARG 16
+ = #define REG_ATOI 255 // convert name to number (!)
+ = #define REG_ITOA 0400 // convert number to name (!)
*/
-static struct rerr {
- int code;
- char *name;
- char *explain;
-} rerrs[] = {
- {REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match"},
- {REG_BADPAT, "REG_BADPAT", "invalid regular expression"},
- {REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element"},
- {REG_ECTYPE, "REG_ECTYPE", "invalid character class"},
- {REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)"},
- {REG_ESUBREG, "REG_ESUBREG", "invalid backreference number"},
- {REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced"},
- {REG_EPAREN, "REG_EPAREN", "parentheses not balanced"},
- {REG_EBRACE, "REG_EBRACE", "braces not balanced"},
- {REG_BADBR, "REG_BADBR", "invalid repetition count(s)"},
- {REG_ERANGE, "REG_ERANGE", "invalid character range"},
- {REG_ESPACE, "REG_ESPACE", "out of memory"},
- {REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid"},
- {REG_EMPTY, "REG_EMPTY", "empty (sub)expression"},
- {REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug"},
- {REG_INVARG, "REG_INVARG", "invalid argument to regex routine"},
- {0, "", "*** unknown regexp error code ***"}
+static struct rerr
+{
+ int code;
+ char *name;
+ char *explain;
+} rerrs[] =
+
+{
+ {
+ REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match"
+ },
+ {
+ REG_BADPAT, "REG_BADPAT", "invalid regular expression"
+ },
+ {
+ REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element"
+ },
+ {
+ REG_ECTYPE, "REG_ECTYPE", "invalid character class"
+ },
+ {
+ REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)"
+ },
+ {
+ REG_ESUBREG, "REG_ESUBREG", "invalid backreference number"
+ },
+ {
+ REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced"
+ },
+ {
+ REG_EPAREN, "REG_EPAREN", "parentheses not balanced"
+ },
+ {
+ REG_EBRACE, "REG_EBRACE", "braces not balanced"
+ },
+ {
+ REG_BADBR, "REG_BADBR", "invalid repetition count(s)"
+ },
+ {
+ REG_ERANGE, "REG_ERANGE", "invalid character range"
+ },
+ {
+ REG_ESPACE, "REG_ESPACE", "out of memory"
+ },
+ {
+ REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid"
+ },
+ {
+ REG_EMPTY, "REG_EMPTY", "empty (sub)expression"
+ },
+ {
+ REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug"
+ },
+ {
+ REG_INVARG, "REG_INVARG", "invalid argument to regex routine"
+ },
+ {
+ 0, "", "*** unknown regexp error code ***"
+ }
};
/*
@@ -115,56 +155,61 @@ static struct rerr {
/* ARGSUSED */
size_t
pg95_regerror(errcode, preg, errbuf, errbuf_size)
-int errcode;
-const regex_t *preg;
-char *errbuf;
-size_t errbuf_size;
+int errcode;
+const regex_t *preg;
+char *errbuf;
+size_t errbuf_size;
{
register struct rerr *r;
register size_t len;
- register int target = errcode &~ REG_ITOA;
- register char *s;
- char convbuf[50];
+ register int target = errcode & ~REG_ITOA;
+ register char *s;
+ char convbuf[50];
if (errcode == REG_ATOI)
s = regatoi(preg, convbuf);
- else {
+ else
+ {
for (r = rerrs; r->code != 0; r++)
if (r->code == target)
break;
-
- if (errcode&REG_ITOA) {
+
+ if (errcode & REG_ITOA)
+ {
if (r->code != 0)
strcpy(convbuf, r->name);
else
sprintf(convbuf, "REG_0x%x", target);
assert(strlen(convbuf) < sizeof(convbuf));
s = convbuf;
- } else
+ }
+ else
s = r->explain;
}
len = strlen(s) + 1;
- if (errbuf_size > 0) {
+ if (errbuf_size > 0)
+ {
if (errbuf_size > len)
strcpy(errbuf, s);
- else {
- strncpy(errbuf, s, errbuf_size-1);
- errbuf[errbuf_size-1] = '\0';
+ else
+ {
+ strncpy(errbuf, s, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = '\0';
}
}
- return(len);
+ return (len);
}
/*
- regatoi - internal routine to implement REG_ATOI
== static char *regatoi(const regex_t *preg, char *localbuf);
*/
-static char *
+static char *
regatoi(preg, localbuf)
-const regex_t *preg;
-char *localbuf;
+const regex_t *preg;
+char *localbuf;
{
register struct rerr *r;
@@ -172,8 +217,8 @@ char *localbuf;
if (strcmp(r->name, preg->re_endp) == 0)
break;
if (r->code == 0)
- return("0");
+ return ("0");
sprintf(localbuf, "%d", r->code);
- return(localbuf);
+ return (localbuf);
}
diff --git a/src/backend/regex/regexec.c b/src/backend/regex/regexec.c
index 115a17667bb..5e0021f4299 100644
--- a/src/backend/regex/regexec.c
+++ b/src/backend/regex/regexec.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
@@ -10,22 +10,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)
@@ -34,12 +34,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)regexec.c 8.3 (Berkeley) 3/20/94
+ * @(#)regexec.c 8.3 (Berkeley) 3/20/94
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)regexec.c 8.3 (Berkeley) 3/20/94";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)regexec.c 8.3 (Berkeley) 3/20/94";
+
+#endif /* LIBC_SCCS and not lint */
/*
* the outer shell of regexec()
@@ -60,32 +61,32 @@ static char sccsid[] = "@(#)regexec.c 8.3 (Berkeley) 3/20/94";
#include <regex/utils.h>
#include <regex/regex2.h>
-static int nope = 0; /* for use in asserts; shuts lint up */
+static int nope = 0; /* for use in asserts; shuts lint up */
/* macros for manipulating states, small version */
-#define states long
-#define states1 states /* for later use in regexec() decision */
-#define CLEAR(v) ((v) = 0)
-#define SET0(v, n) ((v) &= ~(1 << (n)))
-#define SET1(v, n) ((v) |= 1 << (n))
-#define ISSET(v, n) ((v) & (1 << (n)))
-#define ASSIGN(d, s) ((d) = (s))
-#define EQ(a, b) ((a) == (b))
-#define STATEVARS int dummy /* dummy version */
-#define STATESETUP(m, n) /* nothing */
-#define STATETEARDOWN(m) /* nothing */
-#define SETUP(v) ((v) = 0)
-#define onestate int
-#define INIT(o, n) ((o) = (unsigned)1 << (n))
-#define INC(o) ((o) <<= 1)
-#define ISSTATEIN(v, o) ((v) & (o))
+#define states long
+#define states1 states /* for later use in regexec() decision */
+#define CLEAR(v) ((v) = 0)
+#define SET0(v, n) ((v) &= ~(1 << (n)))
+#define SET1(v, n) ((v) |= 1 << (n))
+#define ISSET(v, n) ((v) & (1 << (n)))
+#define ASSIGN(d, s) ((d) = (s))
+#define EQ(a, b) ((a) == (b))
+#define STATEVARS int dummy /* dummy version */
+#define STATESETUP(m, n) /* nothing */
+#define STATETEARDOWN(m) /* nothing */
+#define SETUP(v) ((v) = 0)
+#define onestate int
+#define INIT(o, n) ((o) = (unsigned)1 << (n))
+#define INC(o) ((o) <<= 1)
+#define ISSTATEIN(v, o) ((v) & (o))
/* some abbreviations; note that some of these know variable names! */
/* do "if I'm here, I can also be there" etc without branches */
-#define FWD(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) << (n))
-#define BACK(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) >> (n))
-#define ISSETBACK(v, n) ((v) & ((unsigned)here >> (n)))
+#define FWD(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) << (n))
+#define BACK(dst, src, n) ((dst) |= ((unsigned)(src)&(here)) >> (n))
+#define ISSETBACK(v, n) ((v) & ((unsigned)here >> (n)))
/* function names */
-#define SNAMES /* engine.c looks after details */
+#define SNAMES /* engine.c looks after details */
#include "engine.c"
@@ -111,72 +112,73 @@ static int nope = 0; /* for use in asserts; shuts lint up */
#undef SNAMES
/* macros for manipulating states, large version */
-#define states char *
-#define CLEAR(v) memset(v, 0, m->g->nstates)
-#define SET0(v, n) ((v)[n] = 0)
-#define SET1(v, n) ((v)[n] = 1)
-#define ISSET(v, n) ((v)[n])
-#define ASSIGN(d, s) memcpy(d, s, m->g->nstates)
-#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0)
-#define STATEVARS int vn; char *space
-#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \
- if ((m)->space == NULL) return(REG_ESPACE); \
- (m)->vn = 0; }
-#define STATETEARDOWN(m) { free((m)->space); }
-#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates])
-#define onestate int
-#define INIT(o, n) ((o) = (n))
-#define INC(o) ((o)++)
-#define ISSTATEIN(v, o) ((v)[o])
+#define states char *
+#define CLEAR(v) memset(v, 0, m->g->nstates)
+#define SET0(v, n) ((v)[n] = 0)
+#define SET1(v, n) ((v)[n] = 1)
+#define ISSET(v, n) ((v)[n])
+#define ASSIGN(d, s) memcpy(d, s, m->g->nstates)
+#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0)
+#define STATEVARS int vn; char *space
+#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \
+ if ((m)->space == NULL) return(REG_ESPACE); \
+ (m)->vn = 0; }
+#define STATETEARDOWN(m) { free((m)->space); }
+#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates])
+#define onestate int
+#define INIT(o, n) ((o) = (n))
+#define INC(o) ((o)++)
+#define ISSTATEIN(v, o) ((v)[o])
/* some abbreviations; note that some of these know variable names! */
/* do "if I'm here, I can also be there" etc without branches */
-#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here])
-#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here])
-#define ISSETBACK(v, n) ((v)[here - (n)])
+#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here])
+#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here])
+#define ISSETBACK(v, n) ((v)[here - (n)])
/* function names */
-#define LNAMES /* flag */
+#define LNAMES /* flag */
#include "engine.c"
/*
- regexec - interface for matching
= extern int regexec(const regex_t *, const char *, size_t, \
- = regmatch_t [], int);
- = #define REG_NOTBOL 00001
- = #define REG_NOTEOL 00002
- = #define REG_STARTEND 00004
- = #define REG_TRACE 00400 // tracing of execution
- = #define REG_LARGE 01000 // force large representation
- = #define REG_BACKR 02000 // force use of backref code
+ = regmatch_t [], int);
+ = #define REG_NOTBOL 00001
+ = #define REG_NOTEOL 00002
+ = #define REG_STARTEND 00004
+ = #define REG_TRACE 00400 // tracing of execution
+ = #define REG_LARGE 01000 // force large representation
+ = #define REG_BACKR 02000 // force use of backref code
*
* We put this here so we can exploit knowledge of the state representation
* when choosing which matcher to call. Also, by this point the matchers
* have been prototyped.
*/
-int /* 0 success, REG_NOMATCH failure */
+int /* 0 success, REG_NOMATCH failure */
pg95_regexec(preg, string, nmatch, pmatch, eflags)
-const regex_t *preg;
-const char *string;
-size_t nmatch;
-regmatch_t pmatch[];
-int eflags;
+const regex_t *preg;
+const char *string;
+size_t nmatch;
+regmatch_t pmatch[];
+int eflags;
{
register struct re_guts *g = preg->re_g;
+
#ifdef REDEBUG
-# define GOODFLAGS(f) (f)
+#define GOODFLAGS(f) (f)
#else
-# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
+#define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
#endif
if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
- return(REG_BADPAT);
- assert(!(g->iflags&BAD));
- if (g->iflags&BAD) /* backstop for no-debug case */
- return(REG_BADPAT);
+ return (REG_BADPAT);
+ assert(!(g->iflags & BAD));
+ if (g->iflags & BAD) /* backstop for no-debug case */
+ return (REG_BADPAT);
eflags = GOODFLAGS(eflags);
- if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags&REG_LARGE))
- return(smatcher(g, (char *)string, nmatch, pmatch, eflags));
+ if (g->nstates <= CHAR_BIT * sizeof(states1) && !(eflags & REG_LARGE))
+ return (smatcher(g, (char *) string, nmatch, pmatch, eflags));
else
- return(lmatcher(g, (char *)string, nmatch, pmatch, eflags));
+ return (lmatcher(g, (char *) string, nmatch, pmatch, eflags));
}
diff --git a/src/backend/regex/regfree.c b/src/backend/regex/regfree.c
index 9a7ff5cb5e1..26ca8863ed6 100644
--- a/src/backend/regex/regfree.c
+++ b/src/backend/regex/regfree.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
- * The Regents of the University of California. All rights reserved.
+ * The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
@@ -10,22 +10,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)
@@ -34,12 +34,13 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)regfree.c 8.3 (Berkeley) 3/20/94
+ * @(#)regfree.c 8.3 (Berkeley) 3/20/94
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char sccsid[] = "@(#)regfree.c 8.3 (Berkeley) 3/20/94";
-#endif /* LIBC_SCCS and not lint */
+static char sccsid[] = "@(#)regfree.c 8.3 (Berkeley) 3/20/94";
+
+#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <stdio.h>
@@ -55,26 +56,26 @@ static char sccsid[] = "@(#)regfree.c 8.3 (Berkeley) 3/20/94";
*/
void
pg95_regfree(preg)
-regex_t *preg;
+regex_t *preg;
{
register struct re_guts *g;
- if (preg->re_magic != MAGIC1) /* oops */
- return; /* nice to complain, but hard */
+ if (preg->re_magic != MAGIC1) /* oops */
+ return; /* nice to complain, but hard */
g = preg->re_g;
- if (g == NULL || g->magic != MAGIC2) /* oops again */
+ if (g == NULL || g->magic != MAGIC2) /* oops again */
return;
- preg->re_magic = 0; /* mark it invalid */
- g->magic = 0; /* mark it invalid */
+ preg->re_magic = 0; /* mark it invalid */
+ g->magic = 0; /* mark it invalid */
if (g->strip != NULL)
- free((char *)g->strip);
+ free((char *) g->strip);
if (g->sets != NULL)
- free((char *)g->sets);
+ free((char *) g->sets);
if (g->setbits != NULL)
- free((char *)g->setbits);
+ free((char *) g->setbits);
if (g->must != NULL)
free(g->must);
- free((char *)g);
+ free((char *) g);
}
diff --git a/src/backend/rewrite/locks.c b/src/backend/rewrite/locks.c
index 3171d2c845b..213fae9b321 100644
--- a/src/backend/rewrite/locks.c
+++ b/src/backend/rewrite/locks.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.2 1996/11/10 03:01:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.3 1997/09/07 04:48:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -14,7 +14,7 @@
#include "utils/elog.h" /* for elog */
#include "nodes/pg_list.h" /* lisp support package */
#include "nodes/parsenodes.h"
-#include "nodes/primnodes.h" /* Var node def */
+#include "nodes/primnodes.h" /* Var node def */
#include "utils/syscache.h" /* for SearchSysCache */
#include "rewrite/locks.h" /* for rewrite specific lock defns */
@@ -26,106 +26,115 @@
* if we find at least one such match, we return true
* otherwise, we return false
*/
-static bool
-nodeThisLockWasTriggered(Node *node, int varno, AttrNumber attnum)
+static bool
+nodeThisLockWasTriggered(Node * node, int varno, AttrNumber attnum)
{
- if (node==NULL)
- return FALSE;
- switch(nodeTag(node)) {
- case T_Var:
+ if (node == NULL)
+ return FALSE;
+ switch (nodeTag(node))
{
- Var *var = (Var *)node;
- if (varno == var->varno &&
- (attnum == var->varattno || attnum == -1))
- return TRUE;
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr*)node;
- return
- nodeThisLockWasTriggered((Node*)expr->args, varno, attnum);
- }
- break;
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *)node;
- return
- nodeThisLockWasTriggered(tle->expr, varno, attnum);
- }
- break;
- case T_List:
- {
- List *l;
+ case T_Var:
+ {
+ Var *var = (Var *) node;
+
+ if (varno == var->varno &&
+ (attnum == var->varattno || attnum == -1))
+ return TRUE;
+ }
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) node;
+
+ return
+ nodeThisLockWasTriggered((Node *) expr->args, varno, attnum);
+ }
+ break;
+ case T_TargetEntry:
+ {
+ TargetEntry *tle = (TargetEntry *) node;
+
+ return
+ nodeThisLockWasTriggered(tle->expr, varno, attnum);
+ }
+ break;
+ case T_List:
+ {
+ List *l;
- foreach(l, (List*)node) {
- if (nodeThisLockWasTriggered(lfirst(l), varno, attnum))
- return TRUE;
- }
- return FALSE;
+ foreach(l, (List *) node)
+ {
+ if (nodeThisLockWasTriggered(lfirst(l), varno, attnum))
+ return TRUE;
+ }
+ return FALSE;
+ }
+ break;
+ default:
+ break;
}
- break;
- default:
- break;
- }
- return (FALSE);
+ return (FALSE);
}
/*
* thisLockWasTriggered -
- * walk the tree, if there we find a varnode, we check the varattno
- * against the attnum if we find at least one such match, we return true
- * otherwise, we return false
+ * walk the tree, if there we find a varnode, we check the varattno
+ * against the attnum if we find at least one such match, we return true
+ * otherwise, we return false
*/
-static bool
+static bool
thisLockWasTriggered(int varno,
- AttrNumber attnum,
- Query *parsetree)
+ AttrNumber attnum,
+ Query * parsetree)
{
- return
+ return
(nodeThisLockWasTriggered(parsetree->qual, varno, attnum) ||
- nodeThisLockWasTriggered((Node*)parsetree->targetList,
- varno, attnum));
+ nodeThisLockWasTriggered((Node *) parsetree->targetList,
+ varno, attnum));
}
/*
* matchLocks -
- * match the list of locks and returns the matching rules
+ * match the list of locks and returns the matching rules
*/
-List *
+List *
matchLocks(CmdType event,
- RuleLock *rulelocks,
- int varno,
- Query *parsetree)
+ RuleLock * rulelocks,
+ int varno,
+ Query * parsetree)
{
- List *real_locks = NIL;
- int nlocks;
- int i;
-
- Assert(rulelocks != NULL); /* we get called iff there is some lock */
- Assert(parsetree != NULL);
-
- if (parsetree->commandType != CMD_SELECT) {
- if (parsetree->resultRelation != varno) {
- return ( NULL );
+ List *real_locks = NIL;
+ int nlocks;
+ int i;
+
+ Assert(rulelocks != NULL); /* we get called iff there is some lock */
+ Assert(parsetree != NULL);
+
+ if (parsetree->commandType != CMD_SELECT)
+ {
+ if (parsetree->resultRelation != varno)
+ {
+ return (NULL);
+ }
}
- }
-
- nlocks = rulelocks->numLocks;
-
- for (i = 0; i < nlocks; i++) {
- RewriteRule *oneLock = rulelocks->rules[i];
- if (oneLock->event == event) {
- if (parsetree->commandType != CMD_SELECT ||
- thisLockWasTriggered(varno,
- oneLock->attrno,
- parsetree)) {
- real_locks = lappend(real_locks, oneLock);
- }
+ nlocks = rulelocks->numLocks;
+
+ for (i = 0; i < nlocks; i++)
+ {
+ RewriteRule *oneLock = rulelocks->rules[i];
+
+ if (oneLock->event == event)
+ {
+ if (parsetree->commandType != CMD_SELECT ||
+ thisLockWasTriggered(varno,
+ oneLock->attrno,
+ parsetree))
+ {
+ real_locks = lappend(real_locks, oneLock);
+ }
+ }
}
- }
-
- return (real_locks);
-}
+ return (real_locks);
+}
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index a9383fe53da..01b05c4cd0e 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* rewriteDefine.c--
- * routines for defining a rewrite rule
+ * routines for defining a rewrite rule
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.3 1997/07/24 20:13:33 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.4 1997/09/07 04:48:05 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,235 +20,252 @@
#include "utils/builtins.h"
#include "utils/elog.h" /* for elog */
#include "utils/palloc.h"
-#include "utils/lsyscache.h" /* for get_typlen */
+#include "utils/lsyscache.h" /* for get_typlen */
#include "nodes/pg_list.h" /* for Lisp support */
#include "nodes/parsenodes.h"
#include "parser/catalog_utils.h"
-#include "rewrite/locks.h"
+#include "rewrite/locks.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
#include "rewrite/rewriteSupport.h"
#include "tcop/tcopprot.h"
-Oid LastOidProcessed = InvalidOid;
+Oid LastOidProcessed = InvalidOid;
/*
* This is too small for many rule plans, but it'll have to do for now.
* Rule plans, etc will eventually have to be large objects.
- *
+ *
* should this be smaller?
*/
-#define RULE_PLAN_SIZE 8192
+#define RULE_PLAN_SIZE 8192
static void
strcpyq(char *dest, char *source)
{
- char *current=source,*destp= dest;
-
- for(current=source; *current; current++) {
- if (*current == '\"') {
- *destp = '\\';
- destp++;
+ char *current = source,
+ *destp = dest;
+
+ for (current = source; *current; current++)
+ {
+ if (*current == '\"')
+ {
+ *destp = '\\';
+ destp++;
+ }
+ *destp = *current;
+ destp++;
}
- *destp = *current;
- destp++;
- }
- *destp = '\0';
+ *destp = '\0';
}
/*
* InsertRule -
- * takes the arguments and inserts them as attributes into the system
- * relation "pg_rewrite"
+ * takes the arguments and inserts them as attributes into the system
+ * relation "pg_rewrite"
*
- * MODS : changes the value of LastOidProcessed as a side
- * effect of inserting the rule tuple
+ * MODS : changes the value of LastOidProcessed as a side
+ * effect of inserting the rule tuple
*
- * ARGS : rulname - name of the rule
- * evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
- * evobj - name of relation
- * evslot - comma delimited list of slots
- * if null => multi-attr rule
- * evinstead - is an instead rule
- * actiontree - parsetree(s) of rule action
+ * ARGS : rulname - name of the rule
+ * evtype - one of RETRIEVE,REPLACE,DELETE,APPEND
+ * evobj - name of relation
+ * evslot - comma delimited list of slots
+ * if null => multi-attr rule
+ * evinstead - is an instead rule
+ * actiontree - parsetree(s) of rule action
*/
-static Oid
+static Oid
InsertRule(char *rulname,
- int evtype,
- char *evobj,
- char *evslot,
- char *evqual,
- bool evinstead,
- char *actiontree)
+ int evtype,
+ char *evobj,
+ char *evslot,
+ char *evqual,
+ bool evinstead,
+ char *actiontree)
{
- static char rulebuf[RULE_PLAN_SIZE];
- static char actionbuf[RULE_PLAN_SIZE];
- static char qualbuf[RULE_PLAN_SIZE];
- Oid eventrel_oid = InvalidOid;
- AttrNumber evslot_index = InvalidAttrNumber;
- Relation eventrel = NULL;
- char *is_instead = "f";
- extern void eval_as_new_xact();
- char *template;
-
- eventrel = heap_openr(evobj);
- if (eventrel == NULL) {
- elog(WARN, "rules cannot be defined on relations not in schema");
- }
- eventrel_oid = RelationGetRelationId(eventrel);
-
- /*
- * if the slotname is null, we know that this is a multi-attr
- * rule
- */
- if (evslot == NULL)
- evslot_index = -1;
- else
- evslot_index = varattno(eventrel, (char*)evslot);
- heap_close(eventrel);
-
- if (evinstead)
- is_instead = "t";
-
- if (evqual == NULL)
- evqual = "nil";
-
- if (IsDefinedRewriteRule(rulname))
- elog(WARN, "Attempt to insert rule '%s' failed: already exists",
- rulname);
- strcpyq(actionbuf,actiontree);
- strcpyq(qualbuf, evqual);
-
- template = "INSERT INTO pg_rewrite \
+ static char rulebuf[RULE_PLAN_SIZE];
+ static char actionbuf[RULE_PLAN_SIZE];
+ static char qualbuf[RULE_PLAN_SIZE];
+ Oid eventrel_oid = InvalidOid;
+ AttrNumber evslot_index = InvalidAttrNumber;
+ Relation eventrel = NULL;
+ char *is_instead = "f";
+ extern void eval_as_new_xact();
+ char *template;
+
+ eventrel = heap_openr(evobj);
+ if (eventrel == NULL)
+ {
+ elog(WARN, "rules cannot be defined on relations not in schema");
+ }
+ eventrel_oid = RelationGetRelationId(eventrel);
+
+ /*
+ * if the slotname is null, we know that this is a multi-attr rule
+ */
+ if (evslot == NULL)
+ evslot_index = -1;
+ else
+ evslot_index = varattno(eventrel, (char *) evslot);
+ heap_close(eventrel);
+
+ if (evinstead)
+ is_instead = "t";
+
+ if (evqual == NULL)
+ evqual = "nil";
+
+ if (IsDefinedRewriteRule(rulname))
+ elog(WARN, "Attempt to insert rule '%s' failed: already exists",
+ rulname);
+ strcpyq(actionbuf, actiontree);
+ strcpyq(qualbuf, evqual);
+
+ template = "INSERT INTO pg_rewrite \
(rulename, ev_type, ev_class, ev_attr, action, ev_qual, is_instead) VALUES \
('%s', %d::char, %d::oid, %d::int2, '%s'::text, '%s'::text, \
'%s'::bool);";
- if (strlen(template) + strlen(rulname) + strlen(actionbuf) +
- strlen(qualbuf) + 20 /* fudge fac */ > RULE_PLAN_SIZE) {
- elog(WARN, "DefineQueryRewrite: rule plan string too big.");
- }
- sprintf(rulebuf, template,
- rulname, evtype, eventrel_oid, evslot_index, actionbuf,
- qualbuf, is_instead);
-
- pg_eval(rulebuf, (char **) NULL, (Oid *) NULL, 0);
-
- return (LastOidProcessed);
+ if (strlen(template) + strlen(rulname) + strlen(actionbuf) +
+ strlen(qualbuf) + 20 /* fudge fac */ > RULE_PLAN_SIZE)
+ {
+ elog(WARN, "DefineQueryRewrite: rule plan string too big.");
+ }
+ sprintf(rulebuf, template,
+ rulname, evtype, eventrel_oid, evslot_index, actionbuf,
+ qualbuf, is_instead);
+
+ pg_eval(rulebuf, (char **) NULL, (Oid *) NULL, 0);
+
+ return (LastOidProcessed);
}
/*
- * for now, event_object must be a single attribute
+ * for now, event_object must be a single attribute
*/
static void
ValidateRule(int event_type,
- char *eobj_string,
- char *eslot_string,
- Node *event_qual,
- List **action,
- int is_instead,
- Oid event_attype)
+ char *eobj_string,
+ char *eslot_string,
+ Node * event_qual,
+ List ** action,
+ int is_instead,
+ Oid event_attype)
{
- if (((event_type == CMD_INSERT) || (event_type == CMD_DELETE)) &&
- eslot_string) {
- elog(WARN,
- "rules not allowed for insert or delete events to an attribute");
- }
-
- if (event_qual && !*action && is_instead)
- elog(WARN,
- "event_quals on 'instead nothing' rules not currently supported");
-
-#if 0
- /* on retrieve to class.attribute do instead nothing is converted
- * to 'on retrieve to class.attribute do instead
- * retrieve (attribute = NULL)'
- * --- this is also a terrible hack that works well -- glass*/
- if (is_instead && !*action && eslot_string && event_type == CMD_SELECT) {
- char *temp_buffer = (char *) palloc(strlen(template)+80);
- sprintf(temp_buffer, template, event_attype,
- get_typlen(event_attype), eslot_string,
- event_attype);
-
- *action = (List*) stringToNode(temp_buffer);
-
- pfree(temp_buffer);
- }
-#endif
+ if (((event_type == CMD_INSERT) || (event_type == CMD_DELETE)) &&
+ eslot_string)
+ {
+ elog(WARN,
+ "rules not allowed for insert or delete events to an attribute");
+ }
+
+ if (event_qual && !*action && is_instead)
+ elog(WARN,
+ "event_quals on 'instead nothing' rules not currently supported");
+
+#if 0
+
+ /*
+ * on retrieve to class.attribute do instead nothing is converted to
+ * 'on retrieve to class.attribute do instead retrieve (attribute =
+ * NULL)' --- this is also a terrible hack that works well -- glass
+ */
+ if (is_instead && !*action && eslot_string && event_type == CMD_SELECT)
+ {
+ char *temp_buffer = (char *) palloc(strlen(template) + 80);
+
+ sprintf(temp_buffer, template, event_attype,
+ get_typlen(event_attype), eslot_string,
+ event_attype);
+
+ *action = (List *) stringToNode(temp_buffer);
+
+ pfree(temp_buffer);
+ }
+#endif
}
void
-DefineQueryRewrite(RuleStmt *stmt)
+DefineQueryRewrite(RuleStmt * stmt)
{
- CmdType event_type = stmt->event;
- Attr *event_obj = stmt->object;
- Node *event_qual = stmt->whereClause;
- bool is_instead = stmt->instead;
- List *action = stmt->actions;
- Relation event_relation = NULL ;
- Oid ruleId;
- Oid ev_relid = 0;
- char *eslot_string = NULL;
- int event_attno = 0;
- Oid event_attype = 0;
- char *actionP, *event_qualP;
-
- if (event_obj->attrs)
- eslot_string = strVal(lfirst(event_obj->attrs));
- else
- eslot_string = NULL;
-
- event_relation = heap_openr(event_obj->relname);
- if ( event_relation == NULL ) {
- elog(WARN, "virtual relations not supported yet");
- }
- ev_relid = RelationGetRelationId(event_relation);
-
- if (eslot_string == NULL) {
- event_attno = -1;
- event_attype = -1; /* XXX - don't care */
- } else {
- event_attno = varattno(event_relation, eslot_string);
- event_attype = att_typeid(event_relation,event_attno);
- }
- heap_close(event_relation);
-
- /* fix bug about instead nothing */
- ValidateRule(event_type, event_obj->relname,
- eslot_string, event_qual, &action,
- is_instead,event_attype);
-
- if (action == NULL) {
- if (!is_instead) return; /* doesn't do anything */
-
- event_qualP = nodeToString(event_qual);
-
- ruleId = InsertRule(stmt->rulename,
- event_type,
- event_obj->relname,
- eslot_string,
- event_qualP,
- true,
- "nil");
- prs2_addToRelation(ev_relid, ruleId, event_type, event_attno, TRUE,
- event_qual, NIL);
-
- } else {
- event_qualP = nodeToString(event_qual);
- actionP = nodeToString(action);
-
- ruleId = InsertRule(stmt->rulename,
- event_type,
- event_obj->relname,
- eslot_string,
- event_qualP,
- is_instead,
- actionP);
-
- /* what is the max size of type text? XXX -- glass */
- if (length(action) > 15 )
- elog(WARN,"max # of actions exceeded");
- prs2_addToRelation(ev_relid, ruleId, event_type, event_attno,
- is_instead, event_qual, action);
- }
-}
+ CmdType event_type = stmt->event;
+ Attr *event_obj = stmt->object;
+ Node *event_qual = stmt->whereClause;
+ bool is_instead = stmt->instead;
+ List *action = stmt->actions;
+ Relation event_relation = NULL;
+ Oid ruleId;
+ Oid ev_relid = 0;
+ char *eslot_string = NULL;
+ int event_attno = 0;
+ Oid event_attype = 0;
+ char *actionP,
+ *event_qualP;
+
+ if (event_obj->attrs)
+ eslot_string = strVal(lfirst(event_obj->attrs));
+ else
+ eslot_string = NULL;
+
+ event_relation = heap_openr(event_obj->relname);
+ if (event_relation == NULL)
+ {
+ elog(WARN, "virtual relations not supported yet");
+ }
+ ev_relid = RelationGetRelationId(event_relation);
+
+ if (eslot_string == NULL)
+ {
+ event_attno = -1;
+ event_attype = -1; /* XXX - don't care */
+ }
+ else
+ {
+ event_attno = varattno(event_relation, eslot_string);
+ event_attype = att_typeid(event_relation, event_attno);
+ }
+ heap_close(event_relation);
+ /* fix bug about instead nothing */
+ ValidateRule(event_type, event_obj->relname,
+ eslot_string, event_qual, &action,
+ is_instead, event_attype);
+
+ if (action == NULL)
+ {
+ if (!is_instead)
+ return; /* doesn't do anything */
+
+ event_qualP = nodeToString(event_qual);
+
+ ruleId = InsertRule(stmt->rulename,
+ event_type,
+ event_obj->relname,
+ eslot_string,
+ event_qualP,
+ true,
+ "nil");
+ prs2_addToRelation(ev_relid, ruleId, event_type, event_attno, TRUE,
+ event_qual, NIL);
+
+ }
+ else
+ {
+ event_qualP = nodeToString(event_qual);
+ actionP = nodeToString(action);
+
+ ruleId = InsertRule(stmt->rulename,
+ event_type,
+ event_obj->relname,
+ eslot_string,
+ event_qualP,
+ is_instead,
+ actionP);
+
+ /* what is the max size of type text? XXX -- glass */
+ if (length(action) > 15)
+ elog(WARN, "max # of actions exceeded");
+ prs2_addToRelation(ev_relid, ruleId, event_type, event_attno,
+ is_instead, event_qual, action);
+ }
+}
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 093451655d0..980956a4807 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.3 1997/08/12 22:53:41 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.4 1997/09/07 04:48:07 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -15,13 +15,13 @@
#include "utils/palloc.h"
#include "utils/elog.h"
#include "utils/rel.h"
-#include "nodes/pg_list.h"
+#include "nodes/pg_list.h"
#include "nodes/primnodes.h"
-#include "parser/parsetree.h" /* for parsetree manipulation */
+#include "parser/parsetree.h" /* for parsetree manipulation */
#include "nodes/parsenodes.h"
-#include "rewrite/rewriteSupport.h"
+#include "rewrite/rewriteSupport.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/locks.h"
@@ -29,529 +29,580 @@
#include "commands/creatinh.h"
#include "access/heapam.h"
-static void ApplyRetrieveRule(Query *parsetree, RewriteRule *rule,
- int rt_index, int relation_level, int *modified);
-static List *fireRules(Query *parsetree, int rt_index, CmdType event,
- bool *instead_flag, List *locks, List **qual_products);
-static List *deepRewriteQuery(Query *parsetree);
+static void
+ApplyRetrieveRule(Query * parsetree, RewriteRule * rule,
+ int rt_index, int relation_level, int *modified);
+static List *
+fireRules(Query * parsetree, int rt_index, CmdType event,
+ bool * instead_flag, List * locks, List ** qual_products);
+static List *deepRewriteQuery(Query * parsetree);
/*
* gatherRewriteMeta -
- * Gather meta information about parsetree, and rule. Fix rule body
- * and qualifier so that they can be mixed with the parsetree and
- * maintain semantic validity
+ * Gather meta information about parsetree, and rule. Fix rule body
+ * and qualifier so that they can be mixed with the parsetree and
+ * maintain semantic validity
*/
static RewriteInfo *
-gatherRewriteMeta(Query *parsetree,
- Query *rule_action,
- Node *rule_qual,
- int rt_index,
- CmdType event,
- bool *instead_flag)
+gatherRewriteMeta(Query * parsetree,
+ Query * rule_action,
+ Node * rule_qual,
+ int rt_index,
+ CmdType event,
+ bool * instead_flag)
{
- RewriteInfo *info;
- int rt_length;
- int result_reln;
-
- info = (RewriteInfo *) palloc(sizeof(RewriteInfo));
- info->rt_index = rt_index;
- info->event = event;
- info->instead_flag = *instead_flag;
- info->rule_action = (Query*)copyObject(rule_action);
- info->rule_qual = (Node*)copyObject(rule_qual);
- if (info->rule_action == NULL) info->nothing = TRUE;
- else {
- info->nothing = FALSE;
- info->action = info->rule_action->commandType;
- info->current_varno = rt_index;
- info->rt = parsetree->rtable;
- rt_length = length(info->rt);
- info->rt = append(info->rt, info->rule_action->rtable);
-
- info->new_varno = PRS2_NEW_VARNO + rt_length;
- OffsetVarNodes(info->rule_action->qual, rt_length);
- OffsetVarNodes((Node*)info->rule_action->targetList, rt_length);
- OffsetVarNodes(info->rule_qual, rt_length);
- ChangeVarNodes((Node*)info->rule_action->qual,
- PRS2_CURRENT_VARNO+rt_length, rt_index);
- ChangeVarNodes((Node*)info->rule_action->targetList,
- PRS2_CURRENT_VARNO+rt_length, rt_index);
- ChangeVarNodes(info->rule_qual,
- PRS2_CURRENT_VARNO+rt_length, rt_index);
-
- /*
- * bug here about replace CURRENT -- sort of
- * replace current is deprecated now so this code shouldn't really
- * need to be so clutzy but.....
- */
- if (info->action != CMD_SELECT) { /* i.e update XXXXX */
- int new_result_reln = 0;
- result_reln = info->rule_action->resultRelation;
- switch (result_reln) {
- case PRS2_CURRENT_VARNO: new_result_reln = rt_index;
- break;
- case PRS2_NEW_VARNO: /* XXX */
- default:
- new_result_reln = result_reln + rt_length;
- break;
- }
- info->rule_action->resultRelation = new_result_reln;
- }
- }
- return info;
+ RewriteInfo *info;
+ int rt_length;
+ int result_reln;
+
+ info = (RewriteInfo *) palloc(sizeof(RewriteInfo));
+ info->rt_index = rt_index;
+ info->event = event;
+ info->instead_flag = *instead_flag;
+ info->rule_action = (Query *) copyObject(rule_action);
+ info->rule_qual = (Node *) copyObject(rule_qual);
+ if (info->rule_action == NULL)
+ info->nothing = TRUE;
+ else
+ {
+ info->nothing = FALSE;
+ info->action = info->rule_action->commandType;
+ info->current_varno = rt_index;
+ info->rt = parsetree->rtable;
+ rt_length = length(info->rt);
+ info->rt = append(info->rt, info->rule_action->rtable);
+
+ info->new_varno = PRS2_NEW_VARNO + rt_length;
+ OffsetVarNodes(info->rule_action->qual, rt_length);
+ OffsetVarNodes((Node *) info->rule_action->targetList, rt_length);
+ OffsetVarNodes(info->rule_qual, rt_length);
+ ChangeVarNodes((Node *) info->rule_action->qual,
+ PRS2_CURRENT_VARNO + rt_length, rt_index);
+ ChangeVarNodes((Node *) info->rule_action->targetList,
+ PRS2_CURRENT_VARNO + rt_length, rt_index);
+ ChangeVarNodes(info->rule_qual,
+ PRS2_CURRENT_VARNO + rt_length, rt_index);
+
+ /*
+ * bug here about replace CURRENT -- sort of replace current is
+ * deprecated now so this code shouldn't really need to be so
+ * clutzy but.....
+ */
+ if (info->action != CMD_SELECT)
+ { /* i.e update XXXXX */
+ int new_result_reln = 0;
+
+ result_reln = info->rule_action->resultRelation;
+ switch (result_reln)
+ {
+ case PRS2_CURRENT_VARNO:
+ new_result_reln = rt_index;
+ break;
+ case PRS2_NEW_VARNO: /* XXX */
+ default:
+ new_result_reln = result_reln + rt_length;
+ break;
+ }
+ info->rule_action->resultRelation = new_result_reln;
+ }
+ }
+ return info;
}
-static List *
-OptimizeRIRRules(List *locks)
+static List *
+OptimizeRIRRules(List * locks)
{
- List *attr_level = NIL, *i;
- List *relation_level = NIL;
-
- foreach (i, locks) {
- RewriteRule *rule_lock = lfirst(i);
-
- if (rule_lock->attrno == -1)
- relation_level = lappend(relation_level, rule_lock);
- else
- attr_level = lappend(attr_level, rule_lock);
- }
- return nconc(relation_level, attr_level);
+ List *attr_level = NIL,
+ *i;
+ List *relation_level = NIL;
+
+ foreach(i, locks)
+ {
+ RewriteRule *rule_lock = lfirst(i);
+
+ if (rule_lock->attrno == -1)
+ relation_level = lappend(relation_level, rule_lock);
+ else
+ attr_level = lappend(attr_level, rule_lock);
+ }
+ return nconc(relation_level, attr_level);
}
/*
* idea is to put instead rules before regular rules so that
* excess semantically queasy queries aren't processed
*/
-static List *
-orderRules(List *locks)
+static List *
+orderRules(List * locks)
{
- List *regular = NIL, *i;
- List *instead_rules = NIL;
-
- foreach (i, locks) {
- RewriteRule *rule_lock = (RewriteRule *)lfirst(i);
-
- if (rule_lock->isInstead)
- instead_rules = lappend(instead_rules, rule_lock);
- else
- regular = lappend(regular, rule_lock);
- }
- return nconc(regular, instead_rules);
+ List *regular = NIL,
+ *i;
+ List *instead_rules = NIL;
+
+ foreach(i, locks)
+ {
+ RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
+
+ if (rule_lock->isInstead)
+ instead_rules = lappend(instead_rules, rule_lock);
+ else
+ regular = lappend(regular, rule_lock);
+ }
+ return nconc(regular, instead_rules);
}
static int
-AllRetrieve(List *actions)
+AllRetrieve(List * actions)
{
- List *n;
-
- foreach(n, actions) {
- Query *pt = lfirst(n);
-
- /*
- * in the old postgres code, we check whether command_type is
- * a consp of '('*'.commandType). but we've never supported transitive
- * closures. Hence removed - ay 10/94.
- */
- if (pt->commandType != CMD_SELECT)
- return false;
- }
- return true;
+ List *n;
+
+ foreach(n, actions)
+ {
+ Query *pt = lfirst(n);
+
+ /*
+ * in the old postgres code, we check whether command_type is a
+ * consp of '('*'.commandType). but we've never supported
+ * transitive closures. Hence removed - ay 10/94.
+ */
+ if (pt->commandType != CMD_SELECT)
+ return false;
+ }
+ return true;
}
-static List *
-FireRetrieveRulesAtQuery(Query *parsetree,
- int rt_index,
- Relation relation,
- bool *instead_flag,
- int rule_flag)
+static List *
+FireRetrieveRulesAtQuery(Query * parsetree,
+ int rt_index,
+ Relation relation,
+ bool * instead_flag,
+ int rule_flag)
{
- List *i, *locks;
- RuleLock *rt_entry_locks = NULL;
- List *work = NIL;
+ List *i,
+ *locks;
+ RuleLock *rt_entry_locks = NULL;
+ List *work = NIL;
- if ((rt_entry_locks = relation->rd_rules) == NULL)
- return NIL;
-
- locks = matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
-
- /* find all retrieve instead */
- foreach (i, locks) {
- RewriteRule *rule_lock = (RewriteRule *)lfirst(i);
-
- if (!rule_lock->isInstead)
- continue;
- work = lappend(work, rule_lock);
- }
- if (work != NIL) {
- work = OptimizeRIRRules(locks);
- foreach (i, work) {
- RewriteRule *rule_lock = lfirst(i);
- int relation_level;
- int modified = FALSE;
-
- relation_level = (rule_lock->attrno == -1);
- if (rule_lock->actions == NIL) {
- *instead_flag = TRUE;
+ if ((rt_entry_locks = relation->rd_rules) == NULL)
return NIL;
- }
- if (!rule_flag &&
- length(rule_lock->actions) >= 2 &&
- AllRetrieve(rule_lock->actions)) {
- *instead_flag = TRUE;
- return rule_lock->actions;
- }
- ApplyRetrieveRule(parsetree, rule_lock, rt_index, relation_level,
- &modified);
- if (modified) {
- *instead_flag = TRUE;
- FixResdomTypes(parsetree->targetList);
- return lcons(parsetree,NIL);
- }
+
+ locks = matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
+
+ /* find all retrieve instead */
+ foreach(i, locks)
+ {
+ RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
+
+ if (!rule_lock->isInstead)
+ continue;
+ work = lappend(work, rule_lock);
+ }
+ if (work != NIL)
+ {
+ work = OptimizeRIRRules(locks);
+ foreach(i, work)
+ {
+ RewriteRule *rule_lock = lfirst(i);
+ int relation_level;
+ int modified = FALSE;
+
+ relation_level = (rule_lock->attrno == -1);
+ if (rule_lock->actions == NIL)
+ {
+ *instead_flag = TRUE;
+ return NIL;
+ }
+ if (!rule_flag &&
+ length(rule_lock->actions) >= 2 &&
+ AllRetrieve(rule_lock->actions))
+ {
+ *instead_flag = TRUE;
+ return rule_lock->actions;
+ }
+ ApplyRetrieveRule(parsetree, rule_lock, rt_index, relation_level,
+ &modified);
+ if (modified)
+ {
+ *instead_flag = TRUE;
+ FixResdomTypes(parsetree->targetList);
+ return lcons(parsetree, NIL);
+ }
+ }
}
- }
- return NIL;
-}
+ return NIL;
+}
/* Idea is like this:
*
* retrieve-instead-retrieve rules have different semantics than update nodes
- * Separate RIR rules from others. Pass others to FireRules.
+ * Separate RIR rules from others. Pass others to FireRules.
* Order RIR rules and process.
*
* side effect: parsetree's rtable field might be changed
*/
static void
-ApplyRetrieveRule(Query *parsetree,
- RewriteRule *rule,
- int rt_index,
- int relation_level,
- int *modified)
+ApplyRetrieveRule(Query * parsetree,
+ RewriteRule * rule,
+ int rt_index,
+ int relation_level,
+ int *modified)
{
- Query *rule_action = NULL;
- Node *rule_qual;
- List *rtable, *rt;
- int nothing, rt_length;
- int badsql= FALSE;
-
- rule_qual = rule->qual;
- if (rule->actions) {
- if (length(rule->actions) > 1) /* ??? because we don't handle rules
- with more than one action? -ay */
- return;
- rule_action = copyObject(lfirst(rule->actions));
- nothing = FALSE;
- } else {
- nothing = TRUE;
- }
-
- rtable = copyObject(parsetree->rtable);
- foreach (rt, rtable) {
- RangeTblEntry *rte = lfirst(rt);
- /*
- * this is to prevent add_missing_vars_to_base_rels() from
- * adding a bogus entry to the new target list.
- */
- rte->inFromCl = false;
- }
- rt_length = length(rtable);
- rtable = nconc(rtable, copyObject(rule_action->rtable));
- parsetree->rtable = rtable;
-
- rule_action->rtable = rtable;
- OffsetVarNodes(rule_action->qual, rt_length);
- OffsetVarNodes((Node*)rule_action->targetList, rt_length);
- OffsetVarNodes(rule_qual, rt_length);
- ChangeVarNodes(rule_action->qual,
- PRS2_CURRENT_VARNO+rt_length, rt_index);
- ChangeVarNodes((Node*)rule_action->targetList,
- PRS2_CURRENT_VARNO+rt_length, rt_index);
- ChangeVarNodes(rule_qual, PRS2_CURRENT_VARNO+rt_length, rt_index);
- if (relation_level) {
- HandleViewRule(parsetree, rtable, rule_action->targetList, rt_index,
- modified);
- } else {
- HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList,
- rt_index, rule->attrno, modified, &badsql);
- }
- if (*modified && !badsql)
- AddQual(parsetree, rule_action->qual);
+ Query *rule_action = NULL;
+ Node *rule_qual;
+ List *rtable,
+ *rt;
+ int nothing,
+ rt_length;
+ int badsql = FALSE;
+
+ rule_qual = rule->qual;
+ if (rule->actions)
+ {
+ if (length(rule->actions) > 1) /* ??? because we don't handle
+ * rules with more than one
+ * action? -ay */
+ return;
+ rule_action = copyObject(lfirst(rule->actions));
+ nothing = FALSE;
+ }
+ else
+ {
+ nothing = TRUE;
+ }
+
+ rtable = copyObject(parsetree->rtable);
+ foreach(rt, rtable)
+ {
+ RangeTblEntry *rte = lfirst(rt);
+
+ /*
+ * this is to prevent add_missing_vars_to_base_rels() from adding
+ * a bogus entry to the new target list.
+ */
+ rte->inFromCl = false;
+ }
+ rt_length = length(rtable);
+ rtable = nconc(rtable, copyObject(rule_action->rtable));
+ parsetree->rtable = rtable;
+
+ rule_action->rtable = rtable;
+ OffsetVarNodes(rule_action->qual, rt_length);
+ OffsetVarNodes((Node *) rule_action->targetList, rt_length);
+ OffsetVarNodes(rule_qual, rt_length);
+ ChangeVarNodes(rule_action->qual,
+ PRS2_CURRENT_VARNO + rt_length, rt_index);
+ ChangeVarNodes((Node *) rule_action->targetList,
+ PRS2_CURRENT_VARNO + rt_length, rt_index);
+ ChangeVarNodes(rule_qual, PRS2_CURRENT_VARNO + rt_length, rt_index);
+ if (relation_level)
+ {
+ HandleViewRule(parsetree, rtable, rule_action->targetList, rt_index,
+ modified);
+ }
+ else
+ {
+ HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList,
+ rt_index, rule->attrno, modified, &badsql);
+ }
+ if (*modified && !badsql)
+ AddQual(parsetree, rule_action->qual);
}
-static List *
-ProcessRetrieveQuery(Query *parsetree,
- List *rtable,
- bool *instead_flag,
- bool rule)
+static List *
+ProcessRetrieveQuery(Query * parsetree,
+ List * rtable,
+ bool * instead_flag,
+ bool rule)
{
- List *rt;
- List *product_queries = NIL;
- int rt_index = 0;
-
- foreach (rt, rtable) {
- RangeTblEntry *rt_entry = lfirst(rt);
- Relation rt_entry_relation = NULL;
- List *result = NIL;
-
- rt_index++;
- rt_entry_relation = heap_openr(rt_entry->relname);
-
- if (rt_entry_relation->rd_rules != NULL) {
- result =
- FireRetrieveRulesAtQuery(parsetree,
- rt_index,
- rt_entry_relation,
- instead_flag,
- rule);
+ List *rt;
+ List *product_queries = NIL;
+ int rt_index = 0;
+
+ foreach(rt, rtable)
+ {
+ RangeTblEntry *rt_entry = lfirst(rt);
+ Relation rt_entry_relation = NULL;
+ List *result = NIL;
+
+ rt_index++;
+ rt_entry_relation = heap_openr(rt_entry->relname);
+
+ if (rt_entry_relation->rd_rules != NULL)
+ {
+ result =
+ FireRetrieveRulesAtQuery(parsetree,
+ rt_index,
+ rt_entry_relation,
+ instead_flag,
+ rule);
+ }
+ heap_close(rt_entry_relation);
+ if (*instead_flag)
+ return result;
}
- heap_close(rt_entry_relation);
- if (*instead_flag)
- return result;
- }
- if (rule)
- return NIL;
+ if (rule)
+ return NIL;
- foreach (rt, rtable) {
- RangeTblEntry *rt_entry = lfirst(rt);
- Relation rt_entry_relation = NULL;
- RuleLock *rt_entry_locks = NULL;
- List *result = NIL;
- List *locks = NIL;
- List *dummy_products;
-
- rt_index++;
- rt_entry_relation = heap_openr(rt_entry->relname);
- rt_entry_locks = rt_entry_relation->rd_rules;
- heap_close(rt_entry_relation);
-
- if (rt_entry_locks) {
- locks =
- matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
+ foreach(rt, rtable)
+ {
+ RangeTblEntry *rt_entry = lfirst(rt);
+ Relation rt_entry_relation = NULL;
+ RuleLock *rt_entry_locks = NULL;
+ List *result = NIL;
+ List *locks = NIL;
+ List *dummy_products;
+
+ rt_index++;
+ rt_entry_relation = heap_openr(rt_entry->relname);
+ rt_entry_locks = rt_entry_relation->rd_rules;
+ heap_close(rt_entry_relation);
+
+ if (rt_entry_locks)
+ {
+ locks =
+ matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
+ }
+ if (locks != NIL)
+ {
+ result = fireRules(parsetree, rt_index, CMD_SELECT,
+ instead_flag, locks, &dummy_products);
+ if (*instead_flag)
+ return lappend(NIL, result);
+ if (result != NIL)
+ product_queries = nconc(product_queries, result);
+ }
}
- if (locks != NIL) {
- result = fireRules(parsetree, rt_index, CMD_SELECT,
- instead_flag, locks, &dummy_products);
- if (*instead_flag)
- return lappend(NIL, result);
- if (result != NIL)
- product_queries = nconc(product_queries, result);
- }
- }
- return product_queries;
+ return product_queries;
}
-static Query *
-CopyAndAddQual(Query *parsetree,
- List *actions,
- Node *rule_qual,
- int rt_index,
- CmdType event)
+static Query *
+CopyAndAddQual(Query * parsetree,
+ List * actions,
+ Node * rule_qual,
+ int rt_index,
+ CmdType event)
{
- Query *new_tree = (Query *) copyObject(parsetree);
- Node *new_qual = NULL;
- Query *rule_action = NULL;
-
- if (actions)
- rule_action = lfirst(actions);
- if (rule_qual != NULL)
- new_qual = (Node *)copyObject(rule_qual);
- if (rule_action != NULL) {
- List *rtable;
- int rt_length;
-
- rtable = new_tree->rtable;
- rt_length = length(rtable);
- rtable = append(rtable,listCopy(rule_action->rtable));
- new_tree->rtable = rtable;
- OffsetVarNodes(new_qual, rt_length);
- ChangeVarNodes(new_qual, PRS2_CURRENT_VARNO+rt_length, rt_index);
- }
- /* XXX -- where current doesn't work for instead nothing.... yet*/
- AddNotQual(new_tree, new_qual);
-
- return new_tree;
+ Query *new_tree = (Query *) copyObject(parsetree);
+ Node *new_qual = NULL;
+ Query *rule_action = NULL;
+
+ if (actions)
+ rule_action = lfirst(actions);
+ if (rule_qual != NULL)
+ new_qual = (Node *) copyObject(rule_qual);
+ if (rule_action != NULL)
+ {
+ List *rtable;
+ int rt_length;
+
+ rtable = new_tree->rtable;
+ rt_length = length(rtable);
+ rtable = append(rtable, listCopy(rule_action->rtable));
+ new_tree->rtable = rtable;
+ OffsetVarNodes(new_qual, rt_length);
+ ChangeVarNodes(new_qual, PRS2_CURRENT_VARNO + rt_length, rt_index);
+ }
+ /* XXX -- where current doesn't work for instead nothing.... yet */
+ AddNotQual(new_tree, new_qual);
+
+ return new_tree;
}
/*
- * fireRules -
- * Iterate through rule locks applying rules. After an instead rule
- * rule has been applied, return just new parsetree and let RewriteQuery
- * start the process all over again. The locks are reordered to maintain
- * sensible semantics. remember: reality is for dead birds -- glass
+ * fireRules -
+ * Iterate through rule locks applying rules. After an instead rule
+ * rule has been applied, return just new parsetree and let RewriteQuery
+ * start the process all over again. The locks are reordered to maintain
+ * sensible semantics. remember: reality is for dead birds -- glass
*
*/
-static List *
-fireRules(Query *parsetree,
- int rt_index,
- CmdType event,
- bool *instead_flag,
- List *locks,
- List **qual_products)
+static List *
+fireRules(Query * parsetree,
+ int rt_index,
+ CmdType event,
+ bool * instead_flag,
+ List * locks,
+ List ** qual_products)
{
- RewriteInfo *info;
- List *results = NIL;
- List *i;
-
- /* choose rule to fire from list of rules */
- if (locks == NIL) {
- ProcessRetrieveQuery(parsetree,
- parsetree->rtable,
- instead_flag, TRUE);
- if (*instead_flag)
- return lappend(NIL, parsetree);
- else
- return NIL;
- }
-
- locks = orderRules(locks); /* instead rules first */
- foreach (i, locks) {
- RewriteRule *rule_lock = (RewriteRule *)lfirst(i);
- Node *qual, *event_qual;
- List *actions;
- List *r;
- bool orig_instead_flag = *instead_flag;
-
- /* multiple rule action time */
- *instead_flag = rule_lock->isInstead;
- event_qual = rule_lock->qual;
- actions = rule_lock->actions;
- if (event_qual != NULL && *instead_flag)
- *qual_products =
- lappend(*qual_products,
- CopyAndAddQual(parsetree, actions, event_qual,
- rt_index, event));
- foreach (r, actions) {
- Query *rule_action = lfirst(r);
- Node *rule_qual = copyObject(event_qual);
-
- /*--------------------------------------------------
- * Step 1:
- * Rewrite current.attribute or current to tuple variable
- * this appears to be done in parser?
- *--------------------------------------------------
- */
- info = gatherRewriteMeta(parsetree, rule_action, rule_qual,
- rt_index,event,instead_flag);
-
- /* handle escapable cases, or those handled by other code */
- if (info->nothing) {
+ RewriteInfo *info;
+ List *results = NIL;
+ List *i;
+
+ /* choose rule to fire from list of rules */
+ if (locks == NIL)
+ {
+ ProcessRetrieveQuery(parsetree,
+ parsetree->rtable,
+ instead_flag, TRUE);
if (*instead_flag)
- return NIL;
+ return lappend(NIL, parsetree);
else
- continue;
- }
-
- if (info->action == info->event &&
- info->event == CMD_SELECT)
- continue;
-
- /*
- * Event Qualification forces copying of parsetree --- XXX
- * and splitting into two queries one w/rule_qual, one
- * w/NOT rule_qual. Also add user query qual onto rule action
- */
- qual = parsetree->qual;
- AddQual(info->rule_action, qual);
-
- if (info->rule_qual != NULL)
- AddQual(info->rule_action, info->rule_qual);
-
- /*--------------------------------------------------
- * Step 2:
- * Rewrite new.attribute w/ right hand side of target-list
- * entry for appropriate field name in insert/update
- *--------------------------------------------------
- */
- if ((info->event == CMD_INSERT) || (info->event == CMD_UPDATE)) {
- FixNew(info, parsetree);
- }
-
- /*--------------------------------------------------
- * Step 3:
- * rewriting due to retrieve rules
- *--------------------------------------------------
- */
- info->rule_action->rtable = info->rt;
- ProcessRetrieveQuery(info->rule_action, info->rt,
- &orig_instead_flag, TRUE);
-
- /*--------------------------------------------------
- * Step 4
- * Simplify? hey, no algorithm for simplification... let
- * the planner do it.
- *--------------------------------------------------
- */
- results = lappend(results, info->rule_action);
-
- pfree(info);
+ return NIL;
}
- if (*instead_flag) break;
- }
- return results;
+
+ locks = orderRules(locks); /* instead rules first */
+ foreach(i, locks)
+ {
+ RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
+ Node *qual,
+ *event_qual;
+ List *actions;
+ List *r;
+ bool orig_instead_flag = *instead_flag;
+
+ /* multiple rule action time */
+ *instead_flag = rule_lock->isInstead;
+ event_qual = rule_lock->qual;
+ actions = rule_lock->actions;
+ if (event_qual != NULL && *instead_flag)
+ *qual_products =
+ lappend(*qual_products,
+ CopyAndAddQual(parsetree, actions, event_qual,
+ rt_index, event));
+ foreach(r, actions)
+ {
+ Query *rule_action = lfirst(r);
+ Node *rule_qual = copyObject(event_qual);
+
+ /*--------------------------------------------------
+ * Step 1:
+ * Rewrite current.attribute or current to tuple variable
+ * this appears to be done in parser?
+ *--------------------------------------------------
+ */
+ info = gatherRewriteMeta(parsetree, rule_action, rule_qual,
+ rt_index, event, instead_flag);
+
+ /* handle escapable cases, or those handled by other code */
+ if (info->nothing)
+ {
+ if (*instead_flag)
+ return NIL;
+ else
+ continue;
+ }
+
+ if (info->action == info->event &&
+ info->event == CMD_SELECT)
+ continue;
+
+ /*
+ * Event Qualification forces copying of parsetree --- XXX and
+ * splitting into two queries one w/rule_qual, one w/NOT
+ * rule_qual. Also add user query qual onto rule action
+ */
+ qual = parsetree->qual;
+ AddQual(info->rule_action, qual);
+
+ if (info->rule_qual != NULL)
+ AddQual(info->rule_action, info->rule_qual);
+
+ /*--------------------------------------------------
+ * Step 2:
+ * Rewrite new.attribute w/ right hand side of target-list
+ * entry for appropriate field name in insert/update
+ *--------------------------------------------------
+ */
+ if ((info->event == CMD_INSERT) || (info->event == CMD_UPDATE))
+ {
+ FixNew(info, parsetree);
+ }
+
+ /*--------------------------------------------------
+ * Step 3:
+ * rewriting due to retrieve rules
+ *--------------------------------------------------
+ */
+ info->rule_action->rtable = info->rt;
+ ProcessRetrieveQuery(info->rule_action, info->rt,
+ &orig_instead_flag, TRUE);
+
+ /*--------------------------------------------------
+ * Step 4
+ * Simplify? hey, no algorithm for simplification... let
+ * the planner do it.
+ *--------------------------------------------------
+ */
+ results = lappend(results, info->rule_action);
+
+ pfree(info);
+ }
+ if (*instead_flag)
+ break;
+ }
+ return results;
}
-static List *
-RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
+static List *
+RewriteQuery(Query * parsetree, bool * instead_flag, List ** qual_products)
{
- CmdType event;
- List *product_queries = NIL;
- int result_relation = 0;
-
- Assert(parsetree != NULL);
-
- event = parsetree->commandType;
-
- if (event == CMD_UTILITY)
- return NIL;
+ CmdType event;
+ List *product_queries = NIL;
+ int result_relation = 0;
- /*
- * only for a delete may the targetlist be NULL
- */
- if (event != CMD_DELETE) {
- Assert(parsetree->targetList != NULL);
- }
-
- result_relation = parsetree->resultRelation;
+ Assert(parsetree != NULL);
+
+ event = parsetree->commandType;
+
+ if (event == CMD_UTILITY)
+ return NIL;
- if (event != CMD_SELECT) {
/*
- * the statement is an update, insert or delete
+ * only for a delete may the targetlist be NULL
*/
- RangeTblEntry *rt_entry;
- Relation rt_entry_relation = NULL;
- RuleLock *rt_entry_locks = NULL;
-
- rt_entry = rt_fetch(result_relation, parsetree->rtable);
- rt_entry_relation = heap_openr(rt_entry->relname);
- rt_entry_locks = rt_entry_relation->rd_rules;
- heap_close(rt_entry_relation);
-
- if (rt_entry_locks != NULL) {
- List *locks =
- matchLocks(event, rt_entry_locks, result_relation, parsetree);
-
- product_queries =
- fireRules(parsetree,
- result_relation,
- event,
- instead_flag,
- locks,
- qual_products);
+ if (event != CMD_DELETE)
+ {
+ Assert(parsetree->targetList != NULL);
+ }
+
+ result_relation = parsetree->resultRelation;
+
+ if (event != CMD_SELECT)
+ {
+
+ /*
+ * the statement is an update, insert or delete
+ */
+ RangeTblEntry *rt_entry;
+ Relation rt_entry_relation = NULL;
+ RuleLock *rt_entry_locks = NULL;
+
+ rt_entry = rt_fetch(result_relation, parsetree->rtable);
+ rt_entry_relation = heap_openr(rt_entry->relname);
+ rt_entry_locks = rt_entry_relation->rd_rules;
+ heap_close(rt_entry_relation);
+
+ if (rt_entry_locks != NULL)
+ {
+ List *locks =
+ matchLocks(event, rt_entry_locks, result_relation, parsetree);
+
+ product_queries =
+ fireRules(parsetree,
+ result_relation,
+ event,
+ instead_flag,
+ locks,
+ qual_products);
+ }
+ return product_queries;
+ }
+ else
+ {
+
+ /*
+ * the statement is a select
+ */
+ Query *other;
+
+ other = copyObject(parsetree); /* ApplyRetrieveRule changes the
+ * range table */
+ return
+ ProcessRetrieveQuery(other, parsetree->rtable,
+ instead_flag, FALSE);
}
- return product_queries;
- }else {
- /*
- * the statement is a select
- */
- Query *other;
-
- other = copyObject(parsetree); /* ApplyRetrieveRule changes the
- range table */
- return
- ProcessRetrieveQuery(other, parsetree->rtable,
- instead_flag, FALSE);
- }
}
/*
@@ -559,61 +610,62 @@ RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
* can be rewritten. Detecting cycles is left for the reader as an excercise.
*/
#ifndef REWRITE_INVOKE_MAX
-#define REWRITE_INVOKE_MAX 10
+#define REWRITE_INVOKE_MAX 10
#endif
-static int numQueryRewriteInvoked = 0;
+static int numQueryRewriteInvoked = 0;
/*
* QueryRewrite -
- * rewrite one query via QueryRewrite system, possibly returning 0, or many
- * queries
- */
-List *
-QueryRewrite(Query *parsetree)
+ * rewrite one query via QueryRewrite system, possibly returning 0, or many
+ * queries
+ */
+List *
+QueryRewrite(Query * parsetree)
{
- numQueryRewriteInvoked = 0;
+ numQueryRewriteInvoked = 0;
- /*
- * take a deep breath and apply all the rewrite rules - ay
- */
- return deepRewriteQuery(parsetree);
+ /*
+ * take a deep breath and apply all the rewrite rules - ay
+ */
+ return deepRewriteQuery(parsetree);
}
/*
* deepRewriteQuery -
- * rewrites the query and apply the rules again on the queries rewritten
+ * rewrites the query and apply the rules again on the queries rewritten
*/
-static List *
-deepRewriteQuery(Query *parsetree)
+static List *
+deepRewriteQuery(Query * parsetree)
{
- List *n;
- List *rewritten = NIL;
- List *result = NIL;
- bool instead;
- List *qual_products = NIL;
-
- if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX) {
- elog(WARN, "query rewritten %d times, may contain cycles",
- numQueryRewriteInvoked-1);
- }
-
- instead = FALSE;
- result = RewriteQuery(parsetree, &instead, &qual_products);
- if (!instead)
- rewritten = lcons(parsetree, NIL);
-
- foreach(n, result) {
- Query *pt = lfirst(n);
- List *newstuff = NIL;
-
- newstuff = deepRewriteQuery(pt);
- if (newstuff != NIL)
- rewritten = nconc(rewritten, newstuff);
- }
- if (qual_products != NIL)
- rewritten = nconc(rewritten, qual_products);
-
- return rewritten;
-}
+ List *n;
+ List *rewritten = NIL;
+ List *result = NIL;
+ bool instead;
+ List *qual_products = NIL;
+
+ if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
+ {
+ elog(WARN, "query rewritten %d times, may contain cycles",
+ numQueryRewriteInvoked - 1);
+ }
+
+ instead = FALSE;
+ result = RewriteQuery(parsetree, &instead, &qual_products);
+ if (!instead)
+ rewritten = lcons(parsetree, NIL);
+ foreach(n, result)
+ {
+ Query *pt = lfirst(n);
+ List *newstuff = NIL;
+
+ newstuff = deepRewriteQuery(pt);
+ if (newstuff != NIL)
+ rewritten = nconc(rewritten, newstuff);
+ }
+ if (qual_products != NIL)
+ rewritten = nconc(rewritten, qual_products);
+
+ return rewritten;
+}
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 01fad29f773..b8b39b33281 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.4 1996/11/10 03:02:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.5 1997/09/07 04:48:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,7 @@
#include "nodes/nodes.h"
#include "nodes/relation.h"
#include "nodes/primnodes.h"
-#include "parser/parsetree.h" /* for getrelid() */
+#include "parser/parsetree.h" /* for getrelid() */
#include "utils/lsyscache.h"
#include "utils/builtins.h"
#include "rewrite/rewriteHandler.h"
@@ -28,410 +28,463 @@
#include "nodes/plannodes.h"
#include "optimizer/clauses.h"
-static void ResolveNew(RewriteInfo *info, List *targetlist, Node **node);
+static void ResolveNew(RewriteInfo * info, List * targetlist, Node ** node);
void
-OffsetVarNodes(Node *node, int offset)
+OffsetVarNodes(Node * node, int offset)
{
- if (node==NULL)
- return;
- switch (nodeTag(node)) {
- case T_TargetEntry:
+ if (node == NULL)
+ return;
+ switch (nodeTag(node))
{
- TargetEntry *tle = (TargetEntry *)node;
- OffsetVarNodes(tle->expr, offset);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr*)node;
- OffsetVarNodes((Node*)expr->args, offset);
- }
- break;
- case T_Var:
- {
- Var *var = (Var*)node;
- var->varno += offset;
- var->varnoold += offset;
- }
- break;
- case T_List:
- {
- List *l;
+ case T_TargetEntry:
+ {
+ TargetEntry *tle = (TargetEntry *) node;
+
+ OffsetVarNodes(tle->expr, offset);
+ }
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) node;
- foreach(l, (List*)node) {
- OffsetVarNodes(lfirst(l), offset);
- }
+ OffsetVarNodes((Node *) expr->args, offset);
+ }
+ break;
+ case T_Var:
+ {
+ Var *var = (Var *) node;
+
+ var->varno += offset;
+ var->varnoold += offset;
+ }
+ break;
+ case T_List:
+ {
+ List *l;
+
+ foreach(l, (List *) node)
+ {
+ OffsetVarNodes(lfirst(l), offset);
+ }
+ }
+ break;
+ default:
+ /* ignore the others */
+ break;
}
- break;
- default:
- /* ignore the others */
- break;
- }
}
void
-ChangeVarNodes(Node *node, int old_varno, int new_varno)
+ChangeVarNodes(Node * node, int old_varno, int new_varno)
{
- if (node==NULL)
- return;
- switch (nodeTag(node)) {
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *)node;
- ChangeVarNodes(tle->expr, old_varno, new_varno);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr*)node;
- ChangeVarNodes((Node*)expr->args, old_varno, new_varno);
- }
- break;
- case T_Var:
+ if (node == NULL)
+ return;
+ switch (nodeTag(node))
{
- Var *var = (Var*)node;
- if (var->varno == old_varno) {
- var->varno = new_varno;
- var->varnoold = new_varno;
- }
- }
- break;
- case T_List:
- {
- List *l;
- foreach (l, (List*)node) {
- ChangeVarNodes(lfirst(l), old_varno, new_varno);
- }
+ case T_TargetEntry:
+ {
+ TargetEntry *tle = (TargetEntry *) node;
+
+ ChangeVarNodes(tle->expr, old_varno, new_varno);
+ }
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) node;
+
+ ChangeVarNodes((Node *) expr->args, old_varno, new_varno);
+ }
+ break;
+ case T_Var:
+ {
+ Var *var = (Var *) node;
+
+ if (var->varno == old_varno)
+ {
+ var->varno = new_varno;
+ var->varnoold = new_varno;
+ }
+ }
+ break;
+ case T_List:
+ {
+ List *l;
+
+ foreach(l, (List *) node)
+ {
+ ChangeVarNodes(lfirst(l), old_varno, new_varno);
+ }
+ }
+ break;
+ default:
+ /* ignore the others */
+ break;
}
- break;
- default:
- /* ignore the others */
- break;
- }
}
void
-AddQual(Query *parsetree, Node *qual)
+AddQual(Query * parsetree, Node * qual)
{
- Node *copy, *old;
-
- if (qual == NULL)
- return;
-
- copy = copyObject(qual);
- old = parsetree->qual;
- if (old == NULL)
- parsetree->qual = copy;
- else
- parsetree->qual =
- (Node*)make_andclause(makeList(parsetree->qual, copy, -1));
+ Node *copy,
+ *old;
+
+ if (qual == NULL)
+ return;
+
+ copy = copyObject(qual);
+ old = parsetree->qual;
+ if (old == NULL)
+ parsetree->qual = copy;
+ else
+ parsetree->qual =
+ (Node *) make_andclause(makeList(parsetree->qual, copy, -1));
}
void
-AddNotQual(Query *parsetree, Node *qual)
+AddNotQual(Query * parsetree, Node * qual)
{
- Node *copy;
-
- if (qual == NULL) return;
-
- copy = (Node*)make_notclause(copyObject(qual));
+ Node *copy;
- AddQual(parsetree,copy);
+ if (qual == NULL)
+ return;
+
+ copy = (Node *) make_notclause(copyObject(qual));
+
+ AddQual(parsetree, copy);
}
-static Node *
+static Node *
make_null(Oid type)
{
- Const *c = makeNode(Const);
-
- c->consttype = type;
- c->constlen = get_typlen(type);
- c->constvalue = PointerGetDatum(NULL);
- c->constisnull = true;
- c->constbyval = get_typbyval(type);
- return (Node*)c;
+ Const *c = makeNode(Const);
+
+ c->consttype = type;
+ c->constlen = get_typlen(type);
+ c->constvalue = PointerGetDatum(NULL);
+ c->constisnull = true;
+ c->constbyval = get_typbyval(type);
+ return (Node *) c;
}
void
-FixResdomTypes (List *tlist)
+FixResdomTypes(List * tlist)
{
- List *i;
+ List *i;
- foreach (i, tlist) {
- TargetEntry *tle = lfirst(i);
+ foreach(i, tlist)
+ {
+ TargetEntry *tle = lfirst(i);
- if (nodeTag(tle->expr) == T_Var) {
- Var *var = (Var*)tle->expr;
+ if (nodeTag(tle->expr) == T_Var)
+ {
+ Var *var = (Var *) tle->expr;
- tle->resdom->restype = var->vartype;
- tle->resdom->reslen = get_typlen(var->vartype);
+ tle->resdom->restype = var->vartype;
+ tle->resdom->reslen = get_typlen(var->vartype);
+ }
}
- }
}
-static Node *
-FindMatchingNew(List *tlist, int attno)
+static Node *
+FindMatchingNew(List * tlist, int attno)
{
- List *i;
-
- foreach (i, tlist ) {
- TargetEntry *tle = lfirst(i);
+ List *i;
- if (tle->resdom->resno == attno ) {
- return (tle->expr);
+ foreach(i, tlist)
+ {
+ TargetEntry *tle = lfirst(i);
+
+ if (tle->resdom->resno == attno)
+ {
+ return (tle->expr);
+ }
}
- }
- return NULL;
+ return NULL;
}
-static Node *
-FindMatchingTLEntry(List *tlist, char *e_attname)
+static Node *
+FindMatchingTLEntry(List * tlist, char *e_attname)
{
- List *i;
-
- foreach (i, tlist) {
- TargetEntry *tle = lfirst(i);
- char *resname;
-
- resname = tle->resdom->resname;
- if (!strcmp(e_attname, resname))
- return (tle->expr);
- }
- return NULL;
+ List *i;
+
+ foreach(i, tlist)
+ {
+ TargetEntry *tle = lfirst(i);
+ char *resname;
+
+ resname = tle->resdom->resname;
+ if (!strcmp(e_attname, resname))
+ return (tle->expr);
+ }
+ return NULL;
}
static void
-ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr)
+ResolveNew(RewriteInfo * info, List * targetlist, Node ** nodePtr)
{
- Node *node = *nodePtr;
-
- if (node == NULL)
- return;
-
- switch(nodeTag(node)) {
- case T_TargetEntry:
- ResolveNew(info, targetlist, &((TargetEntry*)node)->expr);
- break;
- case T_Expr:
- ResolveNew(info, targetlist, (Node**)(&(((Expr*)node)->args)));
- break;
- case T_Var: {
- int this_varno = (int)((Var*)node)->varno;
- Node *n;
-
- if (this_varno == info->new_varno) {
- n = FindMatchingNew(targetlist,
- ((Var*)node)->varattno);
- if (n == NULL) {
- if (info->event == CMD_UPDATE) {
- ((Var*)node)->varno = info->current_varno;
- ((Var*)node)->varnoold = info->current_varno;
- } else {
- *nodePtr = make_null(((Var*)node)->vartype);
+ Node *node = *nodePtr;
+
+ if (node == NULL)
+ return;
+
+ switch (nodeTag(node))
+ {
+ case T_TargetEntry:
+ ResolveNew(info, targetlist, &((TargetEntry *) node)->expr);
+ break;
+ case T_Expr:
+ ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)));
+ break;
+ case T_Var:
+ {
+ int this_varno = (int) ((Var *) node)->varno;
+ Node *n;
+
+ if (this_varno == info->new_varno)
+ {
+ n = FindMatchingNew(targetlist,
+ ((Var *) node)->varattno);
+ if (n == NULL)
+ {
+ if (info->event == CMD_UPDATE)
+ {
+ ((Var *) node)->varno = info->current_varno;
+ ((Var *) node)->varnoold = info->current_varno;
+ }
+ else
+ {
+ *nodePtr = make_null(((Var *) node)->vartype);
+ }
+ }
+ else
+ {
+ *nodePtr = n;
+ }
+ }
+ break;
}
- } else {
- *nodePtr = n;
- }
- }
- break;
- }
- case T_List: {
- List *l;
- foreach(l, (List*)node) {
- ResolveNew(info, targetlist, (Node**)&(lfirst(l)));
+ case T_List:
+ {
+ List *l;
+
+ foreach(l, (List *) node)
+ {
+ ResolveNew(info, targetlist, (Node **) & (lfirst(l)));
+ }
+ break;
+ }
+ default:
+ /* ignore the others */
+ break;
}
- break;
- }
- default:
- /* ignore the others */
- break;
- }
}
void
-FixNew(RewriteInfo* info, Query *parsetree)
+FixNew(RewriteInfo * info, Query * parsetree)
{
- ResolveNew(info, parsetree->targetList,
- (Node**)&(info->rule_action->targetList));
- ResolveNew(info, parsetree->targetList, &info->rule_action->qual);
+ ResolveNew(info, parsetree->targetList,
+ (Node **) & (info->rule_action->targetList));
+ ResolveNew(info, parsetree->targetList, &info->rule_action->qual);
}
static void
-nodeHandleRIRAttributeRule(Node **nodePtr,
- List *rtable,
- List *targetlist,
- int rt_index,
- int attr_num,
- int *modified,
- int *badsql)
+nodeHandleRIRAttributeRule(Node ** nodePtr,
+ List * rtable,
+ List * targetlist,
+ int rt_index,
+ int attr_num,
+ int *modified,
+ int *badsql)
{
- Node *node = *nodePtr;
+ Node *node = *nodePtr;
- if (node == NULL)
- return;
- switch (nodeTag(node)) {
- case T_List:
- {
- List *i;
- foreach(i, (List*)node) {
- nodeHandleRIRAttributeRule((Node**)(&(lfirst(i))), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql);
- }
- }
- break;
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *)node;
- nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
- rt_index, attr_num, modified, badsql);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr *)node;
- nodeHandleRIRAttributeRule((Node**)(&(expr->args)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql);
- }
- break;
- case T_Var:
+ if (node == NULL)
+ return;
+ switch (nodeTag(node))
{
- int this_varno = (int) ((Var*)node)->varno;
- NameData name_to_look_for;
- memset(name_to_look_for.data, 0, NAMEDATALEN);
-
- if (this_varno == rt_index &&
- ((Var*) node)->varattno == attr_num) {
- if (((Var*)node)->vartype == 32) { /* HACK */
- *nodePtr = make_null(((Var*)node)->vartype);
- *modified = TRUE;
- *badsql = TRUE;
- break;
- } else {
- namestrcpy(&name_to_look_for,
- (char *)get_attname(getrelid(this_varno,
- rtable),
- attr_num));
+ case T_List:
+ {
+ List *i;
+
+ foreach(i, (List *) node)
+ {
+ nodeHandleRIRAttributeRule((Node **) (&(lfirst(i))), rtable,
+ targetlist, rt_index, attr_num,
+ modified, badsql);
+ }
}
- }
- if (name_to_look_for.data[0]) {
- Node *n;
-
- n = FindMatchingTLEntry(targetlist, (char *)&name_to_look_for);
- if (n == NULL) {
- *nodePtr = make_null(((Var*) node)->vartype);
- } else {
- *nodePtr = n;
+ break;
+ case T_TargetEntry:
+ {
+ TargetEntry *tle = (TargetEntry *) node;
+
+ nodeHandleRIRAttributeRule(&tle->expr, rtable, targetlist,
+ rt_index, attr_num, modified, badsql);
}
- *modified = TRUE;
- }
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) node;
+
+ nodeHandleRIRAttributeRule((Node **) (&(expr->args)), rtable,
+ targetlist, rt_index, attr_num,
+ modified, badsql);
+ }
+ break;
+ case T_Var:
+ {
+ int this_varno = (int) ((Var *) node)->varno;
+ NameData name_to_look_for;
+
+ memset(name_to_look_for.data, 0, NAMEDATALEN);
+
+ if (this_varno == rt_index &&
+ ((Var *) node)->varattno == attr_num)
+ {
+ if (((Var *) node)->vartype == 32)
+ { /* HACK */
+ *nodePtr = make_null(((Var *) node)->vartype);
+ *modified = TRUE;
+ *badsql = TRUE;
+ break;
+ }
+ else
+ {
+ namestrcpy(&name_to_look_for,
+ (char *) get_attname(getrelid(this_varno,
+ rtable),
+ attr_num));
+ }
+ }
+ if (name_to_look_for.data[0])
+ {
+ Node *n;
+
+ n = FindMatchingTLEntry(targetlist, (char *) &name_to_look_for);
+ if (n == NULL)
+ {
+ *nodePtr = make_null(((Var *) node)->vartype);
+ }
+ else
+ {
+ *nodePtr = n;
+ }
+ *modified = TRUE;
+ }
+ }
+ break;
+ default:
+ /* ignore the others */
+ break;
}
- break;
- default:
- /* ignore the others */
- break;
- }
}
-/*
+/*
* Handles 'on retrieve to relation.attribute
- * do instead retrieve (attribute = expression) w/qual'
+ * do instead retrieve (attribute = expression) w/qual'
*/
void
-HandleRIRAttributeRule(Query *parsetree,
- List *rtable,
- List *targetlist,
- int rt_index,
- int attr_num,
- int *modified,
- int *badsql)
+HandleRIRAttributeRule(Query * parsetree,
+ List * rtable,
+ List * targetlist,
+ int rt_index,
+ int attr_num,
+ int *modified,
+ int *badsql)
{
- nodeHandleRIRAttributeRule((Node**)(&(parsetree->targetList)), rtable,
- targetlist, rt_index, attr_num,
- modified, badsql);
- nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
- rt_index, attr_num, modified, badsql);
+ nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
+ targetlist, rt_index, attr_num,
+ modified, badsql);
+ nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
+ rt_index, attr_num, modified, badsql);
}
static void
-nodeHandleViewRule(Node **nodePtr,
- List *rtable,
- List *targetlist,
- int rt_index,
- int *modified)
+nodeHandleViewRule(Node ** nodePtr,
+ List * rtable,
+ List * targetlist,
+ int rt_index,
+ int *modified)
{
- Node *node = *nodePtr;
-
- if (node == NULL)
- return;
+ Node *node = *nodePtr;
- switch (nodeTag(node)) {
- case T_List:
- {
- List *l;
- foreach (l, (List*)node) {
- nodeHandleViewRule((Node**) (&(lfirst(l))),
- rtable, targetlist,
- rt_index, modified);
- }
- }
- break;
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *)node;
- nodeHandleViewRule(&(tle->expr), rtable, targetlist,
- rt_index, modified);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr*)node;
- nodeHandleViewRule((Node**)(&(expr->args)),
- rtable, targetlist,
- rt_index, modified);
- }
- break;
- case T_Var:
+ if (node == NULL)
+ return;
+
+ switch (nodeTag(node))
{
- Var *var = (Var*)node;
- int this_varno = var->varno;
- Node *n;
-
- if (this_varno == rt_index) {
- n = FindMatchingTLEntry(targetlist,
- get_attname(getrelid(this_varno,
- rtable),
- var->varattno));
- if (n == NULL) {
- *nodePtr = make_null(((Var*) node)->vartype);
- } else {
- *nodePtr = n;
+ case T_List:
+ {
+ List *l;
+
+ foreach(l, (List *) node)
+ {
+ nodeHandleViewRule((Node **) (&(lfirst(l))),
+ rtable, targetlist,
+ rt_index, modified);
+ }
+ }
+ break;
+ case T_TargetEntry:
+ {
+ TargetEntry *tle = (TargetEntry *) node;
+
+ nodeHandleViewRule(&(tle->expr), rtable, targetlist,
+ rt_index, modified);
+ }
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) node;
+
+ nodeHandleViewRule((Node **) (&(expr->args)),
+ rtable, targetlist,
+ rt_index, modified);
}
- *modified = TRUE;
- }
- break;
+ break;
+ case T_Var:
+ {
+ Var *var = (Var *) node;
+ int this_varno = var->varno;
+ Node *n;
+
+ if (this_varno == rt_index)
+ {
+ n = FindMatchingTLEntry(targetlist,
+ get_attname(getrelid(this_varno,
+ rtable),
+ var->varattno));
+ if (n == NULL)
+ {
+ *nodePtr = make_null(((Var *) node)->vartype);
+ }
+ else
+ {
+ *nodePtr = n;
+ }
+ *modified = TRUE;
+ }
+ break;
+ }
+ default:
+ /* ignore the others */
+ break;
}
- default:
- /* ignore the others */
- break;
- }
}
void
-HandleViewRule(Query *parsetree,
- List *rtable,
- List *targetlist,
- int rt_index,
- int *modified)
+HandleViewRule(Query * parsetree,
+ List * rtable,
+ List * targetlist,
+ int rt_index,
+ int *modified)
{
- nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
- modified);
- nodeHandleViewRule((Node**)(&(parsetree->targetList)), rtable, targetlist,
- rt_index, modified);
+ nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
+ modified);
+ nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
+ rt_index, modified);
}
-
diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c
index 3052a59a0df..58ccc5865b0 100644
--- a/src/backend/rewrite/rewriteRemove.c
+++ b/src/backend/rewrite/rewriteRemove.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* rewriteRemove.c--
- * routines for removing rewrite rules
+ * routines for removing rewrite rules
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.2 1996/11/03 04:51:51 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.3 1997/09/07 04:48:10 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,37 +18,37 @@
#include "catalog/pg_rewrite.h"
#include "catalog/catname.h" /* for RewriteRelationName */
#include "utils/syscache.h"
-#include "utils/elog.h" /* for elog stuff */
+#include "utils/elog.h" /* for elog stuff */
#include "utils/palloc.h"
-#include "utils/tqual.h" /* 'NowTimeQual' defined here.. */
-#include "access/heapam.h" /* heap AM calls defined here */
-#include "fmgr.h" /* for CHAR_16_EQ */
+#include "utils/tqual.h" /* 'NowTimeQual' defined here.. */
+#include "access/heapam.h" /* heap AM calls defined here */
+#include "fmgr.h" /* for CHAR_16_EQ */
-#include "rewrite/rewriteRemove.h" /* where the decls go */
+#include "rewrite/rewriteRemove.h" /* where the decls go */
#include "rewrite/rewriteSupport.h"
/*-----------------------------------------------------------------------
* RewriteGetRuleEventRel
*-----------------------------------------------------------------------
*/
-char*
+char *
RewriteGetRuleEventRel(char *rulename)
{
- HeapTuple htp;
- Oid eventrel;
-
- htp = SearchSysCacheTuple(REWRITENAME, PointerGetDatum(rulename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "RewriteGetRuleEventRel: rule \"%s\" not found",
- rulename);
- eventrel = ((Form_pg_rewrite) GETSTRUCT(htp))->ev_class;
- htp = SearchSysCacheTuple(RELOID, PointerGetDatum(eventrel),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "RewriteGetRuleEventRel: class %d not found",
- eventrel);
- return ((Form_pg_class) GETSTRUCT(htp))->relname.data;
+ HeapTuple htp;
+ Oid eventrel;
+
+ htp = SearchSysCacheTuple(REWRITENAME, PointerGetDatum(rulename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "RewriteGetRuleEventRel: rule \"%s\" not found",
+ rulename);
+ eventrel = ((Form_pg_rewrite) GETSTRUCT(htp))->ev_class;
+ htp = SearchSysCacheTuple(RELOID, PointerGetDatum(eventrel),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "RewriteGetRuleEventRel: class %d not found",
+ eventrel);
+ return ((Form_pg_class) GETSTRUCT(htp))->relname.data;
}
/* ----------------------------------------------------------------
@@ -58,10 +58,10 @@ RewriteGetRuleEventRel(char *rulename)
* Delete a rule given its rulename.
*
* There are three steps.
- * 1) Find the corresponding tuple in 'pg_rewrite' relation.
- * Find the rule Id (i.e. the Oid of the tuple) and finally delete
- * the tuple.
- * 3) Delete the locks from the 'pg_class' relation.
+ * 1) Find the corresponding tuple in 'pg_rewrite' relation.
+ * Find the rule Id (i.e. the Oid of the tuple) and finally delete
+ * the tuple.
+ * 3) Delete the locks from the 'pg_class' relation.
*
*
* ----------------------------------------------------------------
@@ -69,116 +69,119 @@ RewriteGetRuleEventRel(char *rulename)
void
RemoveRewriteRule(char *ruleName)
{
- Relation RewriteRelation = NULL;
- HeapScanDesc scanDesc = NULL;
- ScanKeyData scanKeyData;
- HeapTuple tuple = NULL;
- Oid ruleId = (Oid)0;
- Oid eventRelationOid = (Oid)NULL;
- Datum eventRelationOidDatum = (Datum)NULL;
- Buffer buffer = (Buffer)NULL;
- bool isNull = false;
-
- /*
- * Open the pg_rewrite relation.
- */
- RewriteRelation = heap_openr(RewriteRelationName);
-
- /*
- * Scan the RuleRelation ('pg_rewrite') until we find a tuple
- */
- ScanKeyEntryInitialize(&scanKeyData, 0, Anum_pg_rewrite_rulename,
- F_CHAR16EQ, NameGetDatum(ruleName));
- scanDesc = heap_beginscan(RewriteRelation,
- 0, NowTimeQual, 1, &scanKeyData);
-
- tuple = heap_getnext(scanDesc, 0, (Buffer *)NULL);
-
- /*
- * complain if no rule with such name existed
- */
- if (!HeapTupleIsValid(tuple)) {
+ Relation RewriteRelation = NULL;
+ HeapScanDesc scanDesc = NULL;
+ ScanKeyData scanKeyData;
+ HeapTuple tuple = NULL;
+ Oid ruleId = (Oid) 0;
+ Oid eventRelationOid = (Oid) NULL;
+ Datum eventRelationOidDatum = (Datum) NULL;
+ Buffer buffer = (Buffer) NULL;
+ bool isNull = false;
+
+ /*
+ * Open the pg_rewrite relation.
+ */
+ RewriteRelation = heap_openr(RewriteRelationName);
+
+ /*
+ * Scan the RuleRelation ('pg_rewrite') until we find a tuple
+ */
+ ScanKeyEntryInitialize(&scanKeyData, 0, Anum_pg_rewrite_rulename,
+ F_CHAR16EQ, NameGetDatum(ruleName));
+ scanDesc = heap_beginscan(RewriteRelation,
+ 0, NowTimeQual, 1, &scanKeyData);
+
+ tuple = heap_getnext(scanDesc, 0, (Buffer *) NULL);
+
+ /*
+ * complain if no rule with such name existed
+ */
+ if (!HeapTupleIsValid(tuple))
+ {
+ heap_close(RewriteRelation);
+ elog(WARN, "No rule with name = '%s' was found.\n", ruleName);
+ }
+
+ /*
+ * Store the OID of the rule (i.e. the tuple's OID) and the event
+ * relation's OID
+ */
+ ruleId = tuple->t_oid;
+ eventRelationOidDatum =
+ PointerGetDatum(heap_getattr(tuple,
+ buffer,
+ Anum_pg_rewrite_ev_class,
+ RelationGetTupleDescriptor(RewriteRelation),
+ &isNull));
+ if (isNull)
+ {
+ /* XXX strange!!! */
+ elog(WARN, "RemoveRewriteRule: null event target relation!");
+ }
+ eventRelationOid = DatumGetObjectId(eventRelationOidDatum);
+
+ /*
+ * Now delete the relation level locks from the updated relation.
+ * (Make sure we do this before we remove the rule from pg_rewrite.
+ * Otherwise, heap_openr on eventRelationOid which reads pg_rwrite for
+ * the rules will fail.)
+ */
+ prs2_deleteFromRelation(eventRelationOid, ruleId);
+
+ /*
+ * Now delete the tuple...
+ */
+ heap_delete(RewriteRelation, &(tuple->t_ctid));
heap_close(RewriteRelation);
- elog(WARN, "No rule with name = '%s' was found.\n", ruleName);
- }
-
- /*
- * Store the OID of the rule (i.e. the tuple's OID)
- * and the event relation's OID
- */
- ruleId = tuple->t_oid;
- eventRelationOidDatum =
- PointerGetDatum(heap_getattr(tuple,
- buffer,
- Anum_pg_rewrite_ev_class,
- RelationGetTupleDescriptor(RewriteRelation),
- &isNull));
- if (isNull) {
- /* XXX strange!!! */
- elog(WARN, "RemoveRewriteRule: null event target relation!");
- }
- eventRelationOid = DatumGetObjectId(eventRelationOidDatum);
-
- /*
- * Now delete the relation level locks from the updated relation.
- * (Make sure we do this before we remove the rule from pg_rewrite.
- * Otherwise, heap_openr on eventRelationOid which reads pg_rwrite
- * for the rules will fail.)
- */
- prs2_deleteFromRelation(eventRelationOid, ruleId);
-
- /*
- * Now delete the tuple...
- */
- heap_delete(RewriteRelation, &(tuple->t_ctid));
- heap_close(RewriteRelation);
- heap_endscan(scanDesc);
+ heap_endscan(scanDesc);
}
/*
* RelationRemoveRules -
- * removes all rules associated with the relation when the relation is
- * being removed.
+ * removes all rules associated with the relation when the relation is
+ * being removed.
*/
void
RelationRemoveRules(Oid relid)
{
- Relation RewriteRelation = NULL;
- HeapScanDesc scanDesc = NULL;
- ScanKeyData scanKeyData;
- HeapTuple tuple = NULL;
-
- /*
- * Open the pg_rewrite relation.
- */
- RewriteRelation = heap_openr(RewriteRelationName);
-
- /*
- * Scan the RuleRelation ('pg_rewrite') for all the tuples that
- * has the same ev_class as relid (the relation to be removed).
- */
- ScanKeyEntryInitialize(&scanKeyData,
- 0,
- Anum_pg_rewrite_ev_class,
- F_OIDEQ,
- ObjectIdGetDatum(relid));
- scanDesc = heap_beginscan(RewriteRelation,
- 0, NowTimeQual, 1, &scanKeyData);
-
- for(;;) {
- tuple = heap_getnext(scanDesc, 0, (Buffer *)NULL);
-
- if (!HeapTupleIsValid(tuple)) {
- break; /* we're done */
- }
-
+ Relation RewriteRelation = NULL;
+ HeapScanDesc scanDesc = NULL;
+ ScanKeyData scanKeyData;
+ HeapTuple tuple = NULL;
+
/*
- * delete the tuple...
+ * Open the pg_rewrite relation.
*/
- heap_delete(RewriteRelation, &(tuple->t_ctid));
- }
+ RewriteRelation = heap_openr(RewriteRelationName);
- heap_endscan(scanDesc);
- heap_close(RewriteRelation);
-}
+ /*
+ * Scan the RuleRelation ('pg_rewrite') for all the tuples that has
+ * the same ev_class as relid (the relation to be removed).
+ */
+ ScanKeyEntryInitialize(&scanKeyData,
+ 0,
+ Anum_pg_rewrite_ev_class,
+ F_OIDEQ,
+ ObjectIdGetDatum(relid));
+ scanDesc = heap_beginscan(RewriteRelation,
+ 0, NowTimeQual, 1, &scanKeyData);
+
+ for (;;)
+ {
+ tuple = heap_getnext(scanDesc, 0, (Buffer *) NULL);
+
+ if (!HeapTupleIsValid(tuple))
+ {
+ break; /* we're done */
+ }
+ /*
+ * delete the tuple...
+ */
+ heap_delete(RewriteRelation, &(tuple->t_ctid));
+ }
+
+ heap_endscan(scanDesc);
+ heap_close(RewriteRelation);
+}
diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c
index 54a8f0c7f97..8d3beb1c10f 100644
--- a/src/backend/rewrite/rewriteSupport.c
+++ b/src/backend/rewrite/rewriteSupport.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* rewriteSupport.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.6 1997/08/12 22:53:43 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.7 1997/09/07 04:48:11 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,7 +19,7 @@
#include "nodes/parsenodes.h"
#include "utils/builtins.h" /* for textout */
#include "utils/rel.h" /* for Relation, RelationData ... */
-#include "utils/elog.h" /* for elog */
+#include "utils/elog.h" /* for elog */
#include "storage/buf.h" /* for InvalidBuffer */
#include "rewrite/rewriteSupport.h"
#include "access/heapam.h"
@@ -31,242 +31,250 @@
#include "utils/palloc.h"
#include "fmgr.h"
-/*
+/*
* RuleIdGetActionInfo -
- * given a rule oid, look it up and return the rule-event-qual and
- * list of parsetrees for the rule (in parseTrees)
+ * given a rule oid, look it up and return the rule-event-qual and
+ * list of parsetrees for the rule (in parseTrees)
*/
#ifdef NOT_USED
-static Node *
-RuleIdGetActionInfo(Oid ruleoid, bool *instead_flag, Query **parseTrees)
+static Node *
+RuleIdGetActionInfo(Oid ruleoid, bool * instead_flag, Query ** parseTrees)
{
- HeapTuple ruletuple;
- char *ruleaction = NULL;
- bool action_is_null = false;
- bool instead_is_null = false;
- Relation ruleRelation = NULL;
- TupleDesc ruleTupdesc = NULL;
- Query *ruleparse = NULL;
- char *rule_evqual_string = NULL;
- Node *rule_evqual = NULL;
-
- ruleRelation = heap_openr (RewriteRelationName);
- ruleTupdesc = RelationGetTupleDescriptor(ruleRelation);
- ruletuple = SearchSysCacheTuple (RULOID,
- ObjectIdGetDatum(ruleoid),
- 0,0,0);
- if (ruletuple == NULL)
- elog(WARN, "rule %u isn't in rewrite system relation", ruleoid);
-
- ruleaction = heap_getattr(ruletuple,
- InvalidBuffer,
- Anum_pg_rewrite_action,
- ruleTupdesc,
- &action_is_null ) ;
- rule_evqual_string = heap_getattr(ruletuple, InvalidBuffer,
- Anum_pg_rewrite_ev_qual,
- ruleTupdesc, &action_is_null) ;
- *instead_flag = !!heap_getattr(ruletuple, InvalidBuffer,
- Anum_pg_rewrite_is_instead,
- ruleTupdesc, &instead_is_null) ;
-
- if (action_is_null || instead_is_null) {
- elog(WARN, "internal error: rewrite rule not properly set up");
- }
-
- ruleaction = textout((struct varlena *)ruleaction);
- rule_evqual_string = textout((struct varlena *)rule_evqual_string);
-
- ruleparse = (Query*)stringToNode(ruleaction);
- rule_evqual = (Node*)stringToNode(rule_evqual_string);
-
- heap_close(ruleRelation);
-
- *parseTrees = ruleparse;
- return rule_evqual;
+ HeapTuple ruletuple;
+ char *ruleaction = NULL;
+ bool action_is_null = false;
+ bool instead_is_null = false;
+ Relation ruleRelation = NULL;
+ TupleDesc ruleTupdesc = NULL;
+ Query *ruleparse = NULL;
+ char *rule_evqual_string = NULL;
+ Node *rule_evqual = NULL;
+
+ ruleRelation = heap_openr(RewriteRelationName);
+ ruleTupdesc = RelationGetTupleDescriptor(ruleRelation);
+ ruletuple = SearchSysCacheTuple(RULOID,
+ ObjectIdGetDatum(ruleoid),
+ 0, 0, 0);
+ if (ruletuple == NULL)
+ elog(WARN, "rule %u isn't in rewrite system relation", ruleoid);
+
+ ruleaction = heap_getattr(ruletuple,
+ InvalidBuffer,
+ Anum_pg_rewrite_action,
+ ruleTupdesc,
+ &action_is_null);
+ rule_evqual_string = heap_getattr(ruletuple, InvalidBuffer,
+ Anum_pg_rewrite_ev_qual,
+ ruleTupdesc, &action_is_null);
+ *instead_flag = !!heap_getattr(ruletuple, InvalidBuffer,
+ Anum_pg_rewrite_is_instead,
+ ruleTupdesc, &instead_is_null);
+
+ if (action_is_null || instead_is_null)
+ {
+ elog(WARN, "internal error: rewrite rule not properly set up");
+ }
+
+ ruleaction = textout((struct varlena *) ruleaction);
+ rule_evqual_string = textout((struct varlena *) rule_evqual_string);
+
+ ruleparse = (Query *) stringToNode(ruleaction);
+ rule_evqual = (Node *) stringToNode(rule_evqual_string);
+
+ heap_close(ruleRelation);
+
+ *parseTrees = ruleparse;
+ return rule_evqual;
}
+
#endif
int
IsDefinedRewriteRule(char *ruleName)
{
- Relation RewriteRelation = NULL;
- HeapScanDesc scanDesc = NULL;
- ScanKeyData scanKey;
- HeapTuple tuple = NULL;
-
-
- /*
- * Open the pg_rewrite relation.
- */
- RewriteRelation = heap_openr(RewriteRelationName);
-
- /*
- * Scan the RuleRelation ('pg_rewrite') until we find a tuple
- */
- ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_rewrite_rulename,
- NameEqualRegProcedure, PointerGetDatum(ruleName));
- scanDesc = heap_beginscan(RewriteRelation,
- 0, NowTimeQual, 1, &scanKey);
-
- tuple = heap_getnext(scanDesc, 0, (Buffer *)NULL);
-
- /*
- * return whether or not the rewrite rule existed
- */
- heap_close(RewriteRelation);
- heap_endscan(scanDesc);
- return (HeapTupleIsValid(tuple));
+ Relation RewriteRelation = NULL;
+ HeapScanDesc scanDesc = NULL;
+ ScanKeyData scanKey;
+ HeapTuple tuple = NULL;
+
+
+ /*
+ * Open the pg_rewrite relation.
+ */
+ RewriteRelation = heap_openr(RewriteRelationName);
+
+ /*
+ * Scan the RuleRelation ('pg_rewrite') until we find a tuple
+ */
+ ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_rewrite_rulename,
+ NameEqualRegProcedure, PointerGetDatum(ruleName));
+ scanDesc = heap_beginscan(RewriteRelation,
+ 0, NowTimeQual, 1, &scanKey);
+
+ tuple = heap_getnext(scanDesc, 0, (Buffer *) NULL);
+
+ /*
+ * return whether or not the rewrite rule existed
+ */
+ heap_close(RewriteRelation);
+ heap_endscan(scanDesc);
+ return (HeapTupleIsValid(tuple));
}
static void
setRelhasrulesInRelation(Oid relationId, bool relhasrules)
{
- Relation relationRelation;
- HeapTuple tuple;
- HeapTuple newTuple;
- Relation idescs[Num_pg_class_indices];
- Form_pg_class relp;
-
- /*
- * Lock a relation given its Oid.
- * Go to the RelationRelation (i.e. pg_relation), find the
- * appropriate tuple, and add the specified lock to it.
- */
- relationRelation = heap_openr(RelationRelationName);
- tuple = ClassOidIndexScan(relationRelation, relationId);
-
- /*
- * Create a new tuple (i.e. a copy of the old tuple
- * with its rule lock field changed and replace the old
- * tuple in the RelationRelation
- * NOTE: XXX ??? do we really need to make that copy ????
- */
- newTuple = heap_copytuple(tuple);
-
- relp = (Form_pg_class) GETSTRUCT(newTuple);
- relp->relhasrules = relhasrules;
-
- heap_replace(relationRelation, &(tuple->t_ctid), newTuple);
-
- /* keep the catalog indices up to date */
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation,
- newTuple);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
-
- /* be tidy */
- pfree(tuple);
- pfree(newTuple);
-
- heap_close(relationRelation);
+ Relation relationRelation;
+ HeapTuple tuple;
+ HeapTuple newTuple;
+ Relation idescs[Num_pg_class_indices];
+ Form_pg_class relp;
+
+ /*
+ * Lock a relation given its Oid. Go to the RelationRelation (i.e.
+ * pg_relation), find the appropriate tuple, and add the specified
+ * lock to it.
+ */
+ relationRelation = heap_openr(RelationRelationName);
+ tuple = ClassOidIndexScan(relationRelation, relationId);
+
+ /*
+ * Create a new tuple (i.e. a copy of the old tuple with its rule lock
+ * field changed and replace the old tuple in the RelationRelation
+ * NOTE: XXX ??? do we really need to make that copy ????
+ */
+ newTuple = heap_copytuple(tuple);
+
+ relp = (Form_pg_class) GETSTRUCT(newTuple);
+ relp->relhasrules = relhasrules;
+
+ heap_replace(relationRelation, &(tuple->t_ctid), newTuple);
+
+ /* keep the catalog indices up to date */
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, relationRelation,
+ newTuple);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+ /* be tidy */
+ pfree(tuple);
+ pfree(newTuple);
+
+ heap_close(relationRelation);
}
void
prs2_addToRelation(Oid relid,
- Oid ruleId,
- CmdType event_type,
- AttrNumber attno,
- bool isInstead,
- Node *qual,
- List *actions)
+ Oid ruleId,
+ CmdType event_type,
+ AttrNumber attno,
+ bool isInstead,
+ Node * qual,
+ List * actions)
{
- Relation relation;
- RewriteRule *thisRule;
- RuleLock *rulelock;
- MemoryContext oldcxt;
-
- /*
- * create an in memory RewriteRule data structure which is cached by
- * every Relation descriptor. (see utils/cache/relcache.c)
- */
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
- thisRule = (RewriteRule *)palloc(sizeof(RewriteRule));
- MemoryContextSwitchTo(oldcxt);
-
- thisRule->ruleId = ruleId;
- thisRule->event = event_type;
- thisRule->attrno = attno;
- thisRule->qual = qual;
- thisRule->actions = actions;
- thisRule->isInstead = isInstead;
-
- relation = heap_open(relid);
-
- /*
- * modify or create a RuleLock cached by Relation
- */
- if (relation->rd_rules == NULL) {
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
- rulelock = (RuleLock *)palloc(sizeof(RuleLock));
- rulelock->numLocks = 1;
- rulelock->rules = (RewriteRule **)palloc(sizeof(RewriteRule*));
- rulelock->rules[0] = thisRule;
- relation->rd_rules = rulelock;
- MemoryContextSwitchTo(oldcxt);
+ Relation relation;
+ RewriteRule *thisRule;
+ RuleLock *rulelock;
+ MemoryContext oldcxt;
/*
- * the fact that relation->rd_rules is NULL means the relhasrules
- * attribute of the tuple of this relation in pg_class is false. We
- * need to set it to true.
+ * create an in memory RewriteRule data structure which is cached by
+ * every Relation descriptor. (see utils/cache/relcache.c)
*/
- setRelhasrulesInRelation(relid, TRUE);
- } else {
- int numlock;
-
- rulelock = relation->rd_rules;
- numlock = rulelock->numLocks;
- /* expand, for safety reasons */
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
- rulelock->rules =
- (RewriteRule **)repalloc(rulelock->rules,
- sizeof(RewriteRule*)*(numlock+1));
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ thisRule = (RewriteRule *) palloc(sizeof(RewriteRule));
MemoryContextSwitchTo(oldcxt);
- rulelock->rules[numlock] = thisRule;
- rulelock->numLocks++;
- }
- heap_close(relation);
+ thisRule->ruleId = ruleId;
+ thisRule->event = event_type;
+ thisRule->attrno = attno;
+ thisRule->qual = qual;
+ thisRule->actions = actions;
+ thisRule->isInstead = isInstead;
+
+ relation = heap_open(relid);
+
+ /*
+ * modify or create a RuleLock cached by Relation
+ */
+ if (relation->rd_rules == NULL)
+ {
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ rulelock = (RuleLock *) palloc(sizeof(RuleLock));
+ rulelock->numLocks = 1;
+ rulelock->rules = (RewriteRule **) palloc(sizeof(RewriteRule *));
+ rulelock->rules[0] = thisRule;
+ relation->rd_rules = rulelock;
+ MemoryContextSwitchTo(oldcxt);
- return;
+ /*
+ * the fact that relation->rd_rules is NULL means the relhasrules
+ * attribute of the tuple of this relation in pg_class is false.
+ * We need to set it to true.
+ */
+ setRelhasrulesInRelation(relid, TRUE);
+ }
+ else
+ {
+ int numlock;
+
+ rulelock = relation->rd_rules;
+ numlock = rulelock->numLocks;
+ /* expand, for safety reasons */
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ rulelock->rules =
+ (RewriteRule **) repalloc(rulelock->rules,
+ sizeof(RewriteRule *) * (numlock + 1));
+ MemoryContextSwitchTo(oldcxt);
+ rulelock->rules[numlock] = thisRule;
+ rulelock->numLocks++;
+ }
+
+ heap_close(relation);
+
+ return;
}
void
prs2_deleteFromRelation(Oid relid, Oid ruleId)
{
- RuleLock *rulelock;
- Relation relation;
- int numlock;
- int i;
- MemoryContext oldcxt;
-
- relation = heap_open(relid);
- rulelock = relation->rd_rules;
- Assert(rulelock != NULL);
-
- numlock = rulelock->numLocks;
- for(i=0; i < numlock; i++) {
- if (rulelock->rules[i]->ruleId == ruleId)
- break;
- }
- Assert(i<numlock);
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
- pfree(rulelock->rules[i]);
- MemoryContextSwitchTo(oldcxt);
- if (numlock==1) {
- relation->rd_rules = NULL;
- /*
- * we don't have rules any more, flag the relhasrules attribute of
- * the tuple of this relation in pg_class false.
- */
- setRelhasrulesInRelation(relid, FALSE);
- } else {
- rulelock->rules[i] = rulelock->rules[numlock-1];
- rulelock->rules[numlock-1] = NULL;
- rulelock->numLocks--;
- }
-
- heap_close(relation);
-}
+ RuleLock *rulelock;
+ Relation relation;
+ int numlock;
+ int i;
+ MemoryContext oldcxt;
+ relation = heap_open(relid);
+ rulelock = relation->rd_rules;
+ Assert(rulelock != NULL);
+
+ numlock = rulelock->numLocks;
+ for (i = 0; i < numlock; i++)
+ {
+ if (rulelock->rules[i]->ruleId == ruleId)
+ break;
+ }
+ Assert(i < numlock);
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ pfree(rulelock->rules[i]);
+ MemoryContextSwitchTo(oldcxt);
+ if (numlock == 1)
+ {
+ relation->rd_rules = NULL;
+
+ /*
+ * we don't have rules any more, flag the relhasrules attribute of
+ * the tuple of this relation in pg_class false.
+ */
+ setRelhasrulesInRelation(relid, FALSE);
+ }
+ else
+ {
+ rulelock->rules[i] = rulelock->rules[numlock - 1];
+ rulelock->rules[numlock - 1] = NULL;
+ rulelock->numLocks--;
+ }
+
+ heap_close(relation);
+}
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index 20f8195d1e9..4ce064d6713 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* buf_init.c--
- * buffer manager initialization routines
+ * buffer manager initialization routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.10 1997/07/28 00:54:33 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.11 1997/09/07 04:48:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -35,98 +35,103 @@
#include "utils/dynahash.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
-#include "executor/execdebug.h" /* for NDirectFileRead */
+#include "executor/execdebug.h" /* for NDirectFileRead */
#include "catalog/catalog.h"
/*
- * if BMTRACE is defined, we trace the last 200 buffer allocations and
- * deallocations in a circular buffer in shared memory.
+ * if BMTRACE is defined, we trace the last 200 buffer allocations and
+ * deallocations in a circular buffer in shared memory.
*/
#ifdef BMTRACE
-bmtrace *TraceBuf;
-long *CurTraceBuf;
-#define BMT_LIMIT 200
-#endif /* BMTRACE */
-int ShowPinTrace = 0;
-
-int NBuffers = NDBUFS; /* NDBUFS defined in miscadmin.h */
-int Data_Descriptors;
-int Free_List_Descriptor;
-int Lookup_List_Descriptor;
-int Num_Descriptors;
-
-BufferDesc *BufferDescriptors;
-BufferBlock BufferBlocks;
+bmtrace *TraceBuf;
+long *CurTraceBuf;
+
+#define BMT_LIMIT 200
+#endif /* BMTRACE */
+int ShowPinTrace = 0;
+
+int NBuffers = NDBUFS; /* NDBUFS defined in miscadmin.h */
+int Data_Descriptors;
+int Free_List_Descriptor;
+int Lookup_List_Descriptor;
+int Num_Descriptors;
+
+BufferDesc *BufferDescriptors;
+BufferBlock BufferBlocks;
+
#ifndef HAS_TEST_AND_SET
-long *NWaitIOBackendP;
+long *NWaitIOBackendP;
+
#endif
-extern IpcSemaphoreId WaitIOSemId;
+extern IpcSemaphoreId WaitIOSemId;
+
+long *PrivateRefCount;/* also used in freelist.c */
+long *LastRefCount; /* refcounts of last ExecMain level */
+long *CommitInfoNeedsSave; /* to write buffers where we have
+ * filled in */
-long *PrivateRefCount; /* also used in freelist.c */
-long *LastRefCount; /* refcounts of last ExecMain level */
-long *CommitInfoNeedsSave; /* to write buffers where we have filled in */
- /* t_tmin (or t_tmax) */
+ /* t_tmin (or t_tmax) */
/*
* Data Structures:
- * buffers live in a freelist and a lookup data structure.
- *
+ * buffers live in a freelist and a lookup data structure.
+ *
*
* Buffer Lookup:
- * Two important notes. First, the buffer has to be
- * available for lookup BEFORE an IO begins. Otherwise
- * a second process trying to read the buffer will
- * allocate its own copy and the buffeer pool will
- * become inconsistent.
+ * Two important notes. First, the buffer has to be
+ * available for lookup BEFORE an IO begins. Otherwise
+ * a second process trying to read the buffer will
+ * allocate its own copy and the buffeer pool will
+ * become inconsistent.
*
* Buffer Replacement:
- * see freelist.c. A buffer cannot be replaced while in
- * use either by data manager or during IO.
+ * see freelist.c. A buffer cannot be replaced while in
+ * use either by data manager or during IO.
*
* WriteBufferBack:
- * currently, a buffer is only written back at the time
- * it is selected for replacement. It should
- * be done sooner if possible to reduce latency of
- * BufferAlloc(). Maybe there should be a daemon process.
+ * currently, a buffer is only written back at the time
+ * it is selected for replacement. It should
+ * be done sooner if possible to reduce latency of
+ * BufferAlloc(). Maybe there should be a daemon process.
*
* Synchronization/Locking:
*
- * BufMgrLock lock -- must be acquired before manipulating the
- * buffer queues (lookup/freelist). Must be released
- * before exit and before doing any IO.
+ * BufMgrLock lock -- must be acquired before manipulating the
+ * buffer queues (lookup/freelist). Must be released
+ * before exit and before doing any IO.
*
* IO_IN_PROGRESS -- this is a flag in the buffer descriptor.
- * It must be set when an IO is initiated and cleared at
- * the end of the IO. It is there to make sure that one
- * process doesn't start to use a buffer while another is
- * faulting it in. see IOWait/IOSignal.
+ * It must be set when an IO is initiated and cleared at
+ * the end of the IO. It is there to make sure that one
+ * process doesn't start to use a buffer while another is
+ * faulting it in. see IOWait/IOSignal.
*
- * refcount -- A buffer is pinned during IO and immediately
- * after a BufferAlloc(). A buffer is always either pinned
- * or on the freelist but never both. The buffer must be
- * released, written, or flushed before the end of
- * transaction.
+ * refcount -- A buffer is pinned during IO and immediately
+ * after a BufferAlloc(). A buffer is always either pinned
+ * or on the freelist but never both. The buffer must be
+ * released, written, or flushed before the end of
+ * transaction.
*
* PrivateRefCount -- Each buffer also has a private refcount the keeps
- * track of the number of times the buffer is pinned in the current
- * processes. This is used for two purposes, first, if we pin a
- * a buffer more than once, we only need to change the shared refcount
- * once, thus only lock the buffer pool once, second, when a transaction
- * aborts, it should only unpin the buffers exactly the number of times it
- * has pinned them, so that it will not blow away buffers of another
- * backend.
+ * track of the number of times the buffer is pinned in the current
+ * processes. This is used for two purposes, first, if we pin a
+ * a buffer more than once, we only need to change the shared refcount
+ * once, thus only lock the buffer pool once, second, when a transaction
+ * aborts, it should only unpin the buffers exactly the number of times it
+ * has pinned them, so that it will not blow away buffers of another
+ * backend.
*
*/
-SPINLOCK BufMgrLock;
+SPINLOCK BufMgrLock;
-long int ReadBufferCount;
-long int ReadLocalBufferCount;
-long int BufferHitCount;
-long int LocalBufferHitCount;
-long int BufferFlushCount;
-long int LocalBufferFlushCount;
+long int ReadBufferCount;
+long int ReadLocalBufferCount;
+long int BufferHitCount;
+long int LocalBufferHitCount;
+long int BufferFlushCount;
+long int LocalBufferFlushCount;
/*
@@ -138,111 +143,121 @@ long int LocalBufferFlushCount;
void
InitBufferPool(IPCKey key)
{
- bool foundBufs,foundDescs;
- int i;
-
- /* check padding of BufferDesc and BufferHdr */
- /* we need both checks because a sbufdesc_padded > PADDED_SBUFDESC_SIZE
- will shrink sbufdesc to the required size, which is bad */
- if (sizeof(struct sbufdesc) != PADDED_SBUFDESC_SIZE ||
- sizeof(struct sbufdesc_unpadded) > PADDED_SBUFDESC_SIZE)
- elog(WARN,"Internal error: sbufdesc does not have the proper size, "
- "contact the Postgres developers");
- if (sizeof(struct sbufdesc_unpadded) <= PADDED_SBUFDESC_SIZE/2)
- elog(WARN,"Internal error: sbufdesc is greatly over-sized, "
- "contact the Postgres developers");
-
- Data_Descriptors = NBuffers;
- Free_List_Descriptor = Data_Descriptors;
- Lookup_List_Descriptor = Data_Descriptors + 1;
- Num_Descriptors = Data_Descriptors + 1;
-
- SpinAcquire(BufMgrLock);
-
+ bool foundBufs,
+ foundDescs;
+ int i;
+
+ /* check padding of BufferDesc and BufferHdr */
+
+ /*
+ * we need both checks because a sbufdesc_padded >
+ * PADDED_SBUFDESC_SIZE will shrink sbufdesc to the required size,
+ * which is bad
+ */
+ if (sizeof(struct sbufdesc) != PADDED_SBUFDESC_SIZE ||
+ sizeof(struct sbufdesc_unpadded) > PADDED_SBUFDESC_SIZE)
+ elog(WARN, "Internal error: sbufdesc does not have the proper size, "
+ "contact the Postgres developers");
+ if (sizeof(struct sbufdesc_unpadded) <= PADDED_SBUFDESC_SIZE / 2)
+ elog(WARN, "Internal error: sbufdesc is greatly over-sized, "
+ "contact the Postgres developers");
+
+ Data_Descriptors = NBuffers;
+ Free_List_Descriptor = Data_Descriptors;
+ Lookup_List_Descriptor = Data_Descriptors + 1;
+ Num_Descriptors = Data_Descriptors + 1;
+
+ SpinAcquire(BufMgrLock);
+
#ifdef BMTRACE
- CurTraceBuf = (long *) ShmemInitStruct("Buffer trace",
- (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long),
- &foundDescs);
- if (!foundDescs)
- memset(CurTraceBuf, 0, (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long));
-
- TraceBuf = (bmtrace *) &(CurTraceBuf[1]);
+ CurTraceBuf = (long *) ShmemInitStruct("Buffer trace",
+ (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long),
+ &foundDescs);
+ if (!foundDescs)
+ memset(CurTraceBuf, 0, (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long));
+
+ TraceBuf = (bmtrace *) & (CurTraceBuf[1]);
#endif
-
- BufferDescriptors = (BufferDesc *)
- ShmemInitStruct("Buffer Descriptors",
- Num_Descriptors*sizeof(BufferDesc),&foundDescs);
-
- BufferBlocks = (BufferBlock)
- ShmemInitStruct("Buffer Blocks",
- NBuffers*BLCKSZ,&foundBufs);
-
+
+ BufferDescriptors = (BufferDesc *)
+ ShmemInitStruct("Buffer Descriptors",
+ Num_Descriptors * sizeof(BufferDesc), &foundDescs);
+
+ BufferBlocks = (BufferBlock)
+ ShmemInitStruct("Buffer Blocks",
+ NBuffers * BLCKSZ, &foundBufs);
+
#ifndef HAS_TEST_AND_SET
- {
- bool foundNWaitIO;
-
- NWaitIOBackendP = (long *)ShmemInitStruct("#Backends Waiting IO",
- sizeof(long),
- &foundNWaitIO);
- if (!foundNWaitIO)
- *NWaitIOBackendP = 0;
- }
+ {
+ bool foundNWaitIO;
+
+ NWaitIOBackendP = (long *) ShmemInitStruct("#Backends Waiting IO",
+ sizeof(long),
+ &foundNWaitIO);
+ if (!foundNWaitIO)
+ *NWaitIOBackendP = 0;
+ }
#endif
-
- if (foundDescs || foundBufs) {
-
- /* both should be present or neither */
- Assert(foundDescs && foundBufs);
-
- } else {
- BufferDesc *buf;
- unsigned long block;
-
- buf = BufferDescriptors;
- block = (unsigned long) BufferBlocks;
-
- /*
- * link the buffers into a circular, doubly-linked list to
- * initialize free list. Still don't know anything about
- * replacement strategy in this file.
- */
- for (i = 0; i < Data_Descriptors; block+=BLCKSZ,buf++,i++) {
- Assert(ShmemIsValid((unsigned long)block));
-
- buf->freeNext = i+1;
- buf->freePrev = i-1;
-
- CLEAR_BUFFERTAG(&(buf->tag));
- buf->data = MAKE_OFFSET(block);
- buf->flags = (BM_DELETED | BM_FREE | BM_VALID);
- buf->refcount = 0;
- buf->buf_id = i;
+
+ if (foundDescs || foundBufs)
+ {
+
+ /* both should be present or neither */
+ Assert(foundDescs && foundBufs);
+
+ }
+ else
+ {
+ BufferDesc *buf;
+ unsigned long block;
+
+ buf = BufferDescriptors;
+ block = (unsigned long) BufferBlocks;
+
+ /*
+ * link the buffers into a circular, doubly-linked list to
+ * initialize free list. Still don't know anything about
+ * replacement strategy in this file.
+ */
+ for (i = 0; i < Data_Descriptors; block += BLCKSZ, buf++, i++)
+ {
+ Assert(ShmemIsValid((unsigned long) block));
+
+ buf->freeNext = i + 1;
+ buf->freePrev = i - 1;
+
+ CLEAR_BUFFERTAG(&(buf->tag));
+ buf->data = MAKE_OFFSET(block);
+ buf->flags = (BM_DELETED | BM_FREE | BM_VALID);
+ buf->refcount = 0;
+ buf->buf_id = i;
#ifdef HAS_TEST_AND_SET
- S_INIT_LOCK(&(buf->io_in_progress_lock));
+ S_INIT_LOCK(&(buf->io_in_progress_lock));
#endif
+ }
+
+ /* close the circular queue */
+ BufferDescriptors[0].freePrev = Data_Descriptors - 1;
+ BufferDescriptors[Data_Descriptors - 1].freeNext = 0;
}
-
- /* close the circular queue */
- BufferDescriptors[0].freePrev = Data_Descriptors-1;
- BufferDescriptors[Data_Descriptors-1].freeNext = 0;
- }
-
- /* Init the rest of the module */
- InitBufTable();
- InitFreeList(!foundDescs);
-
- SpinRelease(BufMgrLock);
-
+
+ /* Init the rest of the module */
+ InitBufTable();
+ InitFreeList(!foundDescs);
+
+ SpinRelease(BufMgrLock);
+
#ifndef HAS_TEST_AND_SET
- {
- int status;
- WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
- 1, IPCProtection, 0, 1, &status);
- }
+ {
+ int status;
+
+ WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key),
+ 1, IPCProtection, 0, 1, &status);
+ }
#endif
- PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
- LastRefCount = (long *) calloc(NBuffers, sizeof(long));
- CommitInfoNeedsSave = (long *) calloc(NBuffers, sizeof(long));
+ PrivateRefCount = (long *) calloc(NBuffers, sizeof(long));
+ LastRefCount = (long *) calloc(NBuffers, sizeof(long));
+ CommitInfoNeedsSave = (long *) calloc(NBuffers, sizeof(long));
}
/* -----------------------------------------------------
@@ -255,43 +270,41 @@ InitBufferPool(IPCKey key)
int
BufferShmemSize()
{
- int size = 0;
- int nbuckets;
- int nsegs;
- int tmp;
-
- nbuckets = 1 << (int)my_log2((NBuffers - 1) / DEF_FFACTOR + 1);
- nsegs = 1 << (int)my_log2((nbuckets - 1) / DEF_SEGSIZE + 1);
-
- /* size of shmem binding table */
- size += MAXALIGN(my_log2(BTABLE_SIZE) * sizeof(void *)); /* HTAB->dir */
- size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */
- size += MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
- size += BUCKET_ALLOC_INCR *
- (MAXALIGN(sizeof(BUCKET_INDEX)) +
- MAXALIGN(BTABLE_KEYSIZE) +
- MAXALIGN(BTABLE_DATASIZE));
-
- /* size of buffer descriptors */
- size += MAXALIGN((NBuffers + 1) * sizeof(BufferDesc));
-
- /* size of data pages */
- size += NBuffers * MAXALIGN(BLCKSZ);
-
- /* size of buffer hash table */
- size += MAXALIGN(my_log2(NBuffers) * sizeof(void *)); /* HTAB->dir */
- size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */
- size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
- tmp = (int)ceil((double)NBuffers/BUCKET_ALLOC_INCR);
- size += tmp * BUCKET_ALLOC_INCR *
- (MAXALIGN(sizeof(BUCKET_INDEX)) +
- MAXALIGN(sizeof(BufferTag)) +
- MAXALIGN(sizeof(Buffer)));
-
+ int size = 0;
+ int nbuckets;
+ int nsegs;
+ int tmp;
+
+ nbuckets = 1 << (int) my_log2((NBuffers - 1) / DEF_FFACTOR + 1);
+ nsegs = 1 << (int) my_log2((nbuckets - 1) / DEF_SEGSIZE + 1);
+
+ /* size of shmem binding table */
+ size += MAXALIGN(my_log2(BTABLE_SIZE) * sizeof(void *)); /* HTAB->dir */
+ size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */
+ size += MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
+ size += BUCKET_ALLOC_INCR *
+ (MAXALIGN(sizeof(BUCKET_INDEX)) +
+ MAXALIGN(BTABLE_KEYSIZE) +
+ MAXALIGN(BTABLE_DATASIZE));
+
+ /* size of buffer descriptors */
+ size += MAXALIGN((NBuffers + 1) * sizeof(BufferDesc));
+
+ /* size of data pages */
+ size += NBuffers * MAXALIGN(BLCKSZ);
+
+ /* size of buffer hash table */
+ size += MAXALIGN(my_log2(NBuffers) * sizeof(void *)); /* HTAB->dir */
+ size += MAXALIGN(sizeof(HHDR)); /* HTAB->hctl */
+ size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
+ tmp = (int) ceil((double) NBuffers / BUCKET_ALLOC_INCR);
+ size += tmp * BUCKET_ALLOC_INCR *
+ (MAXALIGN(sizeof(BUCKET_INDEX)) +
+ MAXALIGN(sizeof(BufferTag)) +
+ MAXALIGN(sizeof(Buffer)));
+
#ifdef BMTRACE
- size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long);
+ size += (BMT_LIMIT * sizeof(bmtrace)) + sizeof(long);
#endif
- return size;
+ return size;
}
-
-
diff --git a/src/backend/storage/buffer/buf_table.c b/src/backend/storage/buffer/buf_table.c
index 61e365ce55e..41b2b4d8ee0 100644
--- a/src/backend/storage/buffer/buf_table.c
+++ b/src/backend/storage/buffer/buf_table.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* buf_table.c--
- * routines for finding buffers in the buffer pool.
+ * routines for finding buffers in the buffer pool.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_table.c,v 1.4 1997/08/19 21:32:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_table.c,v 1.5 1997/09/07 04:48:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,30 +16,31 @@
*
* Data Structures:
*
- * Buffers are identified by their BufferTag (buf.h). This
+ * Buffers are identified by their BufferTag (buf.h). This
* file contains routines for allocating a shmem hash table to
* map buffer tags to buffer descriptors.
*
* Synchronization:
- *
- * All routines in this file assume buffer manager spinlock is
- * held by their caller.
+ *
+ * All routines in this file assume buffer manager spinlock is
+ * held by their caller.
*/
#include "postgres.h"
#include "storage/bufmgr.h"
-#include "storage/buf_internals.h" /* where the declarations go */
+#include "storage/buf_internals.h" /* where the declarations go */
#include "storage/shmem.h"
#include "storage/spin.h"
#include "utils/hsearch.h"
-static HTAB *SharedBufHash;
+static HTAB *SharedBufHash;
-typedef struct lookup {
- BufferTag key;
- Buffer id;
-} LookupEnt;
+typedef struct lookup
+{
+ BufferTag key;
+ Buffer id;
+} LookupEnt;
/*
* Initialize shmem hash table for mapping buffers
@@ -47,109 +48,116 @@ typedef struct lookup {
void
InitBufTable()
{
- HASHCTL info;
- int hash_flags;
-
- /* assume lock is held */
-
- /* BufferTag maps to Buffer */
- info.keysize = sizeof(BufferTag);
- info.datasize = sizeof(Buffer);
- info.hash = tag_hash;
-
- hash_flags = (HASH_ELEM | HASH_FUNCTION);
-
-
- SharedBufHash = (HTAB *) ShmemInitHash("Shared Buf Lookup Table",
- NBuffers,NBuffers,
- &info,hash_flags);
-
- if (! SharedBufHash) {
- elog(FATAL,"couldn't initialize shared buffer pool Hash Tbl");
- exit(1);
- }
-
+ HASHCTL info;
+ int hash_flags;
+
+ /* assume lock is held */
+
+ /* BufferTag maps to Buffer */
+ info.keysize = sizeof(BufferTag);
+ info.datasize = sizeof(Buffer);
+ info.hash = tag_hash;
+
+ hash_flags = (HASH_ELEM | HASH_FUNCTION);
+
+
+ SharedBufHash = (HTAB *) ShmemInitHash("Shared Buf Lookup Table",
+ NBuffers, NBuffers,
+ &info, hash_flags);
+
+ if (!SharedBufHash)
+ {
+ elog(FATAL, "couldn't initialize shared buffer pool Hash Tbl");
+ exit(1);
+ }
+
}
-BufferDesc *
-BufTableLookup(BufferTag *tagPtr)
+BufferDesc *
+BufTableLookup(BufferTag * tagPtr)
{
- LookupEnt * result;
- bool found;
-
- if (tagPtr->blockNum == P_NEW)
- return(NULL);
-
- result = (LookupEnt *)
- hash_search(SharedBufHash,(char *) tagPtr,HASH_FIND,&found);
-
- if (! result){
- elog(WARN,"BufTableLookup: BufferLookup table corrupted");
- return(NULL);
- }
- if (! found) {
- return(NULL);
- }
- return(&(BufferDescriptors[result->id]));
+ LookupEnt *result;
+ bool found;
+
+ if (tagPtr->blockNum == P_NEW)
+ return (NULL);
+
+ result = (LookupEnt *)
+ hash_search(SharedBufHash, (char *) tagPtr, HASH_FIND, &found);
+
+ if (!result)
+ {
+ elog(WARN, "BufTableLookup: BufferLookup table corrupted");
+ return (NULL);
+ }
+ if (!found)
+ {
+ return (NULL);
+ }
+ return (&(BufferDescriptors[result->id]));
}
/*
* BufTableDelete
*/
bool
-BufTableDelete(BufferDesc *buf)
+BufTableDelete(BufferDesc * buf)
{
- LookupEnt * result;
- bool found;
-
- /* buffer not initialized or has been removed from
- * table already. BM_DELETED keeps us from removing
- * buffer twice.
- */
- if (buf->flags & BM_DELETED) {
- return(TRUE);
- }
-
- buf->flags |= BM_DELETED;
-
- result = (LookupEnt *)
- hash_search(SharedBufHash,(char *) &(buf->tag),HASH_REMOVE,&found);
-
- if (! (result && found)) {
- elog(WARN,"BufTableDelete: BufferLookup table corrupted");
- return(FALSE);
- }
-
- return(TRUE);
+ LookupEnt *result;
+ bool found;
+
+ /*
+ * buffer not initialized or has been removed from table already.
+ * BM_DELETED keeps us from removing buffer twice.
+ */
+ if (buf->flags & BM_DELETED)
+ {
+ return (TRUE);
+ }
+
+ buf->flags |= BM_DELETED;
+
+ result = (LookupEnt *)
+ hash_search(SharedBufHash, (char *) &(buf->tag), HASH_REMOVE, &found);
+
+ if (!(result && found))
+ {
+ elog(WARN, "BufTableDelete: BufferLookup table corrupted");
+ return (FALSE);
+ }
+
+ return (TRUE);
}
bool
-BufTableInsert(BufferDesc *buf)
+BufTableInsert(BufferDesc * buf)
{
- LookupEnt * result;
- bool found;
-
- /* cannot insert it twice */
- Assert (buf->flags & BM_DELETED);
- buf->flags &= ~(BM_DELETED);
-
- result = (LookupEnt *)
- hash_search(SharedBufHash,(char *) &(buf->tag),HASH_ENTER,&found);
-
- if (! result) {
- Assert(0);
- elog(WARN,"BufTableInsert: BufferLookup table corrupted");
- return(FALSE);
- }
- /* found something else in the table ! */
- if (found) {
- Assert(0);
- elog(WARN,"BufTableInsert: BufferLookup table corrupted");
- return(FALSE);
- }
-
- result->id = buf->buf_id;
- return(TRUE);
+ LookupEnt *result;
+ bool found;
+
+ /* cannot insert it twice */
+ Assert(buf->flags & BM_DELETED);
+ buf->flags &= ~(BM_DELETED);
+
+ result = (LookupEnt *)
+ hash_search(SharedBufHash, (char *) &(buf->tag), HASH_ENTER, &found);
+
+ if (!result)
+ {
+ Assert(0);
+ elog(WARN, "BufTableInsert: BufferLookup table corrupted");
+ return (FALSE);
+ }
+ /* found something else in the table ! */
+ if (found)
+ {
+ Assert(0);
+ elog(WARN, "BufTableInsert: BufferLookup table corrupted");
+ return (FALSE);
+ }
+
+ result->id = buf->buf_id;
+ return (TRUE);
}
/* prints out collision stats for the buf table */
@@ -157,8 +165,9 @@ BufTableInsert(BufferDesc *buf)
void
DBG_LookupListCheck(int nlookup)
{
- nlookup = 10;
-
- hash_stats("Shared",SharedBufHash);
+ nlookup = 10;
+
+ hash_stats("Shared", SharedBufHash);
}
+
#endif
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 466728c4a46..2a53e6bd78c 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -1,44 +1,44 @@
/*-------------------------------------------------------------------------
*
* bufmgr.c--
- * buffer manager interface routines
+ * buffer manager interface routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.19 1997/08/19 21:32:39 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.20 1997/09/07 04:48:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
*
* BufferAlloc() -- lookup a buffer in the buffer table. If
- * it isn't there add it, but do not read it into memory.
- * This is used when we are about to reinitialize the
- * buffer so don't care what the current disk contents are.
- * BufferAlloc() pins the new buffer in memory.
+ * it isn't there add it, but do not read it into memory.
+ * This is used when we are about to reinitialize the
+ * buffer so don't care what the current disk contents are.
+ * BufferAlloc() pins the new buffer in memory.
*
* ReadBuffer() -- same as BufferAlloc() but reads the data
- * on a buffer cache miss.
+ * on a buffer cache miss.
*
* ReleaseBuffer() -- unpin the buffer
*
* WriteNoReleaseBuffer() -- mark the buffer contents as "dirty"
- * but don't unpin. The disk IO is delayed until buffer
- * replacement if WriteMode is BUFFER_LATE_WRITE.
+ * but don't unpin. The disk IO is delayed until buffer
+ * replacement if WriteMode is BUFFER_LATE_WRITE.
*
- * WriteBuffer() -- WriteNoReleaseBuffer() + ReleaseBuffer()
+ * WriteBuffer() -- WriteNoReleaseBuffer() + ReleaseBuffer()
*
* FlushBuffer() -- as above but never delayed write.
*
* BufferSync() -- flush all dirty buffers in the buffer pool.
- *
+ *
* InitBufferPool() -- Init the buffer module.
*
- * See other files:
- * freelist.c -- chooses victim for buffer replacement
- * buf_table.c -- manages the buffer lookup table
+ * See other files:
+ * freelist.c -- chooses victim for buffer replacement
+ * buf_table.c -- manages the buffer lookup table
*/
#include <sys/types.h>
#include <sys/file.h>
@@ -66,7 +66,7 @@
#include "utils/palloc.h"
#include "utils/memutils.h"
#include "utils/relcache.h"
-#include "executor/execdebug.h" /* for NDirectFileRead */
+#include "executor/execdebug.h" /* for NDirectFileRead */
#include "catalog/catalog.h"
extern SPINLOCK BufMgrLock;
@@ -77,76 +77,88 @@ extern long int LocalBufferHitCount;
extern long int BufferFlushCount;
extern long int LocalBufferFlushCount;
-static int WriteMode = BUFFER_LATE_WRITE; /* Delayed write is default */
+static int WriteMode = BUFFER_LATE_WRITE; /* Delayed write is
+ * default */
+
+static void WaitIO(BufferDesc * buf, SPINLOCK spinlock);
-static void WaitIO(BufferDesc *buf, SPINLOCK spinlock);
#ifndef HAS_TEST_AND_SET
-static void SignalIO(BufferDesc *buf);
-extern long *NWaitIOBackendP; /* defined in buf_init.c */
-#endif /* HAS_TEST_AND_SET */
-
-static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
- bool bufferLockHeld);
-static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
- bool *foundPtr, bool bufferLockHeld);
-static int FlushBuffer (Buffer buffer, bool release);
-static void BufferSync(void);
-static int BufferReplace(BufferDesc *bufHdr, bool bufferLockHeld);
+static void SignalIO(BufferDesc * buf);
+extern long *NWaitIOBackendP;/* defined in buf_init.c */
+
+#endif /* HAS_TEST_AND_SET */
+
+static Buffer
+ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum,
+ bool bufferLockHeld);
+static BufferDesc *
+BufferAlloc(Relation reln, BlockNumber blockNum,
+ bool * foundPtr, bool bufferLockHeld);
+static int FlushBuffer(Buffer buffer, bool release);
+static void BufferSync(void);
+static int BufferReplace(BufferDesc * bufHdr, bool bufferLockHeld);
/* ---------------------------------------------------
* RelationGetBufferWithBuffer
- * see if the given buffer is what we want
- * if yes, we don't need to bother the buffer manager
+ * see if the given buffer is what we want
+ * if yes, we don't need to bother the buffer manager
* ---------------------------------------------------
*/
Buffer
RelationGetBufferWithBuffer(Relation relation,
- BlockNumber blockNumber,
- Buffer buffer)
+ BlockNumber blockNumber,
+ Buffer buffer)
{
- BufferDesc *bufHdr;
- LRelId lrelId;
-
- if (BufferIsValid(buffer)) {
- if (!BufferIsLocal(buffer)) {
- bufHdr = &BufferDescriptors[buffer-1];
- lrelId = RelationGetLRelId(relation);
- SpinAcquire(BufMgrLock);
- if (bufHdr->tag.blockNum == blockNumber &&
- bufHdr->tag.relId.relId == lrelId.relId &&
- bufHdr->tag.relId.dbId == lrelId.dbId) {
- SpinRelease(BufMgrLock);
- return(buffer);
- }
- return(ReadBufferWithBufferLock(relation, blockNumber, true));
- } else {
- bufHdr = &LocalBufferDescriptors[-buffer-1];
- if (bufHdr->tag.relId.relId == relation->rd_id &&
- bufHdr->tag.blockNum == blockNumber) {
- return(buffer);
- }
+ BufferDesc *bufHdr;
+ LRelId lrelId;
+
+ if (BufferIsValid(buffer))
+ {
+ if (!BufferIsLocal(buffer))
+ {
+ bufHdr = &BufferDescriptors[buffer - 1];
+ lrelId = RelationGetLRelId(relation);
+ SpinAcquire(BufMgrLock);
+ if (bufHdr->tag.blockNum == blockNumber &&
+ bufHdr->tag.relId.relId == lrelId.relId &&
+ bufHdr->tag.relId.dbId == lrelId.dbId)
+ {
+ SpinRelease(BufMgrLock);
+ return (buffer);
+ }
+ return (ReadBufferWithBufferLock(relation, blockNumber, true));
+ }
+ else
+ {
+ bufHdr = &LocalBufferDescriptors[-buffer - 1];
+ if (bufHdr->tag.relId.relId == relation->rd_id &&
+ bufHdr->tag.blockNum == blockNumber)
+ {
+ return (buffer);
+ }
+ }
}
- }
- return(ReadBuffer(relation, blockNumber));
+ return (ReadBuffer(relation, blockNumber));
}
/*
* ReadBuffer -- returns a buffer containing the requested
- * block of the requested relation. If the blknum
- * requested is P_NEW, extend the relation file and
- * allocate a new block.
+ * block of the requested relation. If the blknum
+ * requested is P_NEW, extend the relation file and
+ * allocate a new block.
*
* Returns: the buffer number for the buffer containing
- * the block read or NULL on an error.
+ * the block read or NULL on an error.
*
* Assume when this function is called, that reln has been
- * opened already.
+ * opened already.
*/
-extern int ShowPinTrace;
+extern int ShowPinTrace;
-#undef ReadBuffer /* conflicts with macro when BUFMGR_DEBUG defined */
+#undef ReadBuffer /* conflicts with macro when BUFMGR_DEBUG
+ * defined */
/*
* ReadBuffer --
@@ -155,7 +167,7 @@ extern int ShowPinTrace;
Buffer
ReadBuffer(Relation reln, BlockNumber blockNum)
{
- return ReadBufferWithBufferLock(reln, blockNum, false);
+ return ReadBufferWithBufferLock(reln, blockNum, false);
}
/*
@@ -164,156 +176,176 @@ ReadBuffer(Relation reln, BlockNumber blockNum)
* XXX caller must have already acquired BufMgrLock
*/
#ifdef NOT_USED
-static bool
+static bool
is_userbuffer(Buffer buffer)
{
- BufferDesc *buf = &BufferDescriptors[buffer-1];
-
- if (IsSystemRelationName(buf->sb_relname))
- return false;
- return true;
+ BufferDesc *buf = &BufferDescriptors[buffer - 1];
+
+ if (IsSystemRelationName(buf->sb_relname))
+ return false;
+ return true;
}
+
#endif
#ifdef NOT_USED
Buffer
ReadBuffer_Debug(char *file,
- int line,
- Relation reln,
- BlockNumber blockNum)
+ int line,
+ Relation reln,
+ BlockNumber blockNum)
{
- Buffer buffer;
-
- buffer = ReadBufferWithBufferLock(reln, blockNum, false);
- if (ShowPinTrace && !BufferIsLocal(buffer) && is_userbuffer(buffer)) {
- BufferDesc *buf = &BufferDescriptors[buffer-1];
-
- fprintf(stderr, "PIN(RD) %ld relname = %s, blockNum = %d, \
+ Buffer buffer;
+
+ buffer = ReadBufferWithBufferLock(reln, blockNum, false);
+ if (ShowPinTrace && !BufferIsLocal(buffer) && is_userbuffer(buffer))
+ {
+ BufferDesc *buf = &BufferDescriptors[buffer - 1];
+
+ fprintf(stderr, "PIN(RD) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
- buffer, buf->sb_relname, buf->tag.blockNum,
- PrivateRefCount[buffer - 1], file, line);
- }
- return buffer;
+ buffer, buf->sb_relname, buf->tag.blockNum,
+ PrivateRefCount[buffer - 1], file, line);
+ }
+ return buffer;
}
+
#endif
/*
- * ReadBufferWithBufferLock -- does the work of
- * ReadBuffer() but with the possibility that
- * the buffer lock has already been held. this
- * is yet another effort to reduce the number of
- * semops in the system.
+ * ReadBufferWithBufferLock -- does the work of
+ * ReadBuffer() but with the possibility that
+ * the buffer lock has already been held. this
+ * is yet another effort to reduce the number of
+ * semops in the system.
*/
-static Buffer
+static Buffer
ReadBufferWithBufferLock(Relation reln,
- BlockNumber blockNum,
- bool bufferLockHeld)
+ BlockNumber blockNum,
+ bool bufferLockHeld)
{
- BufferDesc *bufHdr;
- int extend; /* extending the file by one block */
- int status;
- bool found;
- bool isLocalBuf;
-
- extend = (blockNum == P_NEW);
- isLocalBuf = reln->rd_islocal;
-
- if (isLocalBuf) {
- ReadLocalBufferCount++;
- bufHdr = LocalBufferAlloc(reln, blockNum, &found);
- if (found) LocalBufferHitCount++;
- } else {
- ReadBufferCount++;
-
- /* lookup the buffer. IO_IN_PROGRESS is set if the requested
- * block is not currently in memory.
- */
- bufHdr = BufferAlloc(reln, blockNum, &found, bufferLockHeld);
- if (found) BufferHitCount++;
- }
-
- if (!bufHdr) {
- return(InvalidBuffer);
- }
-
- /* if its already in the buffer pool, we're done */
- if (found) {
+ BufferDesc *bufHdr;
+ int extend; /* extending the file by one block */
+ int status;
+ bool found;
+ bool isLocalBuf;
+
+ extend = (blockNum == P_NEW);
+ isLocalBuf = reln->rd_islocal;
+
+ if (isLocalBuf)
+ {
+ ReadLocalBufferCount++;
+ bufHdr = LocalBufferAlloc(reln, blockNum, &found);
+ if (found)
+ LocalBufferHitCount++;
+ }
+ else
+ {
+ ReadBufferCount++;
+
+ /*
+ * lookup the buffer. IO_IN_PROGRESS is set if the requested
+ * block is not currently in memory.
+ */
+ bufHdr = BufferAlloc(reln, blockNum, &found, bufferLockHeld);
+ if (found)
+ BufferHitCount++;
+ }
+
+ if (!bufHdr)
+ {
+ return (InvalidBuffer);
+ }
+
+ /* if its already in the buffer pool, we're done */
+ if (found)
+ {
+
+ /*
+ * This happens when a bogus buffer was returned previously and is
+ * floating around in the buffer pool. A routine calling this
+ * would want this extended.
+ */
+ if (extend)
+ {
+ /* new buffers are zero-filled */
+ memset((char *) MAKE_PTR(bufHdr->data), 0, BLCKSZ);
+ smgrextend(bufHdr->bufsmgr, reln,
+ (char *) MAKE_PTR(bufHdr->data));
+ }
+ return (BufferDescriptorGetBuffer(bufHdr));
+
+ }
+
/*
- * This happens when a bogus buffer was returned previously and is
- * floating around in the buffer pool. A routine calling this would
- * want this extended.
+ * if we have gotten to this point, the reln pointer must be ok and
+ * the relation file must be open.
*/
- if (extend) {
- /* new buffers are zero-filled */
- memset((char *) MAKE_PTR(bufHdr->data), 0, BLCKSZ);
- smgrextend(bufHdr->bufsmgr, reln,
- (char *) MAKE_PTR(bufHdr->data));
+ if (extend)
+ {
+ /* new buffers are zero-filled */
+ memset((char *) MAKE_PTR(bufHdr->data), 0, BLCKSZ);
+ status = smgrextend(bufHdr->bufsmgr, reln,
+ (char *) MAKE_PTR(bufHdr->data));
}
- return (BufferDescriptorGetBuffer(bufHdr));
-
- }
-
- /*
- * if we have gotten to this point, the reln pointer must be ok
- * and the relation file must be open.
- */
- if (extend) {
- /* new buffers are zero-filled */
- memset((char *) MAKE_PTR(bufHdr->data), 0, BLCKSZ);
- status = smgrextend(bufHdr->bufsmgr, reln,
- (char *) MAKE_PTR(bufHdr->data));
- } else {
- status = smgrread(bufHdr->bufsmgr, reln, blockNum,
- (char *) MAKE_PTR(bufHdr->data));
- }
-
- if (isLocalBuf)
- return (BufferDescriptorGetBuffer(bufHdr));
+ else
+ {
+ status = smgrread(bufHdr->bufsmgr, reln, blockNum,
+ (char *) MAKE_PTR(bufHdr->data));
+ }
+
+ if (isLocalBuf)
+ return (BufferDescriptorGetBuffer(bufHdr));
+
+ /* lock buffer manager again to update IO IN PROGRESS */
+ SpinAcquire(BufMgrLock);
+
+ if (status == SM_FAIL)
+ {
+ /* IO Failed. cleanup the data structures and go home */
+
+ if (!BufTableDelete(bufHdr))
+ {
+ SpinRelease(BufMgrLock);
+ elog(FATAL, "BufRead: buffer table broken after IO error\n");
+ }
+ /* remember that BufferAlloc() pinned the buffer */
+ UnpinBuffer(bufHdr);
- /* lock buffer manager again to update IO IN PROGRESS */
- SpinAcquire(BufMgrLock);
-
- if (status == SM_FAIL) {
- /* IO Failed. cleanup the data structures and go home */
-
- if (! BufTableDelete(bufHdr)) {
- SpinRelease(BufMgrLock);
- elog(FATAL,"BufRead: buffer table broken after IO error\n");
+ /*
+ * Have to reset the flag so that anyone waiting for the buffer
+ * can tell that the contents are invalid.
+ */
+ bufHdr->flags |= BM_IO_ERROR;
+ bufHdr->flags &= ~BM_IO_IN_PROGRESS;
}
- /* remember that BufferAlloc() pinned the buffer */
- UnpinBuffer(bufHdr);
-
- /*
- * Have to reset the flag so that anyone waiting for
- * the buffer can tell that the contents are invalid.
- */
- bufHdr->flags |= BM_IO_ERROR;
- bufHdr->flags &= ~BM_IO_IN_PROGRESS;
- } else {
- /* IO Succeeded. clear the flags, finish buffer update */
-
- bufHdr->flags &= ~(BM_IO_ERROR | BM_IO_IN_PROGRESS);
- }
-
- /* If anyone was waiting for IO to complete, wake them up now */
+ else
+ {
+ /* IO Succeeded. clear the flags, finish buffer update */
+
+ bufHdr->flags &= ~(BM_IO_ERROR | BM_IO_IN_PROGRESS);
+ }
+
+ /* If anyone was waiting for IO to complete, wake them up now */
#ifdef HAS_TEST_AND_SET
- S_UNLOCK(&(bufHdr->io_in_progress_lock));
+ S_UNLOCK(&(bufHdr->io_in_progress_lock));
#else
- if (bufHdr->refcount > 1)
- SignalIO(bufHdr);
+ if (bufHdr->refcount > 1)
+ SignalIO(bufHdr);
#endif
-
- SpinRelease(BufMgrLock);
-
- if (status == SM_FAIL)
- return(InvalidBuffer);
-
- return(BufferDescriptorGetBuffer(bufHdr));
+
+ SpinRelease(BufMgrLock);
+
+ if (status == SM_FAIL)
+ return (InvalidBuffer);
+
+ return (BufferDescriptorGetBuffer(bufHdr));
}
/*
* BufferAlloc -- Get a buffer from the buffer pool but dont
- * read it.
+ * read it.
*
* Returns: descriptor for buffer
*
@@ -321,321 +353,339 @@ ReadBufferWithBufferLock(Relation reln,
*/
static BufferDesc *
BufferAlloc(Relation reln,
- BlockNumber blockNum,
- bool *foundPtr,
- bool bufferLockHeld)
+ BlockNumber blockNum,
+ bool * foundPtr,
+ bool bufferLockHeld)
{
- BufferDesc *buf, *buf2;
- BufferTag newTag; /* identity of requested block */
- bool inProgress; /* buffer undergoing IO */
- bool newblock = FALSE;
-
- /* create a new tag so we can lookup the buffer */
- /* assume that the relation is already open */
- if (blockNum == P_NEW) {
- newblock = TRUE;
- blockNum = smgrnblocks(reln->rd_rel->relsmgr, reln);
- }
-
- INIT_BUFFERTAG(&newTag,reln,blockNum);
-
- if (!bufferLockHeld)
- SpinAcquire(BufMgrLock);
-
- /* see if the block is in the buffer pool already */
- buf = BufTableLookup(&newTag);
- if (buf != NULL) {
- /* Found it. Now, (a) pin the buffer so no
- * one steals it from the buffer pool,
- * (b) check IO_IN_PROGRESS, someone may be
- * faulting the buffer into the buffer pool.
- */
-
- PinBuffer(buf);
- inProgress = (buf->flags & BM_IO_IN_PROGRESS);
-
- *foundPtr = TRUE;
- if (inProgress) {
- WaitIO(buf, BufMgrLock);
- if (buf->flags & BM_IO_ERROR) {
- /* wierd race condition:
- *
- * We were waiting for someone else to read the buffer.
- * While we were waiting, the reader boof'd in some
- * way, so the contents of the buffer are still
- * invalid. By saying that we didn't find it, we can
- * make the caller reinitialize the buffer. If two
- * processes are waiting for this block, both will
- * read the block. The second one to finish may overwrite
- * any updates made by the first. (Assume higher level
- * synchronization prevents this from happening).
- *
- * This is never going to happen, don't worry about it.
- */
- *foundPtr = FALSE;
- }
+ BufferDesc *buf,
+ *buf2;
+ BufferTag newTag; /* identity of requested block */
+ bool inProgress; /* buffer undergoing IO */
+ bool newblock = FALSE;
+
+ /* create a new tag so we can lookup the buffer */
+ /* assume that the relation is already open */
+ if (blockNum == P_NEW)
+ {
+ newblock = TRUE;
+ blockNum = smgrnblocks(reln->rd_rel->relsmgr, reln);
}
+
+ INIT_BUFFERTAG(&newTag, reln, blockNum);
+
+ if (!bufferLockHeld)
+ SpinAcquire(BufMgrLock);
+
+ /* see if the block is in the buffer pool already */
+ buf = BufTableLookup(&newTag);
+ if (buf != NULL)
+ {
+
+ /*
+ * Found it. Now, (a) pin the buffer so no one steals it from the
+ * buffer pool, (b) check IO_IN_PROGRESS, someone may be faulting
+ * the buffer into the buffer pool.
+ */
+
+ PinBuffer(buf);
+ inProgress = (buf->flags & BM_IO_IN_PROGRESS);
+
+ *foundPtr = TRUE;
+ if (inProgress)
+ {
+ WaitIO(buf, BufMgrLock);
+ if (buf->flags & BM_IO_ERROR)
+ {
+
+ /*
+ * wierd race condition:
+ *
+ * We were waiting for someone else to read the buffer. While
+ * we were waiting, the reader boof'd in some way, so the
+ * contents of the buffer are still invalid. By saying
+ * that we didn't find it, we can make the caller
+ * reinitialize the buffer. If two processes are waiting
+ * for this block, both will read the block. The second
+ * one to finish may overwrite any updates made by the
+ * first. (Assume higher level synchronization prevents
+ * this from happening).
+ *
+ * This is never going to happen, don't worry about it.
+ */
+ *foundPtr = FALSE;
+ }
+ }
#ifdef BMTRACE
- _bm_trace((reln->rd_rel->relisshared ? 0 : MyDatabaseId), reln->rd_id, blockNum, BufferDescriptorGetBuffer(buf), BMT_ALLOCFND);
-#endif /* BMTRACE */
-
- SpinRelease(BufMgrLock);
-
- return(buf);
- }
-
- *foundPtr = FALSE;
-
- /*
- * Didn't find it in the buffer pool. We'll have
- * to initialize a new buffer. First, grab one from
- * the free list. If it's dirty, flush it to disk.
- * Remember to unlock BufMgr spinlock while doing the IOs.
- */
- inProgress = FALSE;
- for (buf = (BufferDesc *) NULL; buf == (BufferDesc *) NULL; ) {
-
- /* GetFreeBuffer will abort if it can't find a free buffer */
- buf = GetFreeBuffer();
-
- /*
- * But it can return buf == NULL if we are in aborting
- * transaction now and so elog(WARN,...) in GetFreeBuffer
- * will not abort again.
- */
- if ( buf == NULL )
- return (NULL);
-
+ _bm_trace((reln->rd_rel->relisshared ? 0 : MyDatabaseId), reln->rd_id, blockNum, BufferDescriptorGetBuffer(buf), BMT_ALLOCFND);
+#endif /* BMTRACE */
+
+ SpinRelease(BufMgrLock);
+
+ return (buf);
+ }
+
+ *foundPtr = FALSE;
+
/*
- * There should be exactly one pin on the buffer after
- * it is allocated -- ours. If it had a pin it wouldn't
- * have been on the free list. No one else could have
- * pinned it between GetFreeBuffer and here because we
- * have the BufMgrLock.
+ * Didn't find it in the buffer pool. We'll have to initialize a new
+ * buffer. First, grab one from the free list. If it's dirty, flush
+ * it to disk. Remember to unlock BufMgr spinlock while doing the IOs.
*/
- Assert(buf->refcount == 0);
- buf->refcount = 1;
- PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 1;
-
- if (buf->flags & BM_DIRTY) {
- bool smok;
- /*
- * Set BM_IO_IN_PROGRESS to keep anyone from doing anything
- * with the contents of the buffer while we write it out.
- * We don't really care if they try to read it, but if they
- * can complete a BufferAlloc on it they can then scribble
- * into it, and we'd really like to avoid that while we are
- * flushing the buffer. Setting this flag should block them
- * in WaitIO until we're done.
- */
- inProgress = TRUE;
- buf->flags |= BM_IO_IN_PROGRESS;
-#ifdef HAS_TEST_AND_SET
- /*
- * All code paths that acquire this lock pin the buffer
- * first; since no one had it pinned (it just came off the
- * free list), no one else can have this lock.
- */
- Assert(S_LOCK_FREE(&(buf->io_in_progress_lock)));
- S_LOCK(&(buf->io_in_progress_lock));
-#endif /* HAS_TEST_AND_SET */
-
- /*
- * Write the buffer out, being careful to release BufMgrLock
- * before starting the I/O.
- *
- * This #ifndef is here because a few extra semops REALLY kill
- * you on machines that don't have spinlocks. If you don't
- * operate with much concurrency, well...
- */
- smok = BufferReplace(buf, true);
-#ifndef OPTIMIZE_SINGLE
- SpinAcquire(BufMgrLock);
-#endif /* OPTIMIZE_SINGLE */
-
- if ( smok == FALSE )
- {
- elog(NOTICE, "BufferAlloc: cannot write block %u for %s/%s",
- buf->tag.blockNum, buf->sb_dbname, buf->sb_relname);
- inProgress = FALSE;
- buf->flags |= BM_IO_ERROR;
- buf->flags &= ~BM_IO_IN_PROGRESS;
-#ifdef HAS_TEST_AND_SET
- S_UNLOCK(&(buf->io_in_progress_lock));
-#else /* !HAS_TEST_AND_SET */
- if (buf->refcount > 1)
- SignalIO(buf);
-#endif /* !HAS_TEST_AND_SET */
- PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
- buf->refcount--;
- if ( buf->refcount == 0 )
- {
- AddBufferToFreelist(buf);
- buf->flags |= BM_FREE;
- }
- buf = (BufferDesc *) NULL;
- }
- else
- {
+ inProgress = FALSE;
+ for (buf = (BufferDesc *) NULL; buf == (BufferDesc *) NULL;)
+ {
+
+ /* GetFreeBuffer will abort if it can't find a free buffer */
+ buf = GetFreeBuffer();
+
/*
- * BM_JUST_DIRTIED cleared by BufferReplace and shouldn't
- * be setted by anyone. - vadim 01/17/97
+ * But it can return buf == NULL if we are in aborting transaction
+ * now and so elog(WARN,...) in GetFreeBuffer will not abort
+ * again.
*/
- if ( buf->flags & BM_JUST_DIRTIED )
- {
- elog (FATAL, "BufferAlloc: content of block %u (%s) changed while flushing",
- buf->tag.blockNum, buf->sb_relname);
- }
- else
- {
- buf->flags &= ~BM_DIRTY;
- }
- }
-
- /*
- * Somebody could have pinned the buffer while we were
- * doing the I/O and had given up the BufMgrLock (though
- * they would be waiting for us to clear the BM_IO_IN_PROGRESS
- * flag). That's why this is a loop -- if so, we need to clear
- * the I/O flags, remove our pin and start all over again.
- *
- * People may be making buffers free at any time, so there's
- * no reason to think that we have an immediate disaster on
- * our hands.
- */
- if ( buf && buf->refcount > 1 )
- {
- inProgress = FALSE;
- buf->flags &= ~BM_IO_IN_PROGRESS;
-#ifdef HAS_TEST_AND_SET
- S_UNLOCK(&(buf->io_in_progress_lock));
-#else /* !HAS_TEST_AND_SET */
- if (buf->refcount > 1)
- SignalIO(buf);
-#endif /* !HAS_TEST_AND_SET */
- PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
- buf->refcount--;
- buf = (BufferDesc *) NULL;
- }
-
- /*
- * Somebody could have allocated another buffer for the
- * same block we are about to read in. (While we flush out
- * the dirty buffer, we don't hold the lock and someone could
- * have allocated another buffer for the same block. The problem
- * is we haven't gotten around to insert the new tag into
- * the buffer table. So we need to check here. -ay 3/95
- */
- buf2 = BufTableLookup(&newTag);
- if (buf2 != NULL) {
- /* Found it. Someone has already done what we're about
- * to do. We'll just handle this as if it were found in
- * the buffer pool in the first place.
+ if (buf == NULL)
+ return (NULL);
+
+ /*
+ * There should be exactly one pin on the buffer after it is
+ * allocated -- ours. If it had a pin it wouldn't have been on
+ * the free list. No one else could have pinned it between
+ * GetFreeBuffer and here because we have the BufMgrLock.
*/
- if ( buf != NULL )
+ Assert(buf->refcount == 0);
+ buf->refcount = 1;
+ PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 1;
+
+ if (buf->flags & BM_DIRTY)
{
+ bool smok;
+
+ /*
+ * Set BM_IO_IN_PROGRESS to keep anyone from doing anything
+ * with the contents of the buffer while we write it out. We
+ * don't really care if they try to read it, but if they can
+ * complete a BufferAlloc on it they can then scribble into
+ * it, and we'd really like to avoid that while we are
+ * flushing the buffer. Setting this flag should block them
+ * in WaitIO until we're done.
+ */
+ inProgress = TRUE;
+ buf->flags |= BM_IO_IN_PROGRESS;
#ifdef HAS_TEST_AND_SET
- S_UNLOCK(&(buf->io_in_progress_lock));
-#else /* !HAS_TEST_AND_SET */
- if (buf->refcount > 1)
- SignalIO(buf);
-#endif /* !HAS_TEST_AND_SET */
-
- /* give up the buffer since we don't need it any more */
- buf->refcount--;
- PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
- AddBufferToFreelist(buf);
- buf->flags |= BM_FREE;
- buf->flags &= ~BM_IO_IN_PROGRESS;
- }
- PinBuffer(buf2);
- inProgress = (buf2->flags & BM_IO_IN_PROGRESS);
-
- *foundPtr = TRUE;
- if (inProgress) {
- WaitIO(buf2, BufMgrLock);
- if (buf2->flags & BM_IO_ERROR) {
- *foundPtr = FALSE;
- }
+ /*
+ * All code paths that acquire this lock pin the buffer first;
+ * since no one had it pinned (it just came off the free
+ * list), no one else can have this lock.
+ */
+ Assert(S_LOCK_FREE(&(buf->io_in_progress_lock)));
+ S_LOCK(&(buf->io_in_progress_lock));
+#endif /* HAS_TEST_AND_SET */
+
+ /*
+ * Write the buffer out, being careful to release BufMgrLock
+ * before starting the I/O.
+ *
+ * This #ifndef is here because a few extra semops REALLY kill
+ * you on machines that don't have spinlocks. If you don't
+ * operate with much concurrency, well...
+ */
+ smok = BufferReplace(buf, true);
+#ifndef OPTIMIZE_SINGLE
+ SpinAcquire(BufMgrLock);
+#endif /* OPTIMIZE_SINGLE */
+
+ if (smok == FALSE)
+ {
+ elog(NOTICE, "BufferAlloc: cannot write block %u for %s/%s",
+ buf->tag.blockNum, buf->sb_dbname, buf->sb_relname);
+ inProgress = FALSE;
+ buf->flags |= BM_IO_ERROR;
+ buf->flags &= ~BM_IO_IN_PROGRESS;
+#ifdef HAS_TEST_AND_SET
+ S_UNLOCK(&(buf->io_in_progress_lock));
+#else /* !HAS_TEST_AND_SET */
+ if (buf->refcount > 1)
+ SignalIO(buf);
+#endif /* !HAS_TEST_AND_SET */
+ PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
+ buf->refcount--;
+ if (buf->refcount == 0)
+ {
+ AddBufferToFreelist(buf);
+ buf->flags |= BM_FREE;
+ }
+ buf = (BufferDesc *) NULL;
+ }
+ else
+ {
+
+ /*
+ * BM_JUST_DIRTIED cleared by BufferReplace and shouldn't
+ * be setted by anyone. - vadim 01/17/97
+ */
+ if (buf->flags & BM_JUST_DIRTIED)
+ {
+ elog(FATAL, "BufferAlloc: content of block %u (%s) changed while flushing",
+ buf->tag.blockNum, buf->sb_relname);
+ }
+ else
+ {
+ buf->flags &= ~BM_DIRTY;
+ }
+ }
+
+ /*
+ * Somebody could have pinned the buffer while we were doing
+ * the I/O and had given up the BufMgrLock (though they would
+ * be waiting for us to clear the BM_IO_IN_PROGRESS flag).
+ * That's why this is a loop -- if so, we need to clear the
+ * I/O flags, remove our pin and start all over again.
+ *
+ * People may be making buffers free at any time, so there's no
+ * reason to think that we have an immediate disaster on our
+ * hands.
+ */
+ if (buf && buf->refcount > 1)
+ {
+ inProgress = FALSE;
+ buf->flags &= ~BM_IO_IN_PROGRESS;
+#ifdef HAS_TEST_AND_SET
+ S_UNLOCK(&(buf->io_in_progress_lock));
+#else /* !HAS_TEST_AND_SET */
+ if (buf->refcount > 1)
+ SignalIO(buf);
+#endif /* !HAS_TEST_AND_SET */
+ PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
+ buf->refcount--;
+ buf = (BufferDesc *) NULL;
+ }
+
+ /*
+ * Somebody could have allocated another buffer for the same
+ * block we are about to read in. (While we flush out the
+ * dirty buffer, we don't hold the lock and someone could have
+ * allocated another buffer for the same block. The problem is
+ * we haven't gotten around to insert the new tag into the
+ * buffer table. So we need to check here. -ay 3/95
+ */
+ buf2 = BufTableLookup(&newTag);
+ if (buf2 != NULL)
+ {
+
+ /*
+ * Found it. Someone has already done what we're about to
+ * do. We'll just handle this as if it were found in the
+ * buffer pool in the first place.
+ */
+ if (buf != NULL)
+ {
+#ifdef HAS_TEST_AND_SET
+ S_UNLOCK(&(buf->io_in_progress_lock));
+#else /* !HAS_TEST_AND_SET */
+ if (buf->refcount > 1)
+ SignalIO(buf);
+#endif /* !HAS_TEST_AND_SET */
+
+ /* give up the buffer since we don't need it any more */
+ buf->refcount--;
+ PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
+ AddBufferToFreelist(buf);
+ buf->flags |= BM_FREE;
+ buf->flags &= ~BM_IO_IN_PROGRESS;
+ }
+
+ PinBuffer(buf2);
+ inProgress = (buf2->flags & BM_IO_IN_PROGRESS);
+
+ *foundPtr = TRUE;
+ if (inProgress)
+ {
+ WaitIO(buf2, BufMgrLock);
+ if (buf2->flags & BM_IO_ERROR)
+ {
+ *foundPtr = FALSE;
+ }
+ }
+
+ SpinRelease(BufMgrLock);
+
+ return (buf2);
+ }
}
-
+ }
+
+ /*
+ * At this point we should have the sole pin on a non-dirty buffer and
+ * we may or may not already have the BM_IO_IN_PROGRESS flag set.
+ */
+
+ /*
+ * Change the name of the buffer in the lookup table:
+ *
+ * Need to update the lookup table before the read starts. If someone
+ * comes along looking for the buffer while we are reading it in, we
+ * don't want them to allocate a new buffer. For the same reason, we
+ * didn't want to erase the buf table entry for the buffer we were
+ * writing back until now, either.
+ */
+
+ if (!BufTableDelete(buf))
+ {
SpinRelease(BufMgrLock);
-
- return(buf2);
- }
+ elog(FATAL, "buffer wasn't in the buffer table\n");
+
}
- }
- /*
- * At this point we should have the sole pin on a non-dirty
- * buffer and we may or may not already have the BM_IO_IN_PROGRESS
- * flag set.
- */
-
- /*
- * Change the name of the buffer in the lookup table:
- *
- * Need to update the lookup table before the read starts.
- * If someone comes along looking for the buffer while
- * we are reading it in, we don't want them to allocate
- * a new buffer. For the same reason, we didn't want
- * to erase the buf table entry for the buffer we were
- * writing back until now, either.
- */
-
- if (! BufTableDelete(buf)) {
- SpinRelease(BufMgrLock);
- elog(FATAL,"buffer wasn't in the buffer table\n");
-
- }
-
- /* record the database name and relation name for this buffer */
- strcpy (buf->sb_relname, reln->rd_rel->relname.data);
- strcpy (buf->sb_dbname, GetDatabaseName());
-
- /* remember which storage manager is responsible for it */
- buf->bufsmgr = reln->rd_rel->relsmgr;
-
- INIT_BUFFERTAG(&(buf->tag),reln,blockNum);
- if (! BufTableInsert(buf)) {
- SpinRelease(BufMgrLock);
- elog(FATAL,"Buffer in lookup table twice \n");
- }
-
- /* Buffer contents are currently invalid. Have
- * to mark IO IN PROGRESS so no one fiddles with
- * them until the read completes. If this routine
- * has been called simply to allocate a buffer, no
- * io will be attempted, so the flag isnt set.
- */
- if (!inProgress) {
- buf->flags |= BM_IO_IN_PROGRESS;
+
+ /* record the database name and relation name for this buffer */
+ strcpy(buf->sb_relname, reln->rd_rel->relname.data);
+ strcpy(buf->sb_dbname, GetDatabaseName());
+
+ /* remember which storage manager is responsible for it */
+ buf->bufsmgr = reln->rd_rel->relsmgr;
+
+ INIT_BUFFERTAG(&(buf->tag), reln, blockNum);
+ if (!BufTableInsert(buf))
+ {
+ SpinRelease(BufMgrLock);
+ elog(FATAL, "Buffer in lookup table twice \n");
+ }
+
+ /*
+ * Buffer contents are currently invalid. Have to mark IO IN PROGRESS
+ * so no one fiddles with them until the read completes. If this
+ * routine has been called simply to allocate a buffer, no io will be
+ * attempted, so the flag isnt set.
+ */
+ if (!inProgress)
+ {
+ buf->flags |= BM_IO_IN_PROGRESS;
#ifdef HAS_TEST_AND_SET
- Assert(S_LOCK_FREE(&(buf->io_in_progress_lock)));
- S_LOCK(&(buf->io_in_progress_lock));
-#endif /* HAS_TEST_AND_SET */
- }
-
+ Assert(S_LOCK_FREE(&(buf->io_in_progress_lock)));
+ S_LOCK(&(buf->io_in_progress_lock));
+#endif /* HAS_TEST_AND_SET */
+ }
+
#ifdef BMTRACE
- _bm_trace((reln->rd_rel->relisshared ? 0 : MyDatabaseId), reln->rd_id, blockNum, BufferDescriptorGetBuffer(buf), BMT_ALLOCNOTFND);
-#endif /* BMTRACE */
-
- SpinRelease(BufMgrLock);
-
- return (buf);
+ _bm_trace((reln->rd_rel->relisshared ? 0 : MyDatabaseId), reln->rd_id, blockNum, BufferDescriptorGetBuffer(buf), BMT_ALLOCNOTFND);
+#endif /* BMTRACE */
+
+ SpinRelease(BufMgrLock);
+
+ return (buf);
}
/*
* WriteBuffer--
*
- * Pushes buffer contents to disk if WriteMode is BUFFER_FLUSH_WRITE.
- * Otherwise, marks contents as dirty.
+ * Pushes buffer contents to disk if WriteMode is BUFFER_FLUSH_WRITE.
+ * Otherwise, marks contents as dirty.
*
* Assume that buffer is pinned. Assume that reln is
- * valid.
+ * valid.
*
* Side Effects:
- * Pin count is decremented.
+ * Pin count is decremented.
*/
#undef WriteBuffer
@@ -643,92 +693,103 @@ BufferAlloc(Relation reln,
int
WriteBuffer(Buffer buffer)
{
- BufferDesc *bufHdr;
+ BufferDesc *bufHdr;
- if (WriteMode == BUFFER_FLUSH_WRITE) {
- return (FlushBuffer (buffer, TRUE));
- } else {
+ if (WriteMode == BUFFER_FLUSH_WRITE)
+ {
+ return (FlushBuffer(buffer, TRUE));
+ }
+ else
+ {
- if (BufferIsLocal(buffer))
- return WriteLocalBuffer(buffer, TRUE);
-
- if (BAD_BUFFER_ID(buffer))
- return(FALSE);
+ if (BufferIsLocal(buffer))
+ return WriteLocalBuffer(buffer, TRUE);
- bufHdr = &BufferDescriptors[buffer-1];
-
- SpinAcquire(BufMgrLock);
- Assert(bufHdr->refcount > 0);
- bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
- UnpinBuffer(bufHdr);
- SpinRelease(BufMgrLock);
- CommitInfoNeedsSave[buffer - 1] = 0;
- }
- return(TRUE);
-}
+ if (BAD_BUFFER_ID(buffer))
+ return (FALSE);
+
+ bufHdr = &BufferDescriptors[buffer - 1];
+
+ SpinAcquire(BufMgrLock);
+ Assert(bufHdr->refcount > 0);
+ bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
+ UnpinBuffer(bufHdr);
+ SpinRelease(BufMgrLock);
+ CommitInfoNeedsSave[buffer - 1] = 0;
+ }
+ return (TRUE);
+}
#ifdef NOT_USED
void
WriteBuffer_Debug(char *file, int line, Buffer buffer)
{
- WriteBuffer(buffer);
- if (ShowPinTrace && BufferIsLocal(buffer) && is_userbuffer(buffer)) {
- BufferDesc *buf;
- buf = &BufferDescriptors[buffer-1];
- fprintf(stderr, "UNPIN(WR) %ld relname = %s, blockNum = %d, \
+ WriteBuffer(buffer);
+ if (ShowPinTrace && BufferIsLocal(buffer) && is_userbuffer(buffer))
+ {
+ BufferDesc *buf;
+
+ buf = &BufferDescriptors[buffer - 1];
+ fprintf(stderr, "UNPIN(WR) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
- buffer, buf->sb_relname, buf->tag.blockNum,
- PrivateRefCount[buffer - 1], file, line);
- }
+ buffer, buf->sb_relname, buf->tag.blockNum,
+ PrivateRefCount[buffer - 1], file, line);
+ }
}
+
#endif
/*
* DirtyBufferCopy() -- For a given dbid/relid/blockno, if the buffer is
- * in the cache and is dirty, mark it clean and copy
- * it to the requested location. This is a logical
- * write, and has been installed to support the cache
- * management code for write-once storage managers.
+ * in the cache and is dirty, mark it clean and copy
+ * it to the requested location. This is a logical
+ * write, and has been installed to support the cache
+ * management code for write-once storage managers.
*
- * DirtyBufferCopy() -- Copy a given dirty buffer to the requested
- * destination.
+ * DirtyBufferCopy() -- Copy a given dirty buffer to the requested
+ * destination.
*
- * We treat this as a write. If the requested buffer is in the pool
- * and is dirty, we copy it to the location requested and mark it
- * clean. This routine supports the Sony jukebox storage manager,
- * which agrees to take responsibility for the data once we mark
- * it clean.
+ * We treat this as a write. If the requested buffer is in the pool
+ * and is dirty, we copy it to the location requested and mark it
+ * clean. This routine supports the Sony jukebox storage manager,
+ * which agrees to take responsibility for the data once we mark
+ * it clean.
*
- * NOTE: used by sony jukebox code in postgres 4.2 - ay 2/95
+ * NOTE: used by sony jukebox code in postgres 4.2 - ay 2/95
*/
#ifdef NOT_USED
void
DirtyBufferCopy(Oid dbid, Oid relid, BlockNumber blkno, char *dest)
{
- BufferDesc *buf;
- BufferTag btag;
-
- btag.relId.relId = relid;
- btag.relId.dbId = dbid;
- btag.blockNum = blkno;
-
- SpinAcquire(BufMgrLock);
- buf = BufTableLookup(&btag);
-
- if (buf == (BufferDesc *) NULL
- || !(buf->flags & BM_DIRTY)
- || !(buf->flags & BM_VALID)) {
+ BufferDesc *buf;
+ BufferTag btag;
+
+ btag.relId.relId = relid;
+ btag.relId.dbId = dbid;
+ btag.blockNum = blkno;
+
+ SpinAcquire(BufMgrLock);
+ buf = BufTableLookup(&btag);
+
+ if (buf == (BufferDesc *) NULL
+ || !(buf->flags & BM_DIRTY)
+ || !(buf->flags & BM_VALID))
+ {
+ SpinRelease(BufMgrLock);
+ return;
+ }
+
+ /*
+ * hate to do this holding the lock, but release and reacquire is
+ * slower
+ */
+ memmove(dest, (char *) MAKE_PTR(buf->data), BLCKSZ);
+
+ buf->flags &= ~BM_DIRTY;
+
SpinRelease(BufMgrLock);
- return;
- }
-
- /* hate to do this holding the lock, but release and reacquire is slower */
- memmove(dest, (char *) MAKE_PTR(buf->data), BLCKSZ);
-
- buf->flags &= ~BM_DIRTY;
-
- SpinRelease(BufMgrLock);
}
+
#endif
/*
@@ -742,504 +803,541 @@ DirtyBufferCopy(Oid dbid, Oid relid, BlockNumber blkno, char *dest)
static int
FlushBuffer(Buffer buffer, bool release)
{
- BufferDesc *bufHdr;
- Oid bufdb;
- Relation bufrel;
- int status;
-
- if (BufferIsLocal(buffer))
- return FlushLocalBuffer(buffer, release);
-
- if (BAD_BUFFER_ID(buffer))
- return (STATUS_ERROR);
-
- bufHdr = &BufferDescriptors[buffer-1];
- bufdb = bufHdr->tag.relId.dbId;
-
- Assert (bufdb == MyDatabaseId || bufdb == (Oid) NULL);
- bufrel = RelationIdCacheGetRelation (bufHdr->tag.relId.relId);
- Assert (bufrel != (Relation) NULL);
-
- /* To check if block content changed while flushing. - vadim 01/17/97 */
- SpinAcquire(BufMgrLock);
- bufHdr->flags &= ~BM_JUST_DIRTIED;
- SpinRelease(BufMgrLock);
-
- status = smgrflush(bufHdr->bufsmgr, bufrel, bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data));
-
- if (status == SM_FAIL)
- {
- elog(WARN, "FlushBuffer: cannot flush block %u of the relation %s",
- bufHdr->tag.blockNum, bufHdr->sb_relname);
- return (STATUS_ERROR);
- }
- BufferFlushCount++;
-
- SpinAcquire(BufMgrLock);
- /*
- * If this buffer was marked by someone as DIRTY while
- * we were flushing it out we must not clear DIRTY flag
- * - vadim 01/17/97
- */
- if ( bufHdr->flags & BM_JUST_DIRTIED )
- {
- elog (NOTICE, "FlusfBuffer: content of block %u (%s) changed while flushing",
- bufHdr->tag.blockNum, bufHdr->sb_relname);
- }
- else
- {
- bufHdr->flags &= ~BM_DIRTY;
- }
- if ( release )
- UnpinBuffer(bufHdr);
- SpinRelease(BufMgrLock);
- CommitInfoNeedsSave[buffer - 1] = 0;
-
- return(STATUS_OK);
+ BufferDesc *bufHdr;
+ Oid bufdb;
+ Relation bufrel;
+ int status;
+
+ if (BufferIsLocal(buffer))
+ return FlushLocalBuffer(buffer, release);
+
+ if (BAD_BUFFER_ID(buffer))
+ return (STATUS_ERROR);
+
+ bufHdr = &BufferDescriptors[buffer - 1];
+ bufdb = bufHdr->tag.relId.dbId;
+
+ Assert(bufdb == MyDatabaseId || bufdb == (Oid) NULL);
+ bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
+ Assert(bufrel != (Relation) NULL);
+
+ /* To check if block content changed while flushing. - vadim 01/17/97 */
+ SpinAcquire(BufMgrLock);
+ bufHdr->flags &= ~BM_JUST_DIRTIED;
+ SpinRelease(BufMgrLock);
+
+ status = smgrflush(bufHdr->bufsmgr, bufrel, bufHdr->tag.blockNum,
+ (char *) MAKE_PTR(bufHdr->data));
+
+ if (status == SM_FAIL)
+ {
+ elog(WARN, "FlushBuffer: cannot flush block %u of the relation %s",
+ bufHdr->tag.blockNum, bufHdr->sb_relname);
+ return (STATUS_ERROR);
+ }
+ BufferFlushCount++;
+
+ SpinAcquire(BufMgrLock);
+
+ /*
+ * If this buffer was marked by someone as DIRTY while we were
+ * flushing it out we must not clear DIRTY flag - vadim 01/17/97
+ */
+ if (bufHdr->flags & BM_JUST_DIRTIED)
+ {
+ elog(NOTICE, "FlusfBuffer: content of block %u (%s) changed while flushing",
+ bufHdr->tag.blockNum, bufHdr->sb_relname);
+ }
+ else
+ {
+ bufHdr->flags &= ~BM_DIRTY;
+ }
+ if (release)
+ UnpinBuffer(bufHdr);
+ SpinRelease(BufMgrLock);
+ CommitInfoNeedsSave[buffer - 1] = 0;
+
+ return (STATUS_OK);
}
/*
* WriteNoReleaseBuffer -- like WriteBuffer, but do not unpin the buffer
- * when the operation is complete.
+ * when the operation is complete.
*
- * We know that the buffer is for a relation in our private cache,
- * because this routine is called only to write out buffers that
- * were changed by the executing backend.
+ * We know that the buffer is for a relation in our private cache,
+ * because this routine is called only to write out buffers that
+ * were changed by the executing backend.
*/
int
WriteNoReleaseBuffer(Buffer buffer)
{
- BufferDesc *bufHdr;
-
- if (WriteMode == BUFFER_FLUSH_WRITE) {
- return (FlushBuffer (buffer, FALSE));
- } else {
+ BufferDesc *bufHdr;
- if (BufferIsLocal(buffer))
- return WriteLocalBuffer(buffer, FALSE);
-
- if (BAD_BUFFER_ID(buffer))
- return (STATUS_ERROR);
+ if (WriteMode == BUFFER_FLUSH_WRITE)
+ {
+ return (FlushBuffer(buffer, FALSE));
+ }
+ else
+ {
- bufHdr = &BufferDescriptors[buffer-1];
-
- SpinAcquire(BufMgrLock);
- bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
- SpinRelease(BufMgrLock);
- CommitInfoNeedsSave[buffer - 1] = 0;
- }
- return(STATUS_OK);
+ if (BufferIsLocal(buffer))
+ return WriteLocalBuffer(buffer, FALSE);
+
+ if (BAD_BUFFER_ID(buffer))
+ return (STATUS_ERROR);
+
+ bufHdr = &BufferDescriptors[buffer - 1];
+
+ SpinAcquire(BufMgrLock);
+ bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
+ SpinRelease(BufMgrLock);
+ CommitInfoNeedsSave[buffer - 1] = 0;
+ }
+ return (STATUS_OK);
}
#undef ReleaseAndReadBuffer
/*
* ReleaseAndReadBuffer -- combine ReleaseBuffer() and ReadBuffer()
- * so that only one semop needs to be called.
+ * so that only one semop needs to be called.
*
*/
Buffer
ReleaseAndReadBuffer(Buffer buffer,
- Relation relation,
- BlockNumber blockNum)
+ Relation relation,
+ BlockNumber blockNum)
{
- BufferDesc *bufHdr;
- Buffer retbuf;
-
- if (BufferIsLocal(buffer)) {
- Assert(LocalRefCount[-buffer - 1] > 0);
- LocalRefCount[-buffer - 1]--;
- } else {
- if (BufferIsValid(buffer)) {
- bufHdr = &BufferDescriptors[buffer-1];
- Assert(PrivateRefCount[buffer - 1] > 0);
- PrivateRefCount[buffer - 1]--;
- if (PrivateRefCount[buffer - 1] == 0 &&
- LastRefCount[buffer - 1] == 0) {
- /* only release buffer if it is not pinned in previous ExecMain
- level */
- SpinAcquire(BufMgrLock);
- bufHdr->refcount--;
- if (bufHdr->refcount == 0) {
- AddBufferToFreelist(bufHdr);
- bufHdr->flags |= BM_FREE;
- }
- if(CommitInfoNeedsSave[buffer - 1]) {
- bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
- CommitInfoNeedsSave[buffer - 1] = 0;
+ BufferDesc *bufHdr;
+ Buffer retbuf;
+
+ if (BufferIsLocal(buffer))
+ {
+ Assert(LocalRefCount[-buffer - 1] > 0);
+ LocalRefCount[-buffer - 1]--;
+ }
+ else
+ {
+ if (BufferIsValid(buffer))
+ {
+ bufHdr = &BufferDescriptors[buffer - 1];
+ Assert(PrivateRefCount[buffer - 1] > 0);
+ PrivateRefCount[buffer - 1]--;
+ if (PrivateRefCount[buffer - 1] == 0 &&
+ LastRefCount[buffer - 1] == 0)
+ {
+
+ /*
+ * only release buffer if it is not pinned in previous
+ * ExecMain level
+ */
+ SpinAcquire(BufMgrLock);
+ bufHdr->refcount--;
+ if (bufHdr->refcount == 0)
+ {
+ AddBufferToFreelist(bufHdr);
+ bufHdr->flags |= BM_FREE;
+ }
+ if (CommitInfoNeedsSave[buffer - 1])
+ {
+ bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
+ CommitInfoNeedsSave[buffer - 1] = 0;
+ }
+ retbuf = ReadBufferWithBufferLock(relation, blockNum, true);
+ return retbuf;
+ }
}
- retbuf = ReadBufferWithBufferLock(relation, blockNum, true);
- return retbuf;
- }
}
- }
- return (ReadBuffer(relation, blockNum));
+ return (ReadBuffer(relation, blockNum));
}
/*
* BufferSync -- Flush all dirty buffers in the pool.
*
- * This is called at transaction commit time. It does the wrong thing,
- * right now. We should flush only our own changes to stable storage,
- * and we should obey the lock protocol on the buffer manager metadata
- * as we do it. Also, we need to be sure that no other transaction is
- * modifying the page as we flush it. This is only a problem for objects
- * that use a non-two-phase locking protocol, like btree indices. For
- * those objects, we would like to set a write lock for the duration of
- * our IO. Another possibility is to code updates to btree pages
- * carefully, so that writing them out out of order cannot cause
- * any unrecoverable errors.
+ * This is called at transaction commit time. It does the wrong thing,
+ * right now. We should flush only our own changes to stable storage,
+ * and we should obey the lock protocol on the buffer manager metadata
+ * as we do it. Also, we need to be sure that no other transaction is
+ * modifying the page as we flush it. This is only a problem for objects
+ * that use a non-two-phase locking protocol, like btree indices. For
+ * those objects, we would like to set a write lock for the duration of
+ * our IO. Another possibility is to code updates to btree pages
+ * carefully, so that writing them out out of order cannot cause
+ * any unrecoverable errors.
*
- * I don't want to think hard about this right now, so I will try
- * to come back to it later.
+ * I don't want to think hard about this right now, so I will try
+ * to come back to it later.
*/
static void
BufferSync()
-{
- int i;
- Oid bufdb;
- Oid bufrel;
- Relation reln;
- BufferDesc *bufHdr;
- int status;
-
- SpinAcquire(BufMgrLock);
- for (i=0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++) {
- if ((bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY)) {
- bufdb = bufHdr->tag.relId.dbId;
- bufrel = bufHdr->tag.relId.relId;
- if (bufdb == MyDatabaseId || bufdb == (Oid) 0) {
- reln = RelationIdCacheGetRelation(bufrel);
-
- /*
- * We have to pin buffer to keep anyone from stealing it
- * from the buffer pool while we are flushing it or
- * waiting in WaitIO. It's bad for GetFreeBuffer in
- * BufferAlloc, but there is no other way to prevent
- * writing into disk block data from some other buffer,
- * getting smgr status of some other block and
- * clearing BM_DIRTY of ... - VAdim 09/16/96
- */
- PinBuffer(bufHdr);
- if (bufHdr->flags & BM_IO_IN_PROGRESS)
+{
+ int i;
+ Oid bufdb;
+ Oid bufrel;
+ Relation reln;
+ BufferDesc *bufHdr;
+ int status;
+
+ SpinAcquire(BufMgrLock);
+ for (i = 0, bufHdr = BufferDescriptors; i < NBuffers; i++, bufHdr++)
+ {
+ if ((bufHdr->flags & BM_VALID) && (bufHdr->flags & BM_DIRTY))
{
- WaitIO(bufHdr, BufMgrLock);
- UnpinBuffer(bufHdr);
- if (bufHdr->flags & BM_IO_ERROR)
- {
- elog(WARN, "BufferSync: write error %u for %s",
- bufHdr->tag.blockNum, bufHdr->sb_relname);
- }
- if (reln != (Relation)NULL)
- RelationDecrementReferenceCount(reln);
- continue;
- }
-
- /*
- * To check if block content changed while flushing
- * (see below). - vadim 01/17/97
- */
- bufHdr->flags &= ~BM_JUST_DIRTIED;
+ bufdb = bufHdr->tag.relId.dbId;
+ bufrel = bufHdr->tag.relId.relId;
+ if (bufdb == MyDatabaseId || bufdb == (Oid) 0)
+ {
+ reln = RelationIdCacheGetRelation(bufrel);
+
+ /*
+ * We have to pin buffer to keep anyone from stealing it
+ * from the buffer pool while we are flushing it or
+ * waiting in WaitIO. It's bad for GetFreeBuffer in
+ * BufferAlloc, but there is no other way to prevent
+ * writing into disk block data from some other buffer,
+ * getting smgr status of some other block and clearing
+ * BM_DIRTY of ... - VAdim 09/16/96
+ */
+ PinBuffer(bufHdr);
+ if (bufHdr->flags & BM_IO_IN_PROGRESS)
+ {
+ WaitIO(bufHdr, BufMgrLock);
+ UnpinBuffer(bufHdr);
+ if (bufHdr->flags & BM_IO_ERROR)
+ {
+ elog(WARN, "BufferSync: write error %u for %s",
+ bufHdr->tag.blockNum, bufHdr->sb_relname);
+ }
+ if (reln != (Relation) NULL)
+ RelationDecrementReferenceCount(reln);
+ continue;
+ }
+
+ /*
+ * To check if block content changed while flushing (see
+ * below). - vadim 01/17/97
+ */
+ bufHdr->flags &= ~BM_JUST_DIRTIED;
+
+ /*
+ * If we didn't have the reldesc in our local cache, flush
+ * this page out using the 'blind write' storage manager
+ * routine. If we did find it, use the standard
+ * interface.
+ */
- /*
- * If we didn't have the reldesc in our local cache, flush this
- * page out using the 'blind write' storage manager routine. If
- * we did find it, use the standard interface.
- */
-
#ifndef OPTIMIZE_SINGLE
- SpinRelease(BufMgrLock);
-#endif /* OPTIMIZE_SINGLE */
- if (reln == (Relation) NULL) {
- status = smgrblindwrt(bufHdr->bufsmgr, bufHdr->sb_dbname,
- bufHdr->sb_relname, bufdb, bufrel,
- bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data));
- } else {
- status = smgrwrite(bufHdr->bufsmgr, reln,
- bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data));
- }
+ SpinRelease(BufMgrLock);
+#endif /* OPTIMIZE_SINGLE */
+ if (reln == (Relation) NULL)
+ {
+ status = smgrblindwrt(bufHdr->bufsmgr, bufHdr->sb_dbname,
+ bufHdr->sb_relname, bufdb, bufrel,
+ bufHdr->tag.blockNum,
+ (char *) MAKE_PTR(bufHdr->data));
+ }
+ else
+ {
+ status = smgrwrite(bufHdr->bufsmgr, reln,
+ bufHdr->tag.blockNum,
+ (char *) MAKE_PTR(bufHdr->data));
+ }
#ifndef OPTIMIZE_SINGLE
- SpinAcquire(BufMgrLock);
-#endif /* OPTIMIZE_SINGLE */
-
- UnpinBuffer(bufHdr);
- if (status == SM_FAIL) {
- bufHdr->flags |= BM_IO_ERROR;
- elog(WARN, "BufferSync: cannot write %u for %s",
- bufHdr->tag.blockNum, bufHdr->sb_relname);
- }
- BufferFlushCount++;
- /*
- * If this buffer was marked by someone as DIRTY while
- * we were flushing it out we must not clear DIRTY flag
- * - vadim 01/17/97
- */
- if ( bufHdr->flags & BM_JUST_DIRTIED )
- {
- elog (NOTICE, "BufferSync: content of block %u (%s) changed while flushing",
- bufHdr->tag.blockNum, bufHdr->sb_relname);
- }
- else
- {
- bufHdr->flags &= ~BM_DIRTY;
+ SpinAcquire(BufMgrLock);
+#endif /* OPTIMIZE_SINGLE */
+
+ UnpinBuffer(bufHdr);
+ if (status == SM_FAIL)
+ {
+ bufHdr->flags |= BM_IO_ERROR;
+ elog(WARN, "BufferSync: cannot write %u for %s",
+ bufHdr->tag.blockNum, bufHdr->sb_relname);
+ }
+ BufferFlushCount++;
+
+ /*
+ * If this buffer was marked by someone as DIRTY while we
+ * were flushing it out we must not clear DIRTY flag -
+ * vadim 01/17/97
+ */
+ if (bufHdr->flags & BM_JUST_DIRTIED)
+ {
+ elog(NOTICE, "BufferSync: content of block %u (%s) changed while flushing",
+ bufHdr->tag.blockNum, bufHdr->sb_relname);
+ }
+ else
+ {
+ bufHdr->flags &= ~BM_DIRTY;
+ }
+ if (reln != (Relation) NULL)
+ RelationDecrementReferenceCount(reln);
+ }
}
- if (reln != (Relation)NULL)
- RelationDecrementReferenceCount(reln);
- }
}
- }
- SpinRelease(BufMgrLock);
+ SpinRelease(BufMgrLock);
- LocalBufferSync();
+ LocalBufferSync();
}
/*
* WaitIO -- Block until the IO_IN_PROGRESS flag on 'buf'
- * is cleared. Because IO_IN_PROGRESS conflicts are
- * expected to be rare, there is only one BufferIO
- * lock in the entire system. All processes block
- * on this semaphore when they try to use a buffer
- * that someone else is faulting in. Whenever a
- * process finishes an IO and someone is waiting for
- * the buffer, BufferIO is signaled (SignalIO). All
- * waiting processes then wake up and check to see
- * if their buffer is now ready. This implementation
- * is simple, but efficient enough if WaitIO is
- * rarely called by multiple processes simultaneously.
+ * is cleared. Because IO_IN_PROGRESS conflicts are
+ * expected to be rare, there is only one BufferIO
+ * lock in the entire system. All processes block
+ * on this semaphore when they try to use a buffer
+ * that someone else is faulting in. Whenever a
+ * process finishes an IO and someone is waiting for
+ * the buffer, BufferIO is signaled (SignalIO). All
+ * waiting processes then wake up and check to see
+ * if their buffer is now ready. This implementation
+ * is simple, but efficient enough if WaitIO is
+ * rarely called by multiple processes simultaneously.
*
- * ProcSleep atomically releases the spinlock and goes to
- * sleep.
+ * ProcSleep atomically releases the spinlock and goes to
+ * sleep.
*
- * Note: there is an easy fix if the queue becomes long.
- * save the id of the buffer we are waiting for in
- * the queue structure. That way signal can figure
- * out which proc to wake up.
+ * Note: there is an easy fix if the queue becomes long.
+ * save the id of the buffer we are waiting for in
+ * the queue structure. That way signal can figure
+ * out which proc to wake up.
*/
#ifdef HAS_TEST_AND_SET
static void
-WaitIO(BufferDesc *buf, SPINLOCK spinlock)
+WaitIO(BufferDesc * buf, SPINLOCK spinlock)
{
- SpinRelease(spinlock);
- S_LOCK(&(buf->io_in_progress_lock));
- S_UNLOCK(&(buf->io_in_progress_lock));
- SpinAcquire(spinlock);
+ SpinRelease(spinlock);
+ S_LOCK(&(buf->io_in_progress_lock));
+ S_UNLOCK(&(buf->io_in_progress_lock));
+ SpinAcquire(spinlock);
}
-#else /* HAS_TEST_AND_SET */
-IpcSemaphoreId WaitIOSemId;
+#else /* HAS_TEST_AND_SET */
+IpcSemaphoreId WaitIOSemId;
static void
-WaitIO(BufferDesc *buf, SPINLOCK spinlock)
+WaitIO(BufferDesc * buf, SPINLOCK spinlock)
{
- bool inProgress;
-
- for (;;) {
-
- /* wait until someone releases IO lock */
- (*NWaitIOBackendP)++;
- SpinRelease(spinlock);
- IpcSemaphoreLock(WaitIOSemId, 0, 1);
- SpinAcquire(spinlock);
- inProgress = (buf->flags & BM_IO_IN_PROGRESS);
- if (!inProgress) break;
- }
+ bool inProgress;
+
+ for (;;)
+ {
+
+ /* wait until someone releases IO lock */
+ (*NWaitIOBackendP)++;
+ SpinRelease(spinlock);
+ IpcSemaphoreLock(WaitIOSemId, 0, 1);
+ SpinAcquire(spinlock);
+ inProgress = (buf->flags & BM_IO_IN_PROGRESS);
+ if (!inProgress)
+ break;
+ }
}
/*
* SignalIO --
*/
static void
-SignalIO(BufferDesc *buf)
+SignalIO(BufferDesc * buf)
{
- /* somebody better be waiting. */
- Assert( buf->refcount > 1);
- IpcSemaphoreUnlock(WaitIOSemId, 0, *NWaitIOBackendP);
- *NWaitIOBackendP = 0;
+ /* somebody better be waiting. */
+ Assert(buf->refcount > 1);
+ IpcSemaphoreUnlock(WaitIOSemId, 0, *NWaitIOBackendP);
+ *NWaitIOBackendP = 0;
}
-#endif /* HAS_TEST_AND_SET */
-long NDirectFileRead; /* some I/O's are direct file access. bypass bufmgr */
-long NDirectFileWrite; /* e.g., I/O in psort and hashjoin. */
+#endif /* HAS_TEST_AND_SET */
+
+long NDirectFileRead;/* some I/O's are direct file access.
+ * bypass bufmgr */
+long NDirectFileWrite; /* e.g., I/O in psort and
+ * hashjoin. */
void
-PrintBufferUsage(FILE *statfp)
+PrintBufferUsage(FILE * statfp)
{
- float hitrate;
- float localhitrate;
-
- if (ReadBufferCount==0)
- hitrate = 0.0;
- else
- hitrate = (float)BufferHitCount * 100.0/ReadBufferCount;
-
- if (ReadLocalBufferCount==0)
- localhitrate = 0.0;
- else
- localhitrate = (float)LocalBufferHitCount * 100.0/ReadLocalBufferCount;
-
- fprintf(statfp, "!\tShared blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
- ReadBufferCount - BufferHitCount, BufferFlushCount, hitrate);
- fprintf(statfp, "!\tLocal blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
- ReadLocalBufferCount - LocalBufferHitCount, LocalBufferFlushCount, localhitrate);
- fprintf(statfp, "!\tDirect blocks: %10ld read, %10ld written\n",
- NDirectFileRead, NDirectFileWrite);
+ float hitrate;
+ float localhitrate;
+
+ if (ReadBufferCount == 0)
+ hitrate = 0.0;
+ else
+ hitrate = (float) BufferHitCount *100.0 / ReadBufferCount;
+
+ if (ReadLocalBufferCount == 0)
+ localhitrate = 0.0;
+ else
+ localhitrate = (float) LocalBufferHitCount *100.0 / ReadLocalBufferCount;
+
+ fprintf(statfp, "!\tShared blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
+ ReadBufferCount - BufferHitCount, BufferFlushCount, hitrate);
+ fprintf(statfp, "!\tLocal blocks: %10ld read, %10ld written, buffer hit rate = %.2f%%\n",
+ ReadLocalBufferCount - LocalBufferHitCount, LocalBufferFlushCount, localhitrate);
+ fprintf(statfp, "!\tDirect blocks: %10ld read, %10ld written\n",
+ NDirectFileRead, NDirectFileWrite);
}
void
ResetBufferUsage()
{
- BufferHitCount = 0;
- ReadBufferCount = 0;
- BufferFlushCount = 0;
- LocalBufferHitCount = 0;
- ReadLocalBufferCount = 0;
- LocalBufferFlushCount = 0;
- NDirectFileRead = 0;
- NDirectFileWrite = 0;
+ BufferHitCount = 0;
+ ReadBufferCount = 0;
+ BufferFlushCount = 0;
+ LocalBufferHitCount = 0;
+ ReadLocalBufferCount = 0;
+ LocalBufferFlushCount = 0;
+ NDirectFileRead = 0;
+ NDirectFileWrite = 0;
}
/* ----------------------------------------------
- * ResetBufferPool
+ * ResetBufferPool
*
- * this routine is supposed to be called when a transaction aborts.
- * it will release all the buffer pins held by the transaciton.
+ * this routine is supposed to be called when a transaction aborts.
+ * it will release all the buffer pins held by the transaciton.
*
* ----------------------------------------------
*/
void
ResetBufferPool()
{
- register int i;
- for (i=1; i<=NBuffers; i++) {
- CommitInfoNeedsSave[i - 1] = 0;
- if (BufferIsValid(i)) {
- while(PrivateRefCount[i - 1] > 0) {
- ReleaseBuffer(i);
- }
+ register int i;
+
+ for (i = 1; i <= NBuffers; i++)
+ {
+ CommitInfoNeedsSave[i - 1] = 0;
+ if (BufferIsValid(i))
+ {
+ while (PrivateRefCount[i - 1] > 0)
+ {
+ ReleaseBuffer(i);
+ }
+ }
+ LastRefCount[i - 1] = 0;
}
- LastRefCount[i - 1] = 0;
- }
- ResetLocalBufferPool();
+ ResetLocalBufferPool();
}
/* -----------------------------------------------
- * BufferPoolCheckLeak
+ * BufferPoolCheckLeak
*
- * check if there is buffer leak
+ * check if there is buffer leak
*
* -----------------------------------------------
*/
int
BufferPoolCheckLeak()
{
- register int i;
- int error = 0;
-
- for (i = 1; i <= NBuffers; i++) {
- if (BufferIsValid(i)) {
- elog(NOTICE,
- "buffer leak [%d] detected in BufferPoolCheckLeak()", i-1);
- error = 1;
+ register int i;
+ int error = 0;
+
+ for (i = 1; i <= NBuffers; i++)
+ {
+ if (BufferIsValid(i))
+ {
+ elog(NOTICE,
+ "buffer leak [%d] detected in BufferPoolCheckLeak()", i - 1);
+ error = 1;
+ }
}
- }
- if(error) {
- PrintBufferDescs();
- return(1);
- }
- return(0);
+ if (error)
+ {
+ PrintBufferDescs();
+ return (1);
+ }
+ return (0);
}
/* ------------------------------------------------
- * FlushBufferPool
+ * FlushBufferPool
*
- * flush all dirty blocks in buffer pool to disk
+ * flush all dirty blocks in buffer pool to disk
*
* ------------------------------------------------
*/
void
FlushBufferPool(int StableMainMemoryFlag)
{
- if (!StableMainMemoryFlag) {
- BufferSync();
- smgrcommit();
- }
+ if (!StableMainMemoryFlag)
+ {
+ BufferSync();
+ smgrcommit();
+ }
}
/*
* BufferIsValid --
- * True iff the refcnt of the local buffer is > 0
+ * True iff the refcnt of the local buffer is > 0
* Note:
- * BufferIsValid(InvalidBuffer) is False.
- * BufferIsValid(UnknownBuffer) is False.
+ * BufferIsValid(InvalidBuffer) is False.
+ * BufferIsValid(UnknownBuffer) is False.
*/
bool
BufferIsValid(Buffer bufnum)
{
- if (BufferIsLocal(bufnum))
- return (bufnum >= -NLocBuffer && LocalRefCount[-bufnum - 1] > 0);
-
- if (BAD_BUFFER_ID(bufnum))
- return(false);
+ if (BufferIsLocal(bufnum))
+ return (bufnum >= -NLocBuffer && LocalRefCount[-bufnum - 1] > 0);
- return ((bool)(PrivateRefCount[bufnum - 1] > 0));
+ if (BAD_BUFFER_ID(bufnum))
+ return (false);
+
+ return ((bool) (PrivateRefCount[bufnum - 1] > 0));
}
/*
* BufferGetBlockNumber --
- * Returns the block number associated with a buffer.
+ * Returns the block number associated with a buffer.
*
* Note:
- * Assumes that the buffer is valid.
+ * Assumes that the buffer is valid.
*/
BlockNumber
BufferGetBlockNumber(Buffer buffer)
{
- Assert(BufferIsValid(buffer));
+ Assert(BufferIsValid(buffer));
- /* XXX should be a critical section */
- if (BufferIsLocal(buffer))
- return (LocalBufferDescriptors[-buffer-1].tag.blockNum);
- else
- return (BufferDescriptors[buffer-1].tag.blockNum);
+ /* XXX should be a critical section */
+ if (BufferIsLocal(buffer))
+ return (LocalBufferDescriptors[-buffer - 1].tag.blockNum);
+ else
+ return (BufferDescriptors[buffer - 1].tag.blockNum);
}
/*
* BufferGetRelation --
- * Returns the relation desciptor associated with a buffer.
+ * Returns the relation desciptor associated with a buffer.
*
* Note:
- * Assumes buffer is valid.
+ * Assumes buffer is valid.
*/
Relation
BufferGetRelation(Buffer buffer)
{
- Relation relation;
- Oid relid;
-
- Assert(BufferIsValid(buffer));
- Assert(!BufferIsLocal(buffer)); /* not supported for local buffers */
-
- /* XXX should be a critical section */
- relid = LRelIdGetRelationId(BufferDescriptors[buffer-1].tag.relId);
- relation = RelationIdGetRelation(relid);
-
- RelationDecrementReferenceCount(relation);
-
- if (RelationHasReferenceCountZero(relation)) {
- /*
- elog(NOTICE, "BufferGetRelation: 0->1");
- */
-
- RelationIncrementReferenceCount(relation);
- }
-
- return (relation);
+ Relation relation;
+ Oid relid;
+
+ Assert(BufferIsValid(buffer));
+ Assert(!BufferIsLocal(buffer)); /* not supported for local buffers */
+
+ /* XXX should be a critical section */
+ relid = LRelIdGetRelationId(BufferDescriptors[buffer - 1].tag.relId);
+ relation = RelationIdGetRelation(relid);
+
+ RelationDecrementReferenceCount(relation);
+
+ if (RelationHasReferenceCountZero(relation))
+ {
+
+ /*
+ * elog(NOTICE, "BufferGetRelation: 0->1");
+ */
+
+ RelationIncrementReferenceCount(relation);
+ }
+
+ return (relation);
}
/*
@@ -1249,217 +1347,232 @@ BufferGetRelation(Buffer buffer)
*
*/
static int
-BufferReplace(BufferDesc *bufHdr, bool bufferLockHeld)
+BufferReplace(BufferDesc * bufHdr, bool bufferLockHeld)
{
- Relation reln;
- Oid bufdb, bufrel;
- int status;
-
- if (!bufferLockHeld)
- SpinAcquire(BufMgrLock);
-
- /*
- * first try to find the reldesc in the cache, if no luck,
- * don't bother to build the reldesc from scratch, just do
- * a blind write.
- */
-
- bufdb = bufHdr->tag.relId.dbId;
- bufrel = bufHdr->tag.relId.relId;
-
- if (bufdb == MyDatabaseId || bufdb == (Oid) NULL)
- reln = RelationIdCacheGetRelation(bufrel);
- else
- reln = (Relation) NULL;
-
- /* To check if block content changed while flushing. - vadim 01/17/97 */
- bufHdr->flags &= ~BM_JUST_DIRTIED;
-
- SpinRelease(BufMgrLock);
-
- if (reln != (Relation) NULL) {
- status = smgrflush(bufHdr->bufsmgr, reln, bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data));
- } else {
-
- /* blind write always flushes */
- status = smgrblindwrt(bufHdr->bufsmgr, bufHdr->sb_dbname,
- bufHdr->sb_relname, bufdb, bufrel,
- bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data));
- }
-
- if (status == SM_FAIL)
- return (FALSE);
-
- BufferFlushCount++;
-
- return (TRUE);
+ Relation reln;
+ Oid bufdb,
+ bufrel;
+ int status;
+
+ if (!bufferLockHeld)
+ SpinAcquire(BufMgrLock);
+
+ /*
+ * first try to find the reldesc in the cache, if no luck, don't
+ * bother to build the reldesc from scratch, just do a blind write.
+ */
+
+ bufdb = bufHdr->tag.relId.dbId;
+ bufrel = bufHdr->tag.relId.relId;
+
+ if (bufdb == MyDatabaseId || bufdb == (Oid) NULL)
+ reln = RelationIdCacheGetRelation(bufrel);
+ else
+ reln = (Relation) NULL;
+
+ /* To check if block content changed while flushing. - vadim 01/17/97 */
+ bufHdr->flags &= ~BM_JUST_DIRTIED;
+
+ SpinRelease(BufMgrLock);
+
+ if (reln != (Relation) NULL)
+ {
+ status = smgrflush(bufHdr->bufsmgr, reln, bufHdr->tag.blockNum,
+ (char *) MAKE_PTR(bufHdr->data));
+ }
+ else
+ {
+
+ /* blind write always flushes */
+ status = smgrblindwrt(bufHdr->bufsmgr, bufHdr->sb_dbname,
+ bufHdr->sb_relname, bufdb, bufrel,
+ bufHdr->tag.blockNum,
+ (char *) MAKE_PTR(bufHdr->data));
+ }
+
+ if (status == SM_FAIL)
+ return (FALSE);
+
+ BufferFlushCount++;
+
+ return (TRUE);
}
/*
* RelationGetNumberOfBlocks --
- * Returns the buffer descriptor associated with a page in a relation.
+ * Returns the buffer descriptor associated with a page in a relation.
*
* Note:
- * XXX may fail for huge relations.
- * XXX should be elsewhere.
- * XXX maybe should be hidden
+ * XXX may fail for huge relations.
+ * XXX should be elsewhere.
+ * XXX maybe should be hidden
*/
BlockNumber
RelationGetNumberOfBlocks(Relation relation)
{
- return
- ((relation->rd_islocal) ? relation->rd_nblocks :
- smgrnblocks(relation->rd_rel->relsmgr, relation));
+ return
+ ((relation->rd_islocal) ? relation->rd_nblocks :
+ smgrnblocks(relation->rd_rel->relsmgr, relation));
}
/*
* BufferGetBlock --
- * Returns a reference to a disk page image associated with a buffer.
+ * Returns a reference to a disk page image associated with a buffer.
*
* Note:
- * Assumes buffer is valid.
+ * Assumes buffer is valid.
*/
Block
BufferGetBlock(Buffer buffer)
{
- Assert(BufferIsValid(buffer));
+ Assert(BufferIsValid(buffer));
- if (BufferIsLocal(buffer))
- return((Block)MAKE_PTR(LocalBufferDescriptors[-buffer-1].data));
- else
- return((Block)MAKE_PTR(BufferDescriptors[buffer-1].data));
+ if (BufferIsLocal(buffer))
+ return ((Block) MAKE_PTR(LocalBufferDescriptors[-buffer - 1].data));
+ else
+ return ((Block) MAKE_PTR(BufferDescriptors[buffer - 1].data));
}
/* ---------------------------------------------------------------------
- * ReleaseRelationBuffers
+ * ReleaseRelationBuffers
*
- * this function unmarks all the dirty pages of a relation
- * in the buffer pool so that at the end of transaction
- * these pages will not be flushed.
- * XXX currently it sequentially searches the buffer pool, should be
- * changed to more clever ways of searching.
+ * this function unmarks all the dirty pages of a relation
+ * in the buffer pool so that at the end of transaction
+ * these pages will not be flushed.
+ * XXX currently it sequentially searches the buffer pool, should be
+ * changed to more clever ways of searching.
* --------------------------------------------------------------------
*/
void
-ReleaseRelationBuffers (Relation rdesc)
+ReleaseRelationBuffers(Relation rdesc)
{
- register int i;
- int holding = 0;
- BufferDesc *buf;
-
- if ( rdesc->rd_islocal )
- {
- for (i = 0; i < NLocBuffer; i++)
- {
- buf = &LocalBufferDescriptors[i];
- if ((buf->flags & BM_DIRTY) &&
- (buf->tag.relId.relId == rdesc->rd_id))
- {
- buf->flags &= ~BM_DIRTY;
- }
- }
- return;
- }
-
- for (i=1; i<=NBuffers; i++) {
- buf = &BufferDescriptors[i-1];
- if (!holding) {
- SpinAcquire(BufMgrLock);
- holding = 1;
+ register int i;
+ int holding = 0;
+ BufferDesc *buf;
+
+ if (rdesc->rd_islocal)
+ {
+ for (i = 0; i < NLocBuffer; i++)
+ {
+ buf = &LocalBufferDescriptors[i];
+ if ((buf->flags & BM_DIRTY) &&
+ (buf->tag.relId.relId == rdesc->rd_id))
+ {
+ buf->flags &= ~BM_DIRTY;
+ }
+ }
+ return;
}
- if ((buf->flags & BM_DIRTY) &&
- (buf->tag.relId.dbId == MyDatabaseId) &&
- (buf->tag.relId.relId == rdesc->rd_id)) {
- buf->flags &= ~BM_DIRTY;
- if (!(buf->flags & BM_FREE)) {
- SpinRelease(BufMgrLock);
- holding = 0;
- ReleaseBuffer(i);
- }
+
+ for (i = 1; i <= NBuffers; i++)
+ {
+ buf = &BufferDescriptors[i - 1];
+ if (!holding)
+ {
+ SpinAcquire(BufMgrLock);
+ holding = 1;
+ }
+ if ((buf->flags & BM_DIRTY) &&
+ (buf->tag.relId.dbId == MyDatabaseId) &&
+ (buf->tag.relId.relId == rdesc->rd_id))
+ {
+ buf->flags &= ~BM_DIRTY;
+ if (!(buf->flags & BM_FREE))
+ {
+ SpinRelease(BufMgrLock);
+ holding = 0;
+ ReleaseBuffer(i);
+ }
+ }
}
- }
- if (holding)
- SpinRelease(BufMgrLock);
+ if (holding)
+ SpinRelease(BufMgrLock);
}
/* ---------------------------------------------------------------------
- * DropBuffers
+ * DropBuffers
*
- * This function marks all the buffers in the buffer cache for a
- * particular database as clean. This is used when we destroy a
- * database, to avoid trying to flush data to disk when the directory
- * tree no longer exists.
+ * This function marks all the buffers in the buffer cache for a
+ * particular database as clean. This is used when we destroy a
+ * database, to avoid trying to flush data to disk when the directory
+ * tree no longer exists.
*
- * This is an exceedingly non-public interface.
+ * This is an exceedingly non-public interface.
* --------------------------------------------------------------------
*/
void
DropBuffers(Oid dbid)
{
- register int i;
- BufferDesc *buf;
-
- SpinAcquire(BufMgrLock);
- for (i=1; i<=NBuffers; i++) {
- buf = &BufferDescriptors[i-1];
- if ((buf->tag.relId.dbId == dbid) && (buf->flags & BM_DIRTY)) {
- buf->flags &= ~BM_DIRTY;
- }
- }
- SpinRelease(BufMgrLock);
+ register int i;
+ BufferDesc *buf;
+
+ SpinAcquire(BufMgrLock);
+ for (i = 1; i <= NBuffers; i++)
+ {
+ buf = &BufferDescriptors[i - 1];
+ if ((buf->tag.relId.dbId == dbid) && (buf->flags & BM_DIRTY))
+ {
+ buf->flags &= ~BM_DIRTY;
+ }
+ }
+ SpinRelease(BufMgrLock);
}
/* -----------------------------------------------------------------
- * PrintBufferDescs
+ * PrintBufferDescs
*
- * this function prints all the buffer descriptors, for debugging
- * use only.
+ * this function prints all the buffer descriptors, for debugging
+ * use only.
* -----------------------------------------------------------------
*/
void
PrintBufferDescs()
{
- int i;
- BufferDesc *buf = BufferDescriptors;
+ int i;
+ BufferDesc *buf = BufferDescriptors;
- if (IsUnderPostmaster) {
- SpinAcquire(BufMgrLock);
- for (i = 0; i < NBuffers; ++i, ++buf) {
- elog(NOTICE, "[%02d] (freeNext=%d, freePrev=%d, relname=%s, \
+ if (IsUnderPostmaster)
+ {
+ SpinAcquire(BufMgrLock);
+ for (i = 0; i < NBuffers; ++i, ++buf)
+ {
+ elog(NOTICE, "[%02d] (freeNext=%d, freePrev=%d, relname=%s, \
blockNum=%d, flags=0x%x, refcount=%d %d)",
- i, buf->freeNext, buf->freePrev,
- buf->sb_relname, buf->tag.blockNum, buf->flags,
- buf->refcount, PrivateRefCount[i]);
+ i, buf->freeNext, buf->freePrev,
+ buf->sb_relname, buf->tag.blockNum, buf->flags,
+ buf->refcount, PrivateRefCount[i]);
+ }
+ SpinRelease(BufMgrLock);
}
- SpinRelease(BufMgrLock);
- } else {
- /* interactive backend */
- for (i = 0; i < NBuffers; ++i, ++buf) {
- printf("[%-2d] (%s, %d) flags=0x%x, refcnt=%d %ld)\n",
- i, buf->sb_relname, buf->tag.blockNum,
- buf->flags, buf->refcount, PrivateRefCount[i]);
+ else
+ {
+ /* interactive backend */
+ for (i = 0; i < NBuffers; ++i, ++buf)
+ {
+ printf("[%-2d] (%s, %d) flags=0x%x, refcnt=%d %ld)\n",
+ i, buf->sb_relname, buf->tag.blockNum,
+ buf->flags, buf->refcount, PrivateRefCount[i]);
+ }
}
- }
}
void
PrintPinnedBufs()
{
- int i;
- BufferDesc *buf = BufferDescriptors;
-
- SpinAcquire(BufMgrLock);
- for (i = 0; i < NBuffers; ++i, ++buf) {
- if (PrivateRefCount[i] > 0)
- elog(NOTICE, "[%02d] (freeNext=%d, freePrev=%d, relname=%s, \
+ int i;
+ BufferDesc *buf = BufferDescriptors;
+
+ SpinAcquire(BufMgrLock);
+ for (i = 0; i < NBuffers; ++i, ++buf)
+ {
+ if (PrivateRefCount[i] > 0)
+ elog(NOTICE, "[%02d] (freeNext=%d, freePrev=%d, relname=%s, \
blockNum=%d, flags=0x%x, refcount=%d %d)\n",
- i, buf->freeNext, buf->freePrev, buf->sb_relname,
- buf->tag.blockNum, buf->flags,
- buf->refcount, PrivateRefCount[i]);
- }
- SpinRelease(BufMgrLock);
+ i, buf->freeNext, buf->freePrev, buf->sb_relname,
+ buf->tag.blockNum, buf->flags,
+ buf->refcount, PrivateRefCount[i]);
+ }
+ SpinRelease(BufMgrLock);
}
/*
@@ -1474,17 +1587,20 @@ blockNum=%d, flags=0x%x, refcount=%d %d)\n",
void
BufferPoolBlowaway()
{
- register int i;
-
- BufferSync();
- for (i=1; i<=NBuffers; i++) {
- if (BufferIsValid(i)) {
- while(BufferIsValid(i))
- ReleaseBuffer(i);
- }
- BufTableDelete(&BufferDescriptors[i-1]);
- }
+ register int i;
+
+ BufferSync();
+ for (i = 1; i <= NBuffers; i++)
+ {
+ if (BufferIsValid(i))
+ {
+ while (BufferIsValid(i))
+ ReleaseBuffer(i);
+ }
+ BufTableDelete(&BufferDescriptors[i - 1]);
+ }
}
+
#endif
#undef IncrBufferRefCount
@@ -1493,297 +1609,328 @@ BufferPoolBlowaway()
void
IncrBufferRefCount(Buffer buffer)
{
- if (BufferIsLocal(buffer)) {
- Assert(LocalRefCount[-buffer - 1] >= 0);
- LocalRefCount[-buffer - 1]++;
- } else {
- Assert(!BAD_BUFFER_ID(buffer));
- Assert(PrivateRefCount[buffer - 1] >= 0);
- PrivateRefCount[buffer - 1]++;
- }
+ if (BufferIsLocal(buffer))
+ {
+ Assert(LocalRefCount[-buffer - 1] >= 0);
+ LocalRefCount[-buffer - 1]++;
+ }
+ else
+ {
+ Assert(!BAD_BUFFER_ID(buffer));
+ Assert(PrivateRefCount[buffer - 1] >= 0);
+ PrivateRefCount[buffer - 1]++;
+ }
}
/*
* ReleaseBuffer -- remove the pin on a buffer without
- * marking it dirty.
+ * marking it dirty.
*
*/
int
ReleaseBuffer(Buffer buffer)
{
- BufferDesc *bufHdr;
-
- if (BufferIsLocal(buffer)) {
- Assert(LocalRefCount[-buffer - 1] > 0);
- LocalRefCount[-buffer - 1]--;
- return (STATUS_OK);
- }
-
- if (BAD_BUFFER_ID(buffer))
- return(STATUS_ERROR);
-
- bufHdr = &BufferDescriptors[buffer-1];
-
- Assert(PrivateRefCount[buffer - 1] > 0);
- PrivateRefCount[buffer - 1]--;
- if (PrivateRefCount[buffer - 1] == 0 && LastRefCount[buffer - 1] == 0) {
- /* only release buffer if it is not pinned in previous ExecMain
- levels */
- SpinAcquire(BufMgrLock);
- bufHdr->refcount--;
- if (bufHdr->refcount == 0) {
- AddBufferToFreelist(bufHdr);
- bufHdr->flags |= BM_FREE;
+ BufferDesc *bufHdr;
+
+ if (BufferIsLocal(buffer))
+ {
+ Assert(LocalRefCount[-buffer - 1] > 0);
+ LocalRefCount[-buffer - 1]--;
+ return (STATUS_OK);
}
- if(CommitInfoNeedsSave[buffer - 1]) {
- bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
- CommitInfoNeedsSave[buffer - 1] = 0;
+
+ if (BAD_BUFFER_ID(buffer))
+ return (STATUS_ERROR);
+
+ bufHdr = &BufferDescriptors[buffer - 1];
+
+ Assert(PrivateRefCount[buffer - 1] > 0);
+ PrivateRefCount[buffer - 1]--;
+ if (PrivateRefCount[buffer - 1] == 0 && LastRefCount[buffer - 1] == 0)
+ {
+
+ /*
+ * only release buffer if it is not pinned in previous ExecMain
+ * levels
+ */
+ SpinAcquire(BufMgrLock);
+ bufHdr->refcount--;
+ if (bufHdr->refcount == 0)
+ {
+ AddBufferToFreelist(bufHdr);
+ bufHdr->flags |= BM_FREE;
+ }
+ if (CommitInfoNeedsSave[buffer - 1])
+ {
+ bufHdr->flags |= (BM_DIRTY | BM_JUST_DIRTIED);
+ CommitInfoNeedsSave[buffer - 1] = 0;
+ }
+ SpinRelease(BufMgrLock);
}
- SpinRelease(BufMgrLock);
- }
-
- return(STATUS_OK);
+
+ return (STATUS_OK);
}
#ifdef NOT_USED
void
IncrBufferRefCount_Debug(char *file, int line, Buffer buffer)
{
- IncrBufferRefCount(buffer);
- if (ShowPinTrace && !BufferIsLocal(buffer) && is_userbuffer(buffer)) {
- BufferDesc *buf = &BufferDescriptors[buffer-1];
-
- fprintf(stderr, "PIN(Incr) %ld relname = %s, blockNum = %d, \
+ IncrBufferRefCount(buffer);
+ if (ShowPinTrace && !BufferIsLocal(buffer) && is_userbuffer(buffer))
+ {
+ BufferDesc *buf = &BufferDescriptors[buffer - 1];
+
+ fprintf(stderr, "PIN(Incr) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
- buffer, buf->sb_relname, buf->tag.blockNum,
- PrivateRefCount[buffer - 1], file, line);
- }
+ buffer, buf->sb_relname, buf->tag.blockNum,
+ PrivateRefCount[buffer - 1], file, line);
+ }
}
+
#endif
#ifdef NOT_USED
void
ReleaseBuffer_Debug(char *file, int line, Buffer buffer)
{
- ReleaseBuffer(buffer);
- if (ShowPinTrace && !BufferIsLocal(buffer) && is_userbuffer(buffer)) {
- BufferDesc *buf = &BufferDescriptors[buffer-1];
-
- fprintf(stderr, "UNPIN(Rel) %ld relname = %s, blockNum = %d, \
+ ReleaseBuffer(buffer);
+ if (ShowPinTrace && !BufferIsLocal(buffer) && is_userbuffer(buffer))
+ {
+ BufferDesc *buf = &BufferDescriptors[buffer - 1];
+
+ fprintf(stderr, "UNPIN(Rel) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
- buffer, buf->sb_relname, buf->tag.blockNum,
- PrivateRefCount[buffer - 1], file, line);
- }
+ buffer, buf->sb_relname, buf->tag.blockNum,
+ PrivateRefCount[buffer - 1], file, line);
+ }
}
+
#endif
#ifdef NOT_USED
int
ReleaseAndReadBuffer_Debug(char *file,
- int line,
- Buffer buffer,
- Relation relation,
- BlockNumber blockNum)
+ int line,
+ Buffer buffer,
+ Relation relation,
+ BlockNumber blockNum)
{
- bool bufferValid;
- Buffer b;
-
- bufferValid = BufferIsValid(buffer);
- b = ReleaseAndReadBuffer(buffer, relation, blockNum);
- if (ShowPinTrace && bufferValid && BufferIsLocal(buffer)
- && is_userbuffer(buffer)) {
- BufferDesc *buf = &BufferDescriptors[buffer-1];
-
- fprintf(stderr, "UNPIN(Rel&Rd) %ld relname = %s, blockNum = %d, \
+ bool bufferValid;
+ Buffer b;
+
+ bufferValid = BufferIsValid(buffer);
+ b = ReleaseAndReadBuffer(buffer, relation, blockNum);
+ if (ShowPinTrace && bufferValid && BufferIsLocal(buffer)
+ && is_userbuffer(buffer))
+ {
+ BufferDesc *buf = &BufferDescriptors[buffer - 1];
+
+ fprintf(stderr, "UNPIN(Rel&Rd) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
- buffer, buf->sb_relname, buf->tag.blockNum,
- PrivateRefCount[buffer - 1], file, line);
- }
- if (ShowPinTrace && BufferIsLocal(buffer) && is_userbuffer(buffer)) {
- BufferDesc *buf = &BufferDescriptors[b-1];
-
- fprintf(stderr, "PIN(Rel&Rd) %ld relname = %s, blockNum = %d, \
+ buffer, buf->sb_relname, buf->tag.blockNum,
+ PrivateRefCount[buffer - 1], file, line);
+ }
+ if (ShowPinTrace && BufferIsLocal(buffer) && is_userbuffer(buffer))
+ {
+ BufferDesc *buf = &BufferDescriptors[b - 1];
+
+ fprintf(stderr, "PIN(Rel&Rd) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
- b, buf->sb_relname, buf->tag.blockNum,
- PrivateRefCount[b - 1], file, line);
- }
- return b;
+ b, buf->sb_relname, buf->tag.blockNum,
+ PrivateRefCount[b - 1], file, line);
+ }
+ return b;
}
+
#endif
#ifdef BMTRACE
/*
- * trace allocations and deallocations in a circular buffer in
- * shared memory. check the buffer before doing the allocation,
- * and die if there's anything fishy.
+ * trace allocations and deallocations in a circular buffer in
+ * shared memory. check the buffer before doing the allocation,
+ * and die if there's anything fishy.
*/
_bm_trace(Oid dbId, Oid relId, int blkNo, int bufNo, int allocType)
{
- static int mypid = 0;
- long start, cur;
- bmtrace *tb;
-
- if (mypid == 0)
- mypid = getpid();
-
- start = *CurTraceBuf;
-
- if (start > 0)
- cur = start - 1;
- else
- cur = BMT_LIMIT - 1;
-
- for (;;) {
- tb = &TraceBuf[cur];
- if (tb->bmt_op != BMT_NOTUSED) {
- if (tb->bmt_buf == bufNo) {
- if ((tb->bmt_op == BMT_DEALLOC)
- || (tb->bmt_dbid == dbId && tb->bmt_relid == relId
- && tb->bmt_blkno == blkNo))
- goto okay;
-
- /* die holding the buffer lock */
- _bm_die(dbId, relId, blkNo, bufNo, allocType, start, cur);
- }
- }
-
- if (cur == start)
- goto okay;
-
- if (cur == 0)
- cur = BMT_LIMIT - 1;
+ static int mypid = 0;
+ long start,
+ cur;
+ bmtrace *tb;
+
+ if (mypid == 0)
+ mypid = getpid();
+
+ start = *CurTraceBuf;
+
+ if (start > 0)
+ cur = start - 1;
else
- cur--;
- }
-
- okay:
- tb = &TraceBuf[start];
- tb->bmt_pid = mypid;
- tb->bmt_buf = bufNo;
- tb->bmt_dbid = dbId;
- tb->bmt_relid = relId;
- tb->bmt_blkno = blkNo;
- tb->bmt_op = allocType;
-
- *CurTraceBuf = (start + 1) % BMT_LIMIT;
+ cur = BMT_LIMIT - 1;
+
+ for (;;)
+ {
+ tb = &TraceBuf[cur];
+ if (tb->bmt_op != BMT_NOTUSED)
+ {
+ if (tb->bmt_buf == bufNo)
+ {
+ if ((tb->bmt_op == BMT_DEALLOC)
+ || (tb->bmt_dbid == dbId && tb->bmt_relid == relId
+ && tb->bmt_blkno == blkNo))
+ goto okay;
+
+ /* die holding the buffer lock */
+ _bm_die(dbId, relId, blkNo, bufNo, allocType, start, cur);
+ }
+ }
+
+ if (cur == start)
+ goto okay;
+
+ if (cur == 0)
+ cur = BMT_LIMIT - 1;
+ else
+ cur--;
+ }
+
+okay:
+ tb = &TraceBuf[start];
+ tb->bmt_pid = mypid;
+ tb->bmt_buf = bufNo;
+ tb->bmt_dbid = dbId;
+ tb->bmt_relid = relId;
+ tb->bmt_blkno = blkNo;
+ tb->bmt_op = allocType;
+
+ *CurTraceBuf = (start + 1) % BMT_LIMIT;
}
_bm_die(Oid dbId, Oid relId, int blkNo, int bufNo,
- int allocType, long start, long cur)
+ int allocType, long start, long cur)
{
- FILE *fp;
- bmtrace *tb;
- int i;
-
- tb = &TraceBuf[cur];
-
- if ((fp = AllocateFile("/tmp/death_notice", "w")) == NULL)
- elog(FATAL, "buffer alloc trace error and can't open log file");
-
- fprintf(fp, "buffer alloc trace detected the following error:\n\n");
- fprintf(fp, " buffer %d being %s inconsistently with a previous %s\n\n",
- bufNo, (allocType == BMT_DEALLOC ? "deallocated" : "allocated"),
- (tb->bmt_op == BMT_DEALLOC ? "deallocation" : "allocation"));
-
- fprintf(fp, "the trace buffer contains:\n");
-
- i = start;
- for (;;) {
- tb = &TraceBuf[i];
- if (tb->bmt_op != BMT_NOTUSED) {
- fprintf(fp, " [%3d]%spid %d buf %2d for <%d,%d,%d> ",
- i, (i == cur ? " ---> " : "\t"),
- tb->bmt_pid, tb->bmt_buf,
- tb->bmt_dbid, tb->bmt_relid, tb->bmt_blkno);
-
- switch (tb->bmt_op) {
- case BMT_ALLOCFND:
+ FILE *fp;
+ bmtrace *tb;
+ int i;
+
+ tb = &TraceBuf[cur];
+
+ if ((fp = AllocateFile("/tmp/death_notice", "w")) == NULL)
+ elog(FATAL, "buffer alloc trace error and can't open log file");
+
+ fprintf(fp, "buffer alloc trace detected the following error:\n\n");
+ fprintf(fp, " buffer %d being %s inconsistently with a previous %s\n\n",
+ bufNo, (allocType == BMT_DEALLOC ? "deallocated" : "allocated"),
+ (tb->bmt_op == BMT_DEALLOC ? "deallocation" : "allocation"));
+
+ fprintf(fp, "the trace buffer contains:\n");
+
+ i = start;
+ for (;;)
+ {
+ tb = &TraceBuf[i];
+ if (tb->bmt_op != BMT_NOTUSED)
+ {
+ fprintf(fp, " [%3d]%spid %d buf %2d for <%d,%d,%d> ",
+ i, (i == cur ? " ---> " : "\t"),
+ tb->bmt_pid, tb->bmt_buf,
+ tb->bmt_dbid, tb->bmt_relid, tb->bmt_blkno);
+
+ switch (tb->bmt_op)
+ {
+ case BMT_ALLOCFND:
+ fprintf(fp, "allocate (found)\n");
+ break;
+
+ case BMT_ALLOCNOTFND:
+ fprintf(fp, "allocate (not found)\n");
+ break;
+
+ case BMT_DEALLOC:
+ fprintf(fp, "deallocate\n");
+ break;
+
+ default:
+ fprintf(fp, "unknown op type %d\n", tb->bmt_op);
+ break;
+ }
+ }
+
+ i = (i + 1) % BMT_LIMIT;
+ if (i == start)
+ break;
+ }
+
+ fprintf(fp, "\noperation causing error:\n");
+ fprintf(fp, "\tpid %d buf %d for <%d,%d,%d> ",
+ getpid(), bufNo, dbId, relId, blkNo);
+
+ switch (allocType)
+ {
+ case BMT_ALLOCFND:
fprintf(fp, "allocate (found)\n");
break;
-
- case BMT_ALLOCNOTFND:
+
+ case BMT_ALLOCNOTFND:
fprintf(fp, "allocate (not found)\n");
break;
-
- case BMT_DEALLOC:
+
+ case BMT_DEALLOC:
fprintf(fp, "deallocate\n");
break;
-
- default:
- fprintf(fp, "unknown op type %d\n", tb->bmt_op);
+
+ default:
+ fprintf(fp, "unknown op type %d\n", allocType);
break;
- }
}
-
- i = (i + 1) % BMT_LIMIT;
- if (i == start)
- break;
- }
-
- fprintf(fp, "\noperation causing error:\n");
- fprintf(fp, "\tpid %d buf %d for <%d,%d,%d> ",
- getpid(), bufNo, dbId, relId, blkNo);
-
- switch (allocType) {
- case BMT_ALLOCFND:
- fprintf(fp, "allocate (found)\n");
- break;
-
- case BMT_ALLOCNOTFND:
- fprintf(fp, "allocate (not found)\n");
- break;
-
- case BMT_DEALLOC:
- fprintf(fp, "deallocate\n");
- break;
-
- default:
- fprintf(fp, "unknown op type %d\n", allocType);
- break;
- }
-
- FreeFile(fp);
-
- kill(getpid(), SIGILL);
+
+ FreeFile(fp);
+
+ kill(getpid(), SIGILL);
}
-#endif /* BMTRACE */
+#endif /* BMTRACE */
void
BufferRefCountReset(int *refcountsave)
{
- int i;
- for (i=0; i<NBuffers; i++) {
- refcountsave[i] = PrivateRefCount[i];
- LastRefCount[i] += PrivateRefCount[i];
- PrivateRefCount[i] = 0;
- }
+ int i;
+
+ for (i = 0; i < NBuffers; i++)
+ {
+ refcountsave[i] = PrivateRefCount[i];
+ LastRefCount[i] += PrivateRefCount[i];
+ PrivateRefCount[i] = 0;
+ }
}
void
BufferRefCountRestore(int *refcountsave)
{
- int i;
- for (i=0; i<NBuffers; i++) {
- PrivateRefCount[i] = refcountsave[i];
- LastRefCount[i] -= refcountsave[i];
- refcountsave[i] = 0;
- }
+ int i;
+
+ for (i = 0; i < NBuffers; i++)
+ {
+ PrivateRefCount[i] = refcountsave[i];
+ LastRefCount[i] -= refcountsave[i];
+ refcountsave[i] = 0;
+ }
}
-int SetBufferWriteMode (int mode)
+int
+SetBufferWriteMode(int mode)
{
- int old;
-
- old = WriteMode;
- WriteMode = mode;
- return (old);
+ int old;
+
+ old = WriteMode;
+ WriteMode = mode;
+ return (old);
}
-void SetBufferCommitInfoNeedsSave(Buffer buffer)
+void
+SetBufferCommitInfoNeedsSave(Buffer buffer)
{
- if ( !BufferIsLocal(buffer) )
- CommitInfoNeedsSave[buffer - 1]++;
+ if (!BufferIsLocal(buffer))
+ CommitInfoNeedsSave[buffer - 1]++;
}
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index f4e7bcdc57a..94a8e84b8c6 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* freelist.c--
- * routines for manipulating the buffer pool's replacement strategy
- * freelist.
+ * routines for manipulating the buffer pool's replacement strategy
+ * freelist.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/freelist.c,v 1.4 1997/08/19 21:32:44 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/freelist.c,v 1.5 1997/09/07 04:48:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,23 +16,23 @@
* OLD COMMENTS
*
* Data Structures:
- * SharedFreeList is a circular queue. Notice that this
- * is a shared memory queue so the next/prev "ptrs" are
- * buffer ids, not addresses.
+ * SharedFreeList is a circular queue. Notice that this
+ * is a shared memory queue so the next/prev "ptrs" are
+ * buffer ids, not addresses.
*
* Sync: all routines in this file assume that the buffer
- * semaphore has been acquired by the caller.
+ * semaphore has been acquired by the caller.
*/
#include <stdio.h>
#include "postgres.h"
#include "storage/bufmgr.h"
-#include "storage/buf_internals.h" /* where declarations go */
+#include "storage/buf_internals.h" /* where declarations go */
#include "storage/spin.h"
-static BufferDesc *SharedFreeList;
+static BufferDesc *SharedFreeList;
/* only actually used in debugging. The lock
* should be acquired before calling the freelist manager.
@@ -40,40 +40,40 @@ static BufferDesc *SharedFreeList;
extern SPINLOCK BufMgrLock;
#define IsInQueue(bf) \
- Assert((bf->freeNext != INVALID_DESCRIPTOR));\
- Assert((bf->freePrev != INVALID_DESCRIPTOR));\
- Assert((bf->flags & BM_FREE))
+ Assert((bf->freeNext != INVALID_DESCRIPTOR));\
+ Assert((bf->freePrev != INVALID_DESCRIPTOR));\
+ Assert((bf->flags & BM_FREE))
#define NotInQueue(bf) \
- Assert((bf->freeNext == INVALID_DESCRIPTOR));\
- Assert((bf->freePrev == INVALID_DESCRIPTOR));\
- Assert(! (bf->flags & BM_FREE))
+ Assert((bf->freeNext == INVALID_DESCRIPTOR));\
+ Assert((bf->freePrev == INVALID_DESCRIPTOR));\
+ Assert(! (bf->flags & BM_FREE))
/*
- * AddBufferToFreelist --
+ * AddBufferToFreelist --
*
* In theory, this is the only routine that needs to be changed
- * if the buffer replacement strategy changes. Just change
+ * if the buffer replacement strategy changes. Just change
* the manner in which buffers are added to the freelist queue.
* Currently, they are added on an LRU basis.
*/
void
-AddBufferToFreelist(BufferDesc *bf)
+AddBufferToFreelist(BufferDesc * bf)
{
#ifdef BMTRACE
- _bm_trace(bf->tag.relId.dbId, bf->tag.relId.relId, bf->tag.blockNum,
- BufferDescriptorGetBuffer(bf), BMT_DEALLOC);
-#endif /* BMTRACE */
- NotInQueue(bf);
-
- /* change bf so it points to inFrontOfNew and its successor */
- bf->freePrev = SharedFreeList->freePrev;
- bf->freeNext = Free_List_Descriptor;
-
- /* insert new into chain */
- BufferDescriptors[bf->freeNext].freePrev = bf->buf_id;
- BufferDescriptors[bf->freePrev].freeNext = bf->buf_id;
+ _bm_trace(bf->tag.relId.dbId, bf->tag.relId.relId, bf->tag.blockNum,
+ BufferDescriptorGetBuffer(bf), BMT_DEALLOC);
+#endif /* BMTRACE */
+ NotInQueue(bf);
+
+ /* change bf so it points to inFrontOfNew and its successor */
+ bf->freePrev = SharedFreeList->freePrev;
+ bf->freeNext = Free_List_Descriptor;
+
+ /* insert new into chain */
+ BufferDescriptors[bf->freeNext].freePrev = bf->buf_id;
+ BufferDescriptors[bf->freePrev].freeNext = bf->buf_id;
}
#undef PinBuffer
@@ -82,47 +82,52 @@ AddBufferToFreelist(BufferDesc *bf)
* PinBuffer -- make buffer unavailable for replacement.
*/
void
-PinBuffer(BufferDesc *buf)
+PinBuffer(BufferDesc * buf)
{
- long b;
-
- /* Assert (buf->refcount < 25); */
-
- if (buf->refcount == 0) {
- IsInQueue(buf);
-
- /* remove from freelist queue */
- BufferDescriptors[buf->freeNext].freePrev = buf->freePrev;
- BufferDescriptors[buf->freePrev].freeNext = buf->freeNext;
- buf->freeNext = buf->freePrev = INVALID_DESCRIPTOR;
-
- /* mark buffer as no longer free */
- buf->flags &= ~BM_FREE;
- } else {
- NotInQueue(buf);
- }
-
- b = BufferDescriptorGetBuffer(buf) - 1;
- Assert(PrivateRefCount[b] >= 0);
- if (PrivateRefCount[b] == 0 && LastRefCount[b] == 0)
- buf->refcount++;
- PrivateRefCount[b]++;
+ long b;
+
+ /* Assert (buf->refcount < 25); */
+
+ if (buf->refcount == 0)
+ {
+ IsInQueue(buf);
+
+ /* remove from freelist queue */
+ BufferDescriptors[buf->freeNext].freePrev = buf->freePrev;
+ BufferDescriptors[buf->freePrev].freeNext = buf->freeNext;
+ buf->freeNext = buf->freePrev = INVALID_DESCRIPTOR;
+
+ /* mark buffer as no longer free */
+ buf->flags &= ~BM_FREE;
+ }
+ else
+ {
+ NotInQueue(buf);
+ }
+
+ b = BufferDescriptorGetBuffer(buf) - 1;
+ Assert(PrivateRefCount[b] >= 0);
+ if (PrivateRefCount[b] == 0 && LastRefCount[b] == 0)
+ buf->refcount++;
+ PrivateRefCount[b]++;
}
#ifdef NOT_USED
void
-PinBuffer_Debug(char *file, int line, BufferDesc *buf)
+PinBuffer_Debug(char *file, int line, BufferDesc * buf)
{
- PinBuffer(buf);
- if (ShowPinTrace) {
- Buffer buffer = BufferDescriptorGetBuffer(buf);
-
- fprintf(stderr, "PIN(Pin) %ld relname = %s, blockNum = %d, \
+ PinBuffer(buf);
+ if (ShowPinTrace)
+ {
+ Buffer buffer = BufferDescriptorGetBuffer(buf);
+
+ fprintf(stderr, "PIN(Pin) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
- buffer, buf->sb_relname, buf->tag.blockNum,
- PrivateRefCount[buffer - 1], file, line);
- }
+ buffer, buf->sb_relname, buf->tag.blockNum,
+ PrivateRefCount[buffer - 1], file, line);
+ }
}
+
#endif
#undef UnpinBuffer
@@ -131,95 +136,102 @@ refcount = %ld, file: %s, line: %d\n",
* UnpinBuffer -- make buffer available for replacement.
*/
void
-UnpinBuffer(BufferDesc *buf)
+UnpinBuffer(BufferDesc * buf)
{
- long b = BufferDescriptorGetBuffer(buf) - 1;
-
- Assert(buf->refcount);
- Assert(PrivateRefCount[b] > 0);
- PrivateRefCount[b]--;
- if (PrivateRefCount[b] == 0 && LastRefCount[b] == 0)
- buf->refcount--;
- NotInQueue(buf);
-
- if (buf->refcount == 0) {
- AddBufferToFreelist(buf);
- buf->flags |= BM_FREE;
- } else {
- /* do nothing */
- }
+ long b = BufferDescriptorGetBuffer(buf) - 1;
+
+ Assert(buf->refcount);
+ Assert(PrivateRefCount[b] > 0);
+ PrivateRefCount[b]--;
+ if (PrivateRefCount[b] == 0 && LastRefCount[b] == 0)
+ buf->refcount--;
+ NotInQueue(buf);
+
+ if (buf->refcount == 0)
+ {
+ AddBufferToFreelist(buf);
+ buf->flags |= BM_FREE;
+ }
+ else
+ {
+ /* do nothing */
+ }
}
#ifdef NOT_USED
void
-UnpinBuffer_Debug(char *file, int line, BufferDesc *buf)
+UnpinBuffer_Debug(char *file, int line, BufferDesc * buf)
{
- UnpinBuffer(buf);
- if (ShowPinTrace) {
- Buffer buffer = BufferDescriptorGetBuffer(buf);
-
- fprintf(stderr, "UNPIN(Unpin) %ld relname = %s, blockNum = %d, \
+ UnpinBuffer(buf);
+ if (ShowPinTrace)
+ {
+ Buffer buffer = BufferDescriptorGetBuffer(buf);
+
+ fprintf(stderr, "UNPIN(Unpin) %ld relname = %s, blockNum = %d, \
refcount = %ld, file: %s, line: %d\n",
- buffer, buf->sb_relname, buf->tag.blockNum,
- PrivateRefCount[buffer - 1], file, line);
- }
+ buffer, buf->sb_relname, buf->tag.blockNum,
+ PrivateRefCount[buffer - 1], file, line);
+ }
}
+
#endif
/*
* GetFreeBuffer() -- get the 'next' buffer from the freelist.
*
*/
-BufferDesc *
+BufferDesc *
GetFreeBuffer()
{
- BufferDesc *buf;
-
- if (Free_List_Descriptor == SharedFreeList->freeNext) {
-
- /* queue is empty. All buffers in the buffer pool are pinned. */
- elog(WARN,"out of free buffers: time to abort !\n");
- return(NULL);
- }
- buf = &(BufferDescriptors[SharedFreeList->freeNext]);
-
- /* remove from freelist queue */
- BufferDescriptors[buf->freeNext].freePrev = buf->freePrev;
- BufferDescriptors[buf->freePrev].freeNext = buf->freeNext;
- buf->freeNext = buf->freePrev = INVALID_DESCRIPTOR;
-
- buf->flags &= ~(BM_FREE);
-
- return(buf);
+ BufferDesc *buf;
+
+ if (Free_List_Descriptor == SharedFreeList->freeNext)
+ {
+
+ /* queue is empty. All buffers in the buffer pool are pinned. */
+ elog(WARN, "out of free buffers: time to abort !\n");
+ return (NULL);
+ }
+ buf = &(BufferDescriptors[SharedFreeList->freeNext]);
+
+ /* remove from freelist queue */
+ BufferDescriptors[buf->freeNext].freePrev = buf->freePrev;
+ BufferDescriptors[buf->freePrev].freeNext = buf->freeNext;
+ buf->freeNext = buf->freePrev = INVALID_DESCRIPTOR;
+
+ buf->flags &= ~(BM_FREE);
+
+ return (buf);
}
/*
* InitFreeList -- initialize the dummy buffer descriptor used
- * as a freelist head.
+ * as a freelist head.
*
* Assume: All of the buffers are already linked in a circular
- * queue. Only called by postmaster and only during
- * initialization.
+ * queue. Only called by postmaster and only during
+ * initialization.
*/
void
InitFreeList(bool init)
{
- SharedFreeList = &(BufferDescriptors[Free_List_Descriptor]);
-
- if (init) {
- /* we only do this once, normally the postmaster */
- SharedFreeList->data = INVALID_OFFSET;
- SharedFreeList->flags = 0;
- SharedFreeList->flags &= ~(BM_VALID | BM_DELETED | BM_FREE);
- SharedFreeList->buf_id = Free_List_Descriptor;
-
- /* insert it into a random spot in the circular queue */
- SharedFreeList->freeNext = BufferDescriptors[0].freeNext;
- SharedFreeList->freePrev = 0;
- BufferDescriptors[SharedFreeList->freeNext].freePrev =
- BufferDescriptors[SharedFreeList->freePrev].freeNext =
- Free_List_Descriptor;
- }
+ SharedFreeList = &(BufferDescriptors[Free_List_Descriptor]);
+
+ if (init)
+ {
+ /* we only do this once, normally the postmaster */
+ SharedFreeList->data = INVALID_OFFSET;
+ SharedFreeList->flags = 0;
+ SharedFreeList->flags &= ~(BM_VALID | BM_DELETED | BM_FREE);
+ SharedFreeList->buf_id = Free_List_Descriptor;
+
+ /* insert it into a random spot in the circular queue */
+ SharedFreeList->freeNext = BufferDescriptors[0].freeNext;
+ SharedFreeList->freePrev = 0;
+ BufferDescriptors[SharedFreeList->freeNext].freePrev =
+ BufferDescriptors[SharedFreeList->freePrev].freeNext =
+ Free_List_Descriptor;
+ }
}
@@ -230,67 +242,78 @@ InitFreeList(bool init)
void
DBG_FreeListCheck(int nfree)
{
- int i;
- BufferDesc *buf;
-
- buf = &(BufferDescriptors[SharedFreeList->freeNext]);
- for (i=0;i<nfree;i++,buf = &(BufferDescriptors[buf->freeNext])) {
-
- if (! (buf->flags & (BM_FREE))){
- if (buf != SharedFreeList) {
- printf("\tfree list corrupted: %d flags %x\n",
- buf->buf_id,buf->flags);
- } else {
- printf("\tfree list corrupted: too short -- %d not %d\n",
- i,nfree);
-
- }
-
-
+ int i;
+ BufferDesc *buf;
+
+ buf = &(BufferDescriptors[SharedFreeList->freeNext]);
+ for (i = 0; i < nfree; i++, buf = &(BufferDescriptors[buf->freeNext]))
+ {
+
+ if (!(buf->flags & (BM_FREE)))
+ {
+ if (buf != SharedFreeList)
+ {
+ printf("\tfree list corrupted: %d flags %x\n",
+ buf->buf_id, buf->flags);
+ }
+ else
+ {
+ printf("\tfree list corrupted: too short -- %d not %d\n",
+ i, nfree);
+
+ }
+
+
+ }
+ if ((BufferDescriptors[buf->freeNext].freePrev != buf->buf_id) ||
+ (BufferDescriptors[buf->freePrev].freeNext != buf->buf_id))
+ {
+ printf("\tfree list links corrupted: %d %ld %ld\n",
+ buf->buf_id, buf->freePrev, buf->freeNext);
+ }
+
}
- if ((BufferDescriptors[buf->freeNext].freePrev != buf->buf_id) ||
- (BufferDescriptors[buf->freePrev].freeNext != buf->buf_id)) {
- printf("\tfree list links corrupted: %d %ld %ld\n",
- buf->buf_id,buf->freePrev,buf->freeNext);
+ if (buf != SharedFreeList)
+ {
+ printf("\tfree list corrupted: %d-th buffer is %d\n",
+ nfree, buf->buf_id);
+
}
-
- }
- if (buf != SharedFreeList) {
- printf("\tfree list corrupted: %d-th buffer is %d\n",
- nfree,buf->buf_id);
-
- }
}
+
#endif
#ifdef NOT_USED
/*
* PrintBufferFreeList -
- * prints the buffer free list, for debugging
+ * prints the buffer free list, for debugging
*/
static void
PrintBufferFreeList()
{
- BufferDesc *buf;
-
- if (SharedFreeList->freeNext == Free_List_Descriptor) {
- printf("free list is empty.\n");
- return;
- }
-
- buf = &(BufferDescriptors[SharedFreeList->freeNext]);
- for (;;) {
- int i = (buf - BufferDescriptors);
- printf("[%-2d] (%s, %d) flags=0x%x, refcnt=%d %ld, nxt=%ld prv=%ld)\n",
- i, buf->sb_relname, buf->tag.blockNum,
- buf->flags, buf->refcount, PrivateRefCount[i],
- buf->freeNext, buf->freePrev);
-
- if (buf->freeNext == Free_List_Descriptor)
- break;
-
- buf = &(BufferDescriptors[buf->freeNext]);
- }
+ BufferDesc *buf;
+
+ if (SharedFreeList->freeNext == Free_List_Descriptor)
+ {
+ printf("free list is empty.\n");
+ return;
+ }
+
+ buf = &(BufferDescriptors[SharedFreeList->freeNext]);
+ for (;;)
+ {
+ int i = (buf - BufferDescriptors);
+
+ printf("[%-2d] (%s, %d) flags=0x%x, refcnt=%d %ld, nxt=%ld prv=%ld)\n",
+ i, buf->sb_relname, buf->tag.blockNum,
+ buf->flags, buf->refcount, PrivateRefCount[i],
+ buf->freeNext, buf->freePrev);
+
+ if (buf->freeNext == Free_List_Descriptor)
+ break;
+
+ buf = &(BufferDescriptors[buf->freeNext]);
+ }
}
#endif
diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c
index 910cb668d7a..072830b3dd6 100644
--- a/src/backend/storage/buffer/localbuf.c
+++ b/src/backend/storage/buffer/localbuf.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* localbuf.c--
- * local buffer manager. Fast buffer manager for temporary tables
- * or special cases when the operation is not visible to other backends.
+ * local buffer manager. Fast buffer manager for temporary tables
+ * or special cases when the operation is not visible to other backends.
*
- * When a relation is being created, the descriptor will have rd_islocal
- * set to indicate that the local buffer manager should be used. During
- * the same transaction the relation is being created, any inserts or
- * selects from the newly created relation will use the local buffer
- * pool. rd_islocal is reset at the end of a transaction (commit/abort).
- * This is useful for queries like SELECT INTO TABLE and create index.
+ * When a relation is being created, the descriptor will have rd_islocal
+ * set to indicate that the local buffer manager should be used. During
+ * the same transaction the relation is being created, any inserts or
+ * selects from the newly created relation will use the local buffer
+ * pool. rd_islocal is reset at the end of a transaction (commit/abort).
+ * This is useful for queries like SELECT INTO TABLE and create index.
*
* Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.8 1997/07/28 00:54:48 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.9 1997/09/07 04:48:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -45,252 +45,262 @@
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/relcache.h"
-#include "executor/execdebug.h" /* for NDirectFileRead */
+#include "executor/execdebug.h" /* for NDirectFileRead */
#include "catalog/catalog.h"
extern long int LocalBufferFlushCount;
-int NLocBuffer = 64;
-BufferDesc *LocalBufferDescriptors = NULL;
-long *LocalRefCount = NULL;
+int NLocBuffer = 64;
+BufferDesc *LocalBufferDescriptors = NULL;
+long *LocalRefCount = NULL;
-static int nextFreeLocalBuf = 0;
+static int nextFreeLocalBuf = 0;
/*#define LBDEBUG*/
/*
* LocalBufferAlloc -
- * allocate a local buffer. We do round robin allocation for now.
+ * allocate a local buffer. We do round robin allocation for now.
*/
-BufferDesc *
-LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
+BufferDesc *
+LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool * foundPtr)
{
- int i;
- BufferDesc *bufHdr = (BufferDesc *) NULL;
+ int i;
+ BufferDesc *bufHdr = (BufferDesc *) NULL;
- if (blockNum == P_NEW) {
- blockNum = reln->rd_nblocks;
- reln->rd_nblocks++;
- }
+ if (blockNum == P_NEW)
+ {
+ blockNum = reln->rd_nblocks;
+ reln->rd_nblocks++;
+ }
- /* a low tech search for now -- not optimized for scans */
- for (i=0; i < NLocBuffer; i++) {
- if (LocalBufferDescriptors[i].tag.relId.relId == reln->rd_id &&
- LocalBufferDescriptors[i].tag.blockNum == blockNum) {
+ /* a low tech search for now -- not optimized for scans */
+ for (i = 0; i < NLocBuffer; i++)
+ {
+ if (LocalBufferDescriptors[i].tag.relId.relId == reln->rd_id &&
+ LocalBufferDescriptors[i].tag.blockNum == blockNum)
+ {
#ifdef LBDEBUG
- fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
- reln->rd_id, blockNum, -i-1);
-#endif
- LocalRefCount[i]++;
- *foundPtr = TRUE;
- return &LocalBufferDescriptors[i];
+ fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
+ reln->rd_id, blockNum, -i - 1);
+#endif
+ LocalRefCount[i]++;
+ *foundPtr = TRUE;
+ return &LocalBufferDescriptors[i];
+ }
}
- }
#ifdef LBDEBUG
- fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
- reln->rd_id, blockNum, -nextFreeLocalBuf-1);
-#endif
-
- /* need to get a new buffer (round robin for now) */
- for(i=0; i < NLocBuffer; i++) {
- int b = (nextFreeLocalBuf + i) % NLocBuffer;
-
- if (LocalRefCount[b]==0) {
- bufHdr = &LocalBufferDescriptors[b];
- LocalRefCount[b]++;
- nextFreeLocalBuf = (b + 1) % NLocBuffer;
- break;
+ fprintf(stderr, "LB ALLOC (%d,%d) %d\n",
+ reln->rd_id, blockNum, -nextFreeLocalBuf - 1);
+#endif
+
+ /* need to get a new buffer (round robin for now) */
+ for (i = 0; i < NLocBuffer; i++)
+ {
+ int b = (nextFreeLocalBuf + i) % NLocBuffer;
+
+ if (LocalRefCount[b] == 0)
+ {
+ bufHdr = &LocalBufferDescriptors[b];
+ LocalRefCount[b]++;
+ nextFreeLocalBuf = (b + 1) % NLocBuffer;
+ break;
+ }
}
- }
- if (bufHdr==NULL)
- elog(WARN, "no empty local buffer.");
-
- /*
- * this buffer is not referenced but it might still be dirty (the
- * last transaction to touch it doesn't need its contents but has
- * not flushed it). if that's the case, write it out before
- * reusing it!
- */
- if (bufHdr->flags & BM_DIRTY) {
- Relation bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
+ if (bufHdr == NULL)
+ elog(WARN, "no empty local buffer.");
- Assert(bufrel != NULL);
-
- /* flush this page */
- smgrwrite(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data));
- LocalBufferFlushCount++;
- }
-
- /*
- * it's all ours now.
- */
- bufHdr->tag.relId.relId = reln->rd_id;
- bufHdr->tag.blockNum = blockNum;
- bufHdr->flags &= ~BM_DIRTY;
-
- /*
- * lazy memory allocation. (see MAKE_PTR for why we need to do
- * MAKE_OFFSET.)
- */
- if (bufHdr->data == (SHMEM_OFFSET)0) {
- char *data = (char *)malloc(BLCKSZ);
-
- bufHdr->data = MAKE_OFFSET(data);
- }
-
- *foundPtr = FALSE;
- return bufHdr;
+ /*
+ * this buffer is not referenced but it might still be dirty (the last
+ * transaction to touch it doesn't need its contents but has not
+ * flushed it). if that's the case, write it out before reusing it!
+ */
+ if (bufHdr->flags & BM_DIRTY)
+ {
+ Relation bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
+
+ Assert(bufrel != NULL);
+
+ /* flush this page */
+ smgrwrite(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
+ (char *) MAKE_PTR(bufHdr->data));
+ LocalBufferFlushCount++;
+ }
+
+ /*
+ * it's all ours now.
+ */
+ bufHdr->tag.relId.relId = reln->rd_id;
+ bufHdr->tag.blockNum = blockNum;
+ bufHdr->flags &= ~BM_DIRTY;
+
+ /*
+ * lazy memory allocation. (see MAKE_PTR for why we need to do
+ * MAKE_OFFSET.)
+ */
+ if (bufHdr->data == (SHMEM_OFFSET) 0)
+ {
+ char *data = (char *) malloc(BLCKSZ);
+
+ bufHdr->data = MAKE_OFFSET(data);
+ }
+
+ *foundPtr = FALSE;
+ return bufHdr;
}
/*
* WriteLocalBuffer -
- * writes out a local buffer
+ * writes out a local buffer
*/
int
WriteLocalBuffer(Buffer buffer, bool release)
{
- int bufid;
+ int bufid;
- Assert(BufferIsLocal(buffer));
+ Assert(BufferIsLocal(buffer));
#ifdef LBDEBUG
- fprintf(stderr, "LB WRITE %d\n", buffer);
-#endif
-
- bufid = - (buffer + 1);
- LocalBufferDescriptors[bufid].flags |= BM_DIRTY;
+ fprintf(stderr, "LB WRITE %d\n", buffer);
+#endif
- if (release) {
- Assert(LocalRefCount[bufid] > 0);
- LocalRefCount[bufid]--;
- }
+ bufid = -(buffer + 1);
+ LocalBufferDescriptors[bufid].flags |= BM_DIRTY;
+
+ if (release)
+ {
+ Assert(LocalRefCount[bufid] > 0);
+ LocalRefCount[bufid]--;
+ }
- return true;
+ return true;
}
/*
* FlushLocalBuffer -
- * flushes a local buffer
+ * flushes a local buffer
*/
int
FlushLocalBuffer(Buffer buffer, bool release)
{
- int bufid;
- Relation bufrel;
- BufferDesc *bufHdr;
+ int bufid;
+ Relation bufrel;
+ BufferDesc *bufHdr;
- Assert(BufferIsLocal(buffer));
+ Assert(BufferIsLocal(buffer));
#ifdef LBDEBUG
- fprintf(stderr, "LB FLUSH %d\n", buffer);
-#endif
-
- bufid = - (buffer + 1);
- bufHdr = &LocalBufferDescriptors[bufid];
- bufHdr->flags &= ~BM_DIRTY;
- bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
-
- Assert(bufrel != NULL);
- smgrflush(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data));
- LocalBufferFlushCount++;
-
- Assert(LocalRefCount[bufid] > 0);
- if ( release )
- LocalRefCount[bufid]--;
-
- return true;
+ fprintf(stderr, "LB FLUSH %d\n", buffer);
+#endif
+
+ bufid = -(buffer + 1);
+ bufHdr = &LocalBufferDescriptors[bufid];
+ bufHdr->flags &= ~BM_DIRTY;
+ bufrel = RelationIdCacheGetRelation(bufHdr->tag.relId.relId);
+
+ Assert(bufrel != NULL);
+ smgrflush(bufrel->rd_rel->relsmgr, bufrel, bufHdr->tag.blockNum,
+ (char *) MAKE_PTR(bufHdr->data));
+ LocalBufferFlushCount++;
+
+ Assert(LocalRefCount[bufid] > 0);
+ if (release)
+ LocalRefCount[bufid]--;
+
+ return true;
}
/*
* InitLocalBuffer -
- * init the local buffer cache. Since most queries (esp. multi-user ones)
- * don't involve local buffers, we delay allocating memory for actual the
- * buffer until we need it.
+ * init the local buffer cache. Since most queries (esp. multi-user ones)
+ * don't involve local buffers, we delay allocating memory for actual the
+ * buffer until we need it.
*/
void
InitLocalBuffer(void)
{
- int i;
-
- /*
- * these aren't going away. I'm not gonna use palloc.
- */
- LocalBufferDescriptors =
- (BufferDesc *)malloc(sizeof(BufferDesc) * NLocBuffer);
- memset(LocalBufferDescriptors, 0, sizeof(BufferDesc) * NLocBuffer);
- nextFreeLocalBuf = 0;
-
- for (i = 0; i < NLocBuffer; i++) {
- BufferDesc *buf = &LocalBufferDescriptors[i];
+ int i;
/*
- * negative to indicate local buffer. This is tricky: shared buffers
- * start with 0. We have to start with -2. (Note that the routine
- * BufferDescriptorGetBuffer adds 1 to buf_id so our first buffer id
- * is -1.)
+ * these aren't going away. I'm not gonna use palloc.
*/
- buf->buf_id = - i - 2;
- }
+ LocalBufferDescriptors =
+ (BufferDesc *) malloc(sizeof(BufferDesc) * NLocBuffer);
+ memset(LocalBufferDescriptors, 0, sizeof(BufferDesc) * NLocBuffer);
+ nextFreeLocalBuf = 0;
+
+ for (i = 0; i < NLocBuffer; i++)
+ {
+ BufferDesc *buf = &LocalBufferDescriptors[i];
+
+ /*
+ * negative to indicate local buffer. This is tricky: shared
+ * buffers start with 0. We have to start with -2. (Note that the
+ * routine BufferDescriptorGetBuffer adds 1 to buf_id so our first
+ * buffer id is -1.)
+ */
+ buf->buf_id = -i - 2;
+ }
- LocalRefCount =
- (long *)malloc(sizeof(long) * NLocBuffer);
- memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
+ LocalRefCount =
+ (long *) malloc(sizeof(long) * NLocBuffer);
+ memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
}
/*
* LocalBufferSync -
- * flush all dirty buffers in the local buffer cache. Since the buffer
- * cache is only used for keeping relations visible during a transaction,
- * we will not need these buffers again.
+ * flush all dirty buffers in the local buffer cache. Since the buffer
+ * cache is only used for keeping relations visible during a transaction,
+ * we will not need these buffers again.
*/
void
LocalBufferSync(void)
{
- int i;
-
- for (i = 0; i < NLocBuffer; i++) {
- BufferDesc *buf = &LocalBufferDescriptors[i];
- Relation bufrel;
+ int i;
+
+ for (i = 0; i < NLocBuffer; i++)
+ {
+ BufferDesc *buf = &LocalBufferDescriptors[i];
+ Relation bufrel;
- if (buf->flags & BM_DIRTY) {
+ if (buf->flags & BM_DIRTY)
+ {
#ifdef LBDEBUG
- fprintf(stderr, "LB SYNC %d\n", -i-1);
-#endif
- bufrel = RelationIdCacheGetRelation(buf->tag.relId.relId);
-
- Assert(bufrel != NULL);
-
- smgrwrite(bufrel->rd_rel->relsmgr, bufrel, buf->tag.blockNum,
- (char *) MAKE_PTR(buf->data));
- LocalBufferFlushCount++;
-
- buf->tag.relId.relId = InvalidOid;
- buf->flags &= ~BM_DIRTY;
+ fprintf(stderr, "LB SYNC %d\n", -i - 1);
+#endif
+ bufrel = RelationIdCacheGetRelation(buf->tag.relId.relId);
+
+ Assert(bufrel != NULL);
+
+ smgrwrite(bufrel->rd_rel->relsmgr, bufrel, buf->tag.blockNum,
+ (char *) MAKE_PTR(buf->data));
+ LocalBufferFlushCount++;
+
+ buf->tag.relId.relId = InvalidOid;
+ buf->flags &= ~BM_DIRTY;
+ }
}
- }
- memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
- nextFreeLocalBuf = 0;
+ memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
+ nextFreeLocalBuf = 0;
}
void
ResetLocalBufferPool(void)
{
- int i;
+ int i;
- for (i = 0; i < NLocBuffer; i++)
- {
- BufferDesc *buf = &LocalBufferDescriptors[i];
+ for (i = 0; i < NLocBuffer; i++)
+ {
+ BufferDesc *buf = &LocalBufferDescriptors[i];
- buf->tag.relId.relId = InvalidOid;
- buf->flags &= ~BM_DIRTY;
- buf->buf_id = - i - 2;
- }
+ buf->tag.relId.relId = InvalidOid;
+ buf->flags &= ~BM_DIRTY;
+ buf->buf_id = -i - 2;
+ }
- memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
- nextFreeLocalBuf = 0;
+ memset(LocalRefCount, 0, sizeof(long) * NLocBuffer);
+ nextFreeLocalBuf = 0;
}
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 03605332344..2e998f27196 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -1,12 +1,12 @@
/*-------------------------------------------------------------------------
*
* fd.c--
- * Virtual file descriptor code.
+ * Virtual file descriptor code.
*
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Id: fd.c,v 1.22 1997/08/19 21:32:48 momjian Exp $
+ * $Id: fd.c,v 1.23 1997/09/07 04:48:25 momjian Exp $
*
* NOTES:
*
@@ -48,7 +48,7 @@
#include <fcntl.h>
#include "postgres.h"
-#include "miscadmin.h" /* for DataDir */
+#include "miscadmin.h" /* for DataDir */
#include "utils/palloc.h"
#include "storage/fd.h"
@@ -67,8 +67,8 @@
* dynamic loading. Keep this here.)
*/
#ifndef RESERVE_FOR_LD
-#define RESERVE_FOR_LD 10
-#endif
+#define RESERVE_FOR_LD 10
+#endif
/*
* We need to ensure that we have at least some file descriptors
@@ -85,9 +85,9 @@
/* Debugging.... */
#ifdef FDDEBUG
-# define DO_DB(A) A
+#define DO_DB(A) A
#else
-# define DO_DB(A) /* A */
+#define DO_DB(A) /* A */
#endif
#define VFD_CLOSED -1
@@ -97,474 +97,501 @@
#define FileIsNotOpen(file) (VfdCache[file].fd == VFD_CLOSED)
-typedef struct vfd {
- signed short fd;
- unsigned short fdstate;
+typedef struct vfd
+{
+ signed short fd;
+ unsigned short fdstate;
-#define FD_DIRTY (1 << 0)
+#define FD_DIRTY (1 << 0)
- File nextFree;
- File lruMoreRecently;
- File lruLessRecently;
- long seekPos;
- char *fileName;
- int fileFlags;
- int fileMode;
-} Vfd;
+ File nextFree;
+ File lruMoreRecently;
+ File lruLessRecently;
+ long seekPos;
+ char *fileName;
+ int fileFlags;
+ int fileMode;
+} Vfd;
/*
- * Virtual File Descriptor array pointer and size. This grows as
+ * Virtual File Descriptor array pointer and size. This grows as
* needed.
*/
-static Vfd *VfdCache;
-static Size SizeVfdCache = 0;
+static Vfd *VfdCache;
+static Size SizeVfdCache = 0;
/*
* Number of file descriptors known to be open.
*/
-static int nfile = 0;
+static int nfile = 0;
-static char Sep_char = '/';
+static char Sep_char = '/';
/*
* Private Routines
*
- * Delete - delete a file from the Lru ring
- * LruDelete - remove a file from the Lru ring and close
- * Insert - put a file at the front of the Lru ring
- * LruInsert - put a file at the front of the Lru ring and open
+ * Delete - delete a file from the Lru ring
+ * LruDelete - remove a file from the Lru ring and close
+ * Insert - put a file at the front of the Lru ring
+ * LruInsert - put a file at the front of the Lru ring and open
* AssertLruRoom - make sure that there is a free fd.
*
* the Last Recently Used ring is a doubly linked list that begins and
* ends on element zero. Element zero is special -- it doesn't represent
- * a file and its "fd" field always == VFD_CLOSED. Element zero is just an
+ * a file and its "fd" field always == VFD_CLOSED. Element zero is just an
* anchor that shows us the beginning/end of the ring.
*
* example:
*
- * /--less----\ /---------\
- * v \ v \
- * #0 --more---> LeastRecentlyUsed --more-\ \
- * ^\ | |
- * \\less--> MostRecentlyUsedFile <---/ |
- * \more---/ \--less--/
+ * /--less----\ /---------\
+ * v \ v \
+ * #0 --more---> LeastRecentlyUsed --more-\ \
+ * ^\ | |
+ * \\less--> MostRecentlyUsedFile <---/ |
+ * \more---/ \--less--/
*
- * AllocateVfd - grab a free (or new) file record (from VfdArray)
- * FreeVfd - free a file record
+ * AllocateVfd - grab a free (or new) file record (from VfdArray)
+ * FreeVfd - free a file record
*
*/
-static void Delete(File file);
-static void LruDelete(File file);
-static void Insert(File file);
-static int LruInsert (File file);
-static void AssertLruRoom(void);
-static File AllocateVfd(void);
-static void FreeVfd(File file);
-
-static int FileAccess(File file);
-static File fileNameOpenFile(FileName fileName, int fileFlags, int fileMode);
-static char *filepath(char *filename);
-static long pg_nofile(void);
+static void Delete(File file);
+static void LruDelete(File file);
+static void Insert(File file);
+static int LruInsert(File file);
+static void AssertLruRoom(void);
+static File AllocateVfd(void);
+static void FreeVfd(File file);
+
+static int FileAccess(File file);
+static File fileNameOpenFile(FileName fileName, int fileFlags, int fileMode);
+static char *filepath(char *filename);
+static long pg_nofile(void);
int
pg_fsync(int fd)
{
- extern int fsyncOff;
- return fsyncOff ? 0 : fsync(fd);
+ extern int fsyncOff;
+
+ return fsyncOff ? 0 : fsync(fd);
}
+
#define fsync pg_fsync
long
pg_nofile(void)
{
- static long no_files = 0;
+ static long no_files = 0;
- if (no_files == 0) {
-#ifndef HAVE_SYSCONF
- no_files = (long)NOFILE;
+ if (no_files == 0)
+ {
+#ifndef HAVE_SYSCONF
+ no_files = (long) NOFILE;
#else
- no_files = sysconf(_SC_OPEN_MAX);
- if (no_files == -1) {
- elog(DEBUG,"pg_nofile: Unable to get _SC_OPEN_MAX using sysconf() using (%d)", NOFILE);
- no_files = (long)NOFILE;
+ no_files = sysconf(_SC_OPEN_MAX);
+ if (no_files == -1)
+ {
+ elog(DEBUG, "pg_nofile: Unable to get _SC_OPEN_MAX using sysconf() using (%d)", NOFILE);
+ no_files = (long) NOFILE;
}
-#endif
- }
+#endif
+ }
if ((no_files - RESERVE_FOR_LD) < FD_MINFREE)
- elog(FATAL,"pg_nofile: insufficient File Descriptors in postmaster to start backend (%ld).\n"
- " O/S allows %ld, Postmaster reserves %d, We need %d (MIN) after that.",
- no_files - RESERVE_FOR_LD, no_files, RESERVE_FOR_LD, FD_MINFREE);
- return no_files - RESERVE_FOR_LD;
+ elog(FATAL, "pg_nofile: insufficient File Descriptors in postmaster to start backend (%ld).\n"
+ " O/S allows %ld, Postmaster reserves %d, We need %d (MIN) after that.",
+ no_files - RESERVE_FOR_LD, no_files, RESERVE_FOR_LD, FD_MINFREE);
+ return no_files - RESERVE_FOR_LD;
}
#if defined(FDDEBUG)
static void
_dump_lru()
{
- int mru = VfdCache[0].lruLessRecently;
- Vfd *vfdP = &VfdCache[mru];
- char buf[2048];
-
- sprintf(buf, "LRU: MOST %d ", mru);
- while (mru != 0)
- {
- mru = vfdP->lruLessRecently;
- vfdP = &VfdCache[mru];
- sprintf (buf + strlen(buf), "%d ", mru);
- }
- sprintf(buf + strlen(buf), "LEAST");
- elog (DEBUG, buf);
+ int mru = VfdCache[0].lruLessRecently;
+ Vfd *vfdP = &VfdCache[mru];
+ char buf[2048];
+
+ sprintf(buf, "LRU: MOST %d ", mru);
+ while (mru != 0)
+ {
+ mru = vfdP->lruLessRecently;
+ vfdP = &VfdCache[mru];
+ sprintf(buf + strlen(buf), "%d ", mru);
+ }
+ sprintf(buf + strlen(buf), "LEAST");
+ elog(DEBUG, buf);
}
-#endif /* FDDEBUG */
+
+#endif /* FDDEBUG */
static void
Delete(File file)
{
- Vfd *fileP;
-
- DO_DB(elog (DEBUG, "Delete %d (%s)",
- file, VfdCache[file].fileName));
- DO_DB(_dump_lru());
-
- Assert(file != 0);
-
- fileP = &VfdCache[file];
-
- VfdCache[fileP->lruLessRecently].lruMoreRecently =
- VfdCache[file].lruMoreRecently;
- VfdCache[fileP->lruMoreRecently].lruLessRecently =
- VfdCache[file].lruLessRecently;
-
- DO_DB(_dump_lru());
+ Vfd *fileP;
+
+ DO_DB(elog(DEBUG, "Delete %d (%s)",
+ file, VfdCache[file].fileName));
+ DO_DB(_dump_lru());
+
+ Assert(file != 0);
+
+ fileP = &VfdCache[file];
+
+ VfdCache[fileP->lruLessRecently].lruMoreRecently =
+ VfdCache[file].lruMoreRecently;
+ VfdCache[fileP->lruMoreRecently].lruLessRecently =
+ VfdCache[file].lruLessRecently;
+
+ DO_DB(_dump_lru());
}
static void
LruDelete(File file)
{
- Vfd *fileP;
- int returnValue;
-
- DO_DB(elog (DEBUG, "LruDelete %d (%s)",
- file, VfdCache[file].fileName));
-
- Assert(file != 0);
-
- fileP = &VfdCache[file];
-
- /* delete the vfd record from the LRU ring */
- Delete(file);
-
- /* save the seek position */
- fileP->seekPos = (long) lseek(fileP->fd, 0L, SEEK_CUR);
- Assert( fileP->seekPos != -1);
-
- /* if we have written to the file, sync it */
- if (fileP->fdstate & FD_DIRTY) {
- returnValue = fsync(fileP->fd);
- Assert(returnValue != -1);
- fileP->fdstate &= ~FD_DIRTY;
- }
-
- /* close the file */
- returnValue = close(fileP->fd);
- Assert(returnValue != -1);
-
- --nfile;
- fileP->fd = VFD_CLOSED;
+ Vfd *fileP;
+ int returnValue;
+
+ DO_DB(elog(DEBUG, "LruDelete %d (%s)",
+ file, VfdCache[file].fileName));
+
+ Assert(file != 0);
+
+ fileP = &VfdCache[file];
+
+ /* delete the vfd record from the LRU ring */
+ Delete(file);
+
+ /* save the seek position */
+ fileP->seekPos = (long) lseek(fileP->fd, 0L, SEEK_CUR);
+ Assert(fileP->seekPos != -1);
+
+ /* if we have written to the file, sync it */
+ if (fileP->fdstate & FD_DIRTY)
+ {
+ returnValue = fsync(fileP->fd);
+ Assert(returnValue != -1);
+ fileP->fdstate &= ~FD_DIRTY;
+ }
+
+ /* close the file */
+ returnValue = close(fileP->fd);
+ Assert(returnValue != -1);
+
+ --nfile;
+ fileP->fd = VFD_CLOSED;
}
static void
Insert(File file)
{
- Vfd *vfdP;
-
- DO_DB(elog(DEBUG, "Insert %d (%s)",
- file, VfdCache[file].fileName));
- DO_DB(_dump_lru());
-
- vfdP = &VfdCache[file];
-
- vfdP->lruMoreRecently = 0;
- vfdP->lruLessRecently = VfdCache[0].lruLessRecently;
- VfdCache[0].lruLessRecently = file;
- VfdCache[vfdP->lruLessRecently].lruMoreRecently = file;
-
- DO_DB(_dump_lru());
+ Vfd *vfdP;
+
+ DO_DB(elog(DEBUG, "Insert %d (%s)",
+ file, VfdCache[file].fileName));
+ DO_DB(_dump_lru());
+
+ vfdP = &VfdCache[file];
+
+ vfdP->lruMoreRecently = 0;
+ vfdP->lruLessRecently = VfdCache[0].lruLessRecently;
+ VfdCache[0].lruLessRecently = file;
+ VfdCache[vfdP->lruLessRecently].lruMoreRecently = file;
+
+ DO_DB(_dump_lru());
}
static int
-LruInsert (File file)
+LruInsert(File file)
{
- Vfd *vfdP;
- int returnValue;
-
- DO_DB(elog(DEBUG, "LruInsert %d (%s)",
- file, VfdCache[file].fileName));
-
- vfdP = &VfdCache[file];
-
- if (FileIsNotOpen(file)) {
-
- if ( nfile >= pg_nofile() )
- AssertLruRoom();
-
- /*
- * Note, we check to see if there's a free file descriptor
- * before attempting to open a file. One general way to do
- * this is to try to open the null device which everybody
- * should be able to open all the time. If this fails, we
- * assume this is because there's no free file descriptors.
- */
- tryAgain:
- vfdP->fd = open(vfdP->fileName,vfdP->fileFlags,vfdP->fileMode);
- if (vfdP->fd < 0 && (errno == EMFILE || errno == ENFILE)) {
- errno = 0;
- AssertLruRoom();
- goto tryAgain;
- }
-
- if (vfdP->fd < 0) {
- DO_DB(elog(DEBUG, "RE_OPEN FAILED: %d",
- errno));
- return (vfdP->fd);
- } else {
- DO_DB(elog (DEBUG, "RE_OPEN SUCCESS"));
- ++nfile;
- }
-
- /* seek to the right position */
- if (vfdP->seekPos != 0L) {
- returnValue =
- lseek(vfdP->fd, vfdP->seekPos, SEEK_SET);
- Assert(returnValue != -1);
- }
-
- /* init state on open */
- vfdP->fdstate = 0x0;
-
- }
-
- /*
- * put it at the head of the Lru ring
- */
-
- Insert(file);
-
- return (0);
+ Vfd *vfdP;
+ int returnValue;
+
+ DO_DB(elog(DEBUG, "LruInsert %d (%s)",
+ file, VfdCache[file].fileName));
+
+ vfdP = &VfdCache[file];
+
+ if (FileIsNotOpen(file))
+ {
+
+ if (nfile >= pg_nofile())
+ AssertLruRoom();
+
+ /*
+ * Note, we check to see if there's a free file descriptor before
+ * attempting to open a file. One general way to do this is to try
+ * to open the null device which everybody should be able to open
+ * all the time. If this fails, we assume this is because there's
+ * no free file descriptors.
+ */
+tryAgain:
+ vfdP->fd = open(vfdP->fileName, vfdP->fileFlags, vfdP->fileMode);
+ if (vfdP->fd < 0 && (errno == EMFILE || errno == ENFILE))
+ {
+ errno = 0;
+ AssertLruRoom();
+ goto tryAgain;
+ }
+
+ if (vfdP->fd < 0)
+ {
+ DO_DB(elog(DEBUG, "RE_OPEN FAILED: %d",
+ errno));
+ return (vfdP->fd);
+ }
+ else
+ {
+ DO_DB(elog(DEBUG, "RE_OPEN SUCCESS"));
+ ++nfile;
+ }
+
+ /* seek to the right position */
+ if (vfdP->seekPos != 0L)
+ {
+ returnValue =
+ lseek(vfdP->fd, vfdP->seekPos, SEEK_SET);
+ Assert(returnValue != -1);
+ }
+
+ /* init state on open */
+ vfdP->fdstate = 0x0;
+
+ }
+
+ /*
+ * put it at the head of the Lru ring
+ */
+
+ Insert(file);
+
+ return (0);
}
static void
AssertLruRoom()
{
- DO_DB(elog(DEBUG, "AssertLruRoom. Opened %d", nfile));
-
- if ( nfile <= 0 )
- elog (FATAL, "AssertLruRoom: No opened files - no one can be closed");
- /*
- * There are opened files and so there should be at least one used vfd
- * in the ring.
- */
- Assert(VfdCache[0].lruMoreRecently != 0);
- LruDelete(VfdCache[0].lruMoreRecently);
+ DO_DB(elog(DEBUG, "AssertLruRoom. Opened %d", nfile));
+
+ if (nfile <= 0)
+ elog(FATAL, "AssertLruRoom: No opened files - no one can be closed");
+
+ /*
+ * There are opened files and so there should be at least one used vfd
+ * in the ring.
+ */
+ Assert(VfdCache[0].lruMoreRecently != 0);
+ LruDelete(VfdCache[0].lruMoreRecently);
}
-static File
+static File
AllocateVfd()
{
- Index i;
- File file;
-
- DO_DB(elog(DEBUG, "AllocateVfd. Size %d", SizeVfdCache));
-
- if (SizeVfdCache == 0) {
-
- /* initialize */
- VfdCache = (Vfd *)malloc(sizeof(Vfd));
- VfdCache->nextFree = 0;
- VfdCache->lruMoreRecently = 0;
- VfdCache->lruLessRecently = 0;
- VfdCache->fd = VFD_CLOSED;
- VfdCache->fdstate = 0x0;
-
- SizeVfdCache = 1;
- }
-
- if (VfdCache[0].nextFree == 0)
- {
- /*
- * The free list is empty so it is time to increase the
- * size of the array
- */
-
- VfdCache =(Vfd *)realloc(VfdCache, sizeof(Vfd)*SizeVfdCache*2);
- Assert(VfdCache != NULL);
-
- /*
- * Set up the free list for the new entries
- */
-
- for (i = SizeVfdCache; i < 2*SizeVfdCache; i++) {
- memset((char *) &(VfdCache[i]), 0, sizeof(VfdCache[0]));
- VfdCache[i].nextFree = i+1;
- VfdCache[i].fd = VFD_CLOSED;
- }
-
- /*
- * Element 0 is the first and last element of the free
- * list
- */
-
- VfdCache[0].nextFree = SizeVfdCache;
- VfdCache[2*SizeVfdCache-1].nextFree = 0;
-
- /*
- * Record the new size
- */
-
- SizeVfdCache *= 2;
- }
- file = VfdCache[0].nextFree;
-
- VfdCache[0].nextFree = VfdCache[file].nextFree;
-
- return file;
+ Index i;
+ File file;
+
+ DO_DB(elog(DEBUG, "AllocateVfd. Size %d", SizeVfdCache));
+
+ if (SizeVfdCache == 0)
+ {
+
+ /* initialize */
+ VfdCache = (Vfd *) malloc(sizeof(Vfd));
+ VfdCache->nextFree = 0;
+ VfdCache->lruMoreRecently = 0;
+ VfdCache->lruLessRecently = 0;
+ VfdCache->fd = VFD_CLOSED;
+ VfdCache->fdstate = 0x0;
+
+ SizeVfdCache = 1;
+ }
+
+ if (VfdCache[0].nextFree == 0)
+ {
+
+ /*
+ * The free list is empty so it is time to increase the size of
+ * the array
+ */
+
+ VfdCache = (Vfd *) realloc(VfdCache, sizeof(Vfd) * SizeVfdCache * 2);
+ Assert(VfdCache != NULL);
+
+ /*
+ * Set up the free list for the new entries
+ */
+
+ for (i = SizeVfdCache; i < 2 * SizeVfdCache; i++)
+ {
+ memset((char *) &(VfdCache[i]), 0, sizeof(VfdCache[0]));
+ VfdCache[i].nextFree = i + 1;
+ VfdCache[i].fd = VFD_CLOSED;
+ }
+
+ /*
+ * Element 0 is the first and last element of the free list
+ */
+
+ VfdCache[0].nextFree = SizeVfdCache;
+ VfdCache[2 * SizeVfdCache - 1].nextFree = 0;
+
+ /*
+ * Record the new size
+ */
+
+ SizeVfdCache *= 2;
+ }
+ file = VfdCache[0].nextFree;
+
+ VfdCache[0].nextFree = VfdCache[file].nextFree;
+
+ return file;
}
static void
FreeVfd(File file)
{
- DO_DB(elog(DEBUG, "FreeVfd: %d (%s)",
- file, VfdCache[file].fileName));
-
- VfdCache[file].nextFree = VfdCache[0].nextFree;
- VfdCache[0].nextFree = file;
+ DO_DB(elog(DEBUG, "FreeVfd: %d (%s)",
+ file, VfdCache[file].fileName));
+
+ VfdCache[file].nextFree = VfdCache[0].nextFree;
+ VfdCache[0].nextFree = file;
}
-static char *
+static char *
filepath(char *filename)
{
- char *buf;
- char basename[16];
- int len;
-
- if (*filename != Sep_char) {
- /* Either /base/ or \base\ */
- sprintf(basename, "%cbase%c", Sep_char, Sep_char);
-
- len = strlen(DataDir) + strlen(basename) + strlen(GetDatabaseName())
- + strlen(filename) + 2;
- buf = (char*) palloc(len);
- sprintf(buf, "%s%s%s%c%s",
- DataDir, basename, GetDatabaseName(), Sep_char, filename);
- } else {
- buf = (char *) palloc(strlen(filename) + 1);
- strcpy(buf, filename);
- }
-
- return(buf);
+ char *buf;
+ char basename[16];
+ int len;
+
+ if (*filename != Sep_char)
+ {
+ /* Either /base/ or \base\ */
+ sprintf(basename, "%cbase%c", Sep_char, Sep_char);
+
+ len = strlen(DataDir) + strlen(basename) + strlen(GetDatabaseName())
+ + strlen(filename) + 2;
+ buf = (char *) palloc(len);
+ sprintf(buf, "%s%s%s%c%s",
+ DataDir, basename, GetDatabaseName(), Sep_char, filename);
+ }
+ else
+ {
+ buf = (char *) palloc(strlen(filename) + 1);
+ strcpy(buf, filename);
+ }
+
+ return (buf);
}
static int
FileAccess(File file)
{
- int returnValue;
-
- DO_DB(elog(DEBUG, "FileAccess %d (%s)",
- file, VfdCache[file].fileName));
-
- /*
- * Is the file open? If not, close the least recently used,
- * then open it and stick it at the head of the used ring
- */
-
- if (FileIsNotOpen(file)) {
-
- returnValue = LruInsert(file);
- if (returnValue != 0)
- return returnValue;
-
- } else {
-
- /*
- * We now know that the file is open and that it is not the
- * last one accessed, so we need to more it to the head of
- * the Lru ring.
- */
-
- Delete(file);
- Insert(file);
- }
-
- return (0);
+ int returnValue;
+
+ DO_DB(elog(DEBUG, "FileAccess %d (%s)",
+ file, VfdCache[file].fileName));
+
+ /*
+ * Is the file open? If not, close the least recently used, then open
+ * it and stick it at the head of the used ring
+ */
+
+ if (FileIsNotOpen(file))
+ {
+
+ returnValue = LruInsert(file);
+ if (returnValue != 0)
+ return returnValue;
+
+ }
+ else
+ {
+
+ /*
+ * We now know that the file is open and that it is not the last
+ * one accessed, so we need to more it to the head of the Lru
+ * ring.
+ */
+
+ Delete(file);
+ Insert(file);
+ }
+
+ return (0);
}
/*
- * Called when we get a shared invalidation message on some relation.
+ * Called when we get a shared invalidation message on some relation.
*/
#ifdef NOT_USED
void
FileInvalidate(File file)
{
- Assert(file > 0);
- if (!FileIsNotOpen(file)) {
- LruDelete(file);
- }
+ Assert(file > 0);
+ if (!FileIsNotOpen(file))
+ {
+ LruDelete(file);
+ }
}
+
#endif
/* VARARGS2 */
-static File
+static File
fileNameOpenFile(FileName fileName,
- int fileFlags,
- int fileMode)
+ int fileFlags,
+ int fileMode)
{
- File file;
- Vfd *vfdP;
-
- DO_DB(elog(DEBUG, "fileNameOpenFile: %s %x %o",
- fileName, fileFlags, fileMode));
-
- file = AllocateVfd();
- vfdP = &VfdCache[file];
-
- if ( nfile >= pg_nofile() )
- AssertLruRoom();
-
- tryAgain:
- vfdP->fd = open(fileName,fileFlags,fileMode);
- if (vfdP->fd < 0 && (errno == EMFILE || errno == ENFILE)) {
- DO_DB(elog(DEBUG, "fileNameOpenFile: not enough descs, retry, er= %d",
- errno));
- errno = 0;
- AssertLruRoom();
- goto tryAgain;
- }
-
- vfdP->fdstate = 0x0;
-
- if (vfdP->fd < 0) {
- FreeVfd(file);
- return -1;
- }
- ++nfile;
- DO_DB(elog(DEBUG, "fileNameOpenFile: success %d",
- vfdP->fd));
-
- Insert(file);
-
- if (fileName==NULL) {
- elog(WARN, "fileNameOpenFile: NULL fname");
- }
- vfdP->fileName = malloc(strlen(fileName)+1);
- strcpy(vfdP->fileName,fileName);
-
- vfdP->fileFlags = fileFlags & ~(O_TRUNC|O_EXCL);
- vfdP->fileMode = fileMode;
- vfdP->seekPos = 0;
-
- return file;
+ File file;
+ Vfd *vfdP;
+
+ DO_DB(elog(DEBUG, "fileNameOpenFile: %s %x %o",
+ fileName, fileFlags, fileMode));
+
+ file = AllocateVfd();
+ vfdP = &VfdCache[file];
+
+ if (nfile >= pg_nofile())
+ AssertLruRoom();
+
+tryAgain:
+ vfdP->fd = open(fileName, fileFlags, fileMode);
+ if (vfdP->fd < 0 && (errno == EMFILE || errno == ENFILE))
+ {
+ DO_DB(elog(DEBUG, "fileNameOpenFile: not enough descs, retry, er= %d",
+ errno));
+ errno = 0;
+ AssertLruRoom();
+ goto tryAgain;
+ }
+
+ vfdP->fdstate = 0x0;
+
+ if (vfdP->fd < 0)
+ {
+ FreeVfd(file);
+ return -1;
+ }
+ ++nfile;
+ DO_DB(elog(DEBUG, "fileNameOpenFile: success %d",
+ vfdP->fd));
+
+ Insert(file);
+
+ if (fileName == NULL)
+ {
+ elog(WARN, "fileNameOpenFile: NULL fname");
+ }
+ vfdP->fileName = malloc(strlen(fileName) + 1);
+ strcpy(vfdP->fileName, fileName);
+
+ vfdP->fileFlags = fileFlags & ~(O_TRUNC | O_EXCL);
+ vfdP->fileMode = fileMode;
+ vfdP->seekPos = 0;
+
+ return file;
}
/*
@@ -573,13 +600,13 @@ fileNameOpenFile(FileName fileName,
File
FileNameOpenFile(FileName fileName, int fileFlags, int fileMode)
{
- File fd;
- char *fname;
-
- fname = filepath(fileName);
- fd = fileNameOpenFile(fname, fileFlags, fileMode);
- pfree(fname);
- return(fd);
+ File fd;
+ char *fname;
+
+ fname = filepath(fileName);
+ fd = fileNameOpenFile(fname, fileFlags, fileMode);
+ pfree(fname);
+ return (fd);
}
/*
@@ -588,150 +615,162 @@ FileNameOpenFile(FileName fileName, int fileFlags, int fileMode)
File
PathNameOpenFile(FileName fileName, int fileFlags, int fileMode)
{
- return(fileNameOpenFile(fileName, fileFlags, fileMode));
+ return (fileNameOpenFile(fileName, fileFlags, fileMode));
}
void
FileClose(File file)
{
- int returnValue;
-
- DO_DB(elog(DEBUG, "FileClose: %d (%s)",
- file, VfdCache[file].fileName));
-
- if (!FileIsNotOpen(file)) {
-
- /* remove the file from the lru ring */
- Delete(file);
-
- /* if we did any writes, sync the file before closing */
- if (VfdCache[file].fdstate & FD_DIRTY) {
- returnValue = fsync(VfdCache[file].fd);
- Assert(returnValue != -1);
- VfdCache[file].fdstate &= ~FD_DIRTY;
- }
-
- /* close the file */
- returnValue = close(VfdCache[file].fd);
- Assert(returnValue != -1);
-
- --nfile;
- VfdCache[file].fd = VFD_CLOSED;
- }
- /*
- * Add the Vfd slot to the free list
- */
- FreeVfd(file);
- /*
- * Free the filename string
- */
- free(VfdCache[file].fileName);
+ int returnValue;
+
+ DO_DB(elog(DEBUG, "FileClose: %d (%s)",
+ file, VfdCache[file].fileName));
+
+ if (!FileIsNotOpen(file))
+ {
+
+ /* remove the file from the lru ring */
+ Delete(file);
+
+ /* if we did any writes, sync the file before closing */
+ if (VfdCache[file].fdstate & FD_DIRTY)
+ {
+ returnValue = fsync(VfdCache[file].fd);
+ Assert(returnValue != -1);
+ VfdCache[file].fdstate &= ~FD_DIRTY;
+ }
+
+ /* close the file */
+ returnValue = close(VfdCache[file].fd);
+ Assert(returnValue != -1);
+
+ --nfile;
+ VfdCache[file].fd = VFD_CLOSED;
+ }
+
+ /*
+ * Add the Vfd slot to the free list
+ */
+ FreeVfd(file);
+
+ /*
+ * Free the filename string
+ */
+ free(VfdCache[file].fileName);
}
void
FileUnlink(File file)
{
- int returnValue;
-
- DO_DB(elog(DEBUG, "FileUnlink: %d (%s)",
- file, VfdCache[file].fileName));
-
- if (!FileIsNotOpen(file)) {
-
- /* remove the file from the lru ring */
- Delete(file);
-
- /* if we did any writes, sync the file before closing */
- if (VfdCache[file].fdstate & FD_DIRTY) {
- returnValue = fsync(VfdCache[file].fd);
- Assert(returnValue != -1);
- VfdCache[file].fdstate &= ~FD_DIRTY;
- }
-
- /* close the file */
- returnValue = close(VfdCache[file].fd);
- Assert(returnValue != -1);
-
- --nfile;
- VfdCache[file].fd = VFD_CLOSED;
- }
- /* add the Vfd slot to the free list */
- FreeVfd(file);
-
- /* free the filename string */
- unlink(VfdCache[file].fileName);
- free(VfdCache[file].fileName);
+ int returnValue;
+
+ DO_DB(elog(DEBUG, "FileUnlink: %d (%s)",
+ file, VfdCache[file].fileName));
+
+ if (!FileIsNotOpen(file))
+ {
+
+ /* remove the file from the lru ring */
+ Delete(file);
+
+ /* if we did any writes, sync the file before closing */
+ if (VfdCache[file].fdstate & FD_DIRTY)
+ {
+ returnValue = fsync(VfdCache[file].fd);
+ Assert(returnValue != -1);
+ VfdCache[file].fdstate &= ~FD_DIRTY;
+ }
+
+ /* close the file */
+ returnValue = close(VfdCache[file].fd);
+ Assert(returnValue != -1);
+
+ --nfile;
+ VfdCache[file].fd = VFD_CLOSED;
+ }
+ /* add the Vfd slot to the free list */
+ FreeVfd(file);
+
+ /* free the filename string */
+ unlink(VfdCache[file].fileName);
+ free(VfdCache[file].fileName);
}
int
FileRead(File file, char *buffer, int amount)
{
- int returnCode;
-
- DO_DB(elog(DEBUG, "FileRead: %d (%s) %d %p",
- file, VfdCache[file].fileName, amount, buffer));
-
- FileAccess(file);
- returnCode = read(VfdCache[file].fd, buffer, amount);
- if (returnCode > 0) {
- VfdCache[file].seekPos += returnCode;
- }
-
- return returnCode;
+ int returnCode;
+
+ DO_DB(elog(DEBUG, "FileRead: %d (%s) %d %p",
+ file, VfdCache[file].fileName, amount, buffer));
+
+ FileAccess(file);
+ returnCode = read(VfdCache[file].fd, buffer, amount);
+ if (returnCode > 0)
+ {
+ VfdCache[file].seekPos += returnCode;
+ }
+
+ return returnCode;
}
int
FileWrite(File file, char *buffer, int amount)
{
- int returnCode;
-
- DO_DB(elog(DEBUG, "FileWrite: %d (%s) %d %p",
- file, VfdCache[file].fileName, amount, buffer));
-
- FileAccess(file);
- returnCode = write(VfdCache[file].fd, buffer, amount);
- if (returnCode > 0) { /* changed by Boris with Mao's advice */
- VfdCache[file].seekPos += returnCode;
- }
-
- /* record the write */
- VfdCache[file].fdstate |= FD_DIRTY;
-
- return returnCode;
+ int returnCode;
+
+ DO_DB(elog(DEBUG, "FileWrite: %d (%s) %d %p",
+ file, VfdCache[file].fileName, amount, buffer));
+
+ FileAccess(file);
+ returnCode = write(VfdCache[file].fd, buffer, amount);
+ if (returnCode > 0)
+ { /* changed by Boris with Mao's advice */
+ VfdCache[file].seekPos += returnCode;
+ }
+
+ /* record the write */
+ VfdCache[file].fdstate |= FD_DIRTY;
+
+ return returnCode;
}
long
FileSeek(File file, long offset, int whence)
{
- int returnCode;
-
- DO_DB(elog (DEBUG, "FileSeek: %d (%s) %ld %d",
- file, VfdCache[file].fileName, offset, whence));
-
- if (FileIsNotOpen(file)) {
- switch(whence) {
- case SEEK_SET:
- VfdCache[file].seekPos = offset;
- return offset;
- case SEEK_CUR:
- VfdCache[file].seekPos = VfdCache[file].seekPos +offset;
- return VfdCache[file].seekPos;
- case SEEK_END:
- FileAccess(file);
- returnCode = VfdCache[file].seekPos =
- lseek(VfdCache[file].fd, offset, whence);
- return returnCode;
- default:
- elog(WARN, "FileSeek: invalid whence: %d", whence);
- break;
- }
- } else {
- returnCode = VfdCache[file].seekPos =
- lseek(VfdCache[file].fd, offset, whence);
- return returnCode;
- }
- /*NOTREACHED*/
- return(-1L);
+ int returnCode;
+
+ DO_DB(elog(DEBUG, "FileSeek: %d (%s) %ld %d",
+ file, VfdCache[file].fileName, offset, whence));
+
+ if (FileIsNotOpen(file))
+ {
+ switch (whence)
+ {
+ case SEEK_SET:
+ VfdCache[file].seekPos = offset;
+ return offset;
+ case SEEK_CUR:
+ VfdCache[file].seekPos = VfdCache[file].seekPos + offset;
+ return VfdCache[file].seekPos;
+ case SEEK_END:
+ FileAccess(file);
+ returnCode = VfdCache[file].seekPos =
+ lseek(VfdCache[file].fd, offset, whence);
+ return returnCode;
+ default:
+ elog(WARN, "FileSeek: invalid whence: %d", whence);
+ break;
+ }
+ }
+ else
+ {
+ returnCode = VfdCache[file].seekPos =
+ lseek(VfdCache[file].fd, offset, whence);
+ return returnCode;
+ }
+ /* NOTREACHED */
+ return (-1L);
}
/*
@@ -741,58 +780,61 @@ FileSeek(File file, long offset, int whence)
long
FileTell(File file)
{
- DO_DB(elog(DEBUG, "FileTell %d (%s)",
- file, VfdCache[file].fileName));
- return VfdCache[file].seekPos;
+ DO_DB(elog(DEBUG, "FileTell %d (%s)",
+ file, VfdCache[file].fileName));
+ return VfdCache[file].seekPos;
}
+
#endif
int
FileTruncate(File file, int offset)
{
- int returnCode;
-
- DO_DB(elog(DEBUG, "FileTruncate %d (%s)",
- file, VfdCache[file].fileName));
-
- FileSync(file);
- FileAccess(file);
- returnCode = ftruncate(VfdCache[file].fd, offset);
- return(returnCode);
+ int returnCode;
+
+ DO_DB(elog(DEBUG, "FileTruncate %d (%s)",
+ file, VfdCache[file].fileName));
+
+ FileSync(file);
+ FileAccess(file);
+ returnCode = ftruncate(VfdCache[file].fd, offset);
+ return (returnCode);
}
int
FileSync(File file)
{
- int returnCode;
-
- /*
- * If the file isn't open, then we don't need to sync it; we
- * always sync files when we close them. Also, if we haven't
- * done any writes that we haven't already synced, we can ignore
- * the request.
- */
-
- if (VfdCache[file].fd < 0 || !(VfdCache[file].fdstate & FD_DIRTY)) {
- returnCode = 0;
- } else {
- returnCode = fsync(VfdCache[file].fd);
- VfdCache[file].fdstate &= ~FD_DIRTY;
- }
-
- return returnCode;
+ int returnCode;
+
+ /*
+ * If the file isn't open, then we don't need to sync it; we always
+ * sync files when we close them. Also, if we haven't done any writes
+ * that we haven't already synced, we can ignore the request.
+ */
+
+ if (VfdCache[file].fd < 0 || !(VfdCache[file].fdstate & FD_DIRTY))
+ {
+ returnCode = 0;
+ }
+ else
+ {
+ returnCode = fsync(VfdCache[file].fd);
+ VfdCache[file].fdstate &= ~FD_DIRTY;
+ }
+
+ return returnCode;
}
int
FileNameUnlink(char *filename)
{
- int retval;
- char *fname;
+ int retval;
+ char *fname;
- fname = filepath(filename);
- retval = unlink(fname);
- pfree(fname);
- return(retval);
+ fname = filepath(filename);
+ retval = unlink(fname);
+ pfree(fname);
+ return (retval);
}
/*
@@ -804,33 +846,36 @@ FileNameUnlink(char *filename)
* allocatedFiles keeps track of how many have been allocated so we
* can give a warning if there are too few left.
*/
-static int allocatedFiles = 0;
+static int allocatedFiles = 0;
-FILE *
+FILE *
AllocateFile(char *name, char *mode)
{
- FILE *file;
- int fdleft;
-
- DO_DB(elog(DEBUG, "AllocateFile: Allocated %d.", allocatedFiles));
+ FILE *file;
+ int fdleft;
+
+ DO_DB(elog(DEBUG, "AllocateFile: Allocated %d.", allocatedFiles));
TryAgain:
- if ((file = fopen(name, mode)) == NULL) {
- if (errno == EMFILE || errno == ENFILE) {
- DO_DB(elog(DEBUG, "AllocateFile: not enough descs, retry, er= %d",
- errno));
- errno = 0;
- AssertLruRoom();
- goto TryAgain;
- }
- }
- else {
- ++allocatedFiles;
- fdleft = pg_nofile() - allocatedFiles;
- if (fdleft < 6)
- elog(NOTICE,"warning: few usable file descriptors left (%d)", fdleft);
- }
- return file;
+ if ((file = fopen(name, mode)) == NULL)
+ {
+ if (errno == EMFILE || errno == ENFILE)
+ {
+ DO_DB(elog(DEBUG, "AllocateFile: not enough descs, retry, er= %d",
+ errno));
+ errno = 0;
+ AssertLruRoom();
+ goto TryAgain;
+ }
+ }
+ else
+ {
+ ++allocatedFiles;
+ fdleft = pg_nofile() - allocatedFiles;
+ if (fdleft < 6)
+ elog(NOTICE, "warning: few usable file descriptors left (%d)", fdleft);
+ }
+ return file;
}
/*
@@ -838,22 +883,24 @@ TryAgain:
* AllocateFile()?
*/
void
-FreeFile(FILE *file)
+FreeFile(FILE * file)
{
- DO_DB(elog(DEBUG, "FreeFile: Allocated %d.", allocatedFiles));
+ DO_DB(elog(DEBUG, "FreeFile: Allocated %d.", allocatedFiles));
- Assert(allocatedFiles > 0);
- fclose(file);
- --allocatedFiles;
+ Assert(allocatedFiles > 0);
+ fclose(file);
+ --allocatedFiles;
}
void
closeAllVfds()
{
- int i;
- Assert (FileIsNotOpen(0)); /* Make sure ring not corrupted */
- for (i=1; i<SizeVfdCache; i++) {
- if (!FileIsNotOpen(i))
- LruDelete(i);
- }
+ int i;
+
+ Assert(FileIsNotOpen(0)); /* Make sure ring not corrupted */
+ for (i = 1; i < SizeVfdCache; i++)
+ {
+ if (!FileIsNotOpen(i))
+ LruDelete(i);
+ }
}
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
index a5573e89151..3dd6d2ec094 100644
--- a/src/backend/storage/ipc/ipc.c
+++ b/src/backend/storage/ipc/ipc.c
@@ -1,26 +1,26 @@
/*-------------------------------------------------------------------------
*
* ipc.c--
- * POSTGRES inter-process communication definitions.
+ * POSTGRES inter-process communication definitions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.11 1997/08/19 21:32:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipc.c,v 1.12 1997/09/07 04:48:30 momjian Exp $
*
* NOTES
*
- * Currently, semaphores are used (my understanding anyway) in two
- * different ways:
- * 1. as mutexes on machines that don't have test-and-set (eg.
- * mips R3000).
- * 2. for putting processes to sleep when waiting on a lock
- * and waking them up when the lock is free.
- * The number of semaphores in (1) is fixed and those are shared
- * among all backends. In (2), there is 1 semaphore per process and those
- * are not shared with anyone else.
- * -ay 4/95
+ * Currently, semaphores are used (my understanding anyway) in two
+ * different ways:
+ * 1. as mutexes on machines that don't have test-and-set (eg.
+ * mips R3000).
+ * 2. for putting processes to sleep when waiting on a lock
+ * and waking them up when the lock is free.
+ * The number of semaphores in (1) is fixed and those are shared
+ * among all backends. In (2), there is 1 semaphore per process and those
+ * are not shared with anyone else.
+ * -ay 4/95
*
*-------------------------------------------------------------------------
*/
@@ -44,94 +44,98 @@
#endif
#if defined(bsd44)
-int UsePrivateMemory = 1;
+int UsePrivateMemory = 1;
+
#else
-int UsePrivateMemory = 0;
+int UsePrivateMemory = 0;
+
#endif
-static void IpcMemoryDetach(int status, char *shmaddr);
+static void IpcMemoryDetach(int status, char *shmaddr);
/* ----------------------------------------------------------------
- * exit() handling stuff
+ * exit() handling stuff
* ----------------------------------------------------------------
*/
#define MAX_ON_EXITS 20
-static struct ONEXIT {
- void (*function)();
- caddr_t arg;
-} onexit_list[ MAX_ON_EXITS ];
+static struct ONEXIT
+{
+ void (*function) ();
+ caddr_t arg;
+} onexit_list[MAX_ON_EXITS];
-static int onexit_index;
-static void IpcConfigTip(void);
+static int onexit_index;
+static void IpcConfigTip(void);
-typedef struct _PrivateMemStruct {
- int id;
- char *memptr;
-} PrivateMem;
+typedef struct _PrivateMemStruct
+{
+ int id;
+ char *memptr;
+} PrivateMem;
-PrivateMem IpcPrivateMem[16];
+PrivateMem IpcPrivateMem[16];
static int
PrivateMemoryCreate(IpcMemoryKey memKey,
- uint32 size)
+ uint32 size)
{
- static int memid = 0;
-
- UsePrivateMemory = 1;
-
- IpcPrivateMem[memid].id = memid;
- IpcPrivateMem[memid].memptr = malloc(size);
- if (IpcPrivateMem[memid].memptr == NULL)
- elog(WARN, "PrivateMemoryCreate: not enough memory to malloc");
- memset(IpcPrivateMem[memid].memptr, 0, size); /* XXX PURIFY */
-
- return (memid++);
+ static int memid = 0;
+
+ UsePrivateMemory = 1;
+
+ IpcPrivateMem[memid].id = memid;
+ IpcPrivateMem[memid].memptr = malloc(size);
+ if (IpcPrivateMem[memid].memptr == NULL)
+ elog(WARN, "PrivateMemoryCreate: not enough memory to malloc");
+ memset(IpcPrivateMem[memid].memptr, 0, size); /* XXX PURIFY */
+
+ return (memid++);
}
-static char *
+static char *
PrivateMemoryAttach(IpcMemoryId memid)
{
- return ( IpcPrivateMem[memid].memptr );
+ return (IpcPrivateMem[memid].memptr);
}
/* ----------------------------------------------------------------
- * exitpg
+ * exitpg
*
- * this function calls all the callbacks registered
- * for it (to free resources) and then calls exit.
- * This should be the only function to call exit().
- * -cim 2/6/90
+ * this function calls all the callbacks registered
+ * for it (to free resources) and then calls exit.
+ * This should be the only function to call exit().
+ * -cim 2/6/90
* ----------------------------------------------------------------
*/
-static int exitpg_inprogress = 0;
+static int exitpg_inprogress = 0;
void
exitpg(int code)
{
- int i;
-
- /* ----------------
- * if exitpg_inprocess is true, then it means that we
- * are being invoked from within an on_exit() handler
- * and so we return immediately to avoid recursion.
- * ----------------
- */
- if (exitpg_inprogress)
- return;
-
- exitpg_inprogress = 1;
-
- /* ----------------
- * call all the callbacks registered before calling exit().
- * ----------------
- */
- for (i = onexit_index - 1; i >= 0; --i)
- (*onexit_list[i].function)(code, onexit_list[i].arg);
-
- exit(code);
+ int i;
+
+ /* ----------------
+ * if exitpg_inprocess is true, then it means that we
+ * are being invoked from within an on_exit() handler
+ * and so we return immediately to avoid recursion.
+ * ----------------
+ */
+ if (exitpg_inprogress)
+ return;
+
+ exitpg_inprogress = 1;
+
+ /* ----------------
+ * call all the callbacks registered before calling exit().
+ * ----------------
+ */
+ for (i = onexit_index - 1; i >= 0; --i)
+ (*onexit_list[i].function) (code, onexit_list[i].arg);
+
+ exit(code);
}
/* ------------------
@@ -143,591 +147,628 @@ exitpg(int code)
void
quasi_exitpg()
{
- int i;
-
- /* ----------------
- * if exitpg_inprocess is true, then it means that we
- * are being invoked from within an on_exit() handler
- * and so we return immediately to avoid recursion.
- * ----------------
- */
- if (exitpg_inprogress)
- return;
-
- exitpg_inprogress = 1;
-
- /* ----------------
- * call all the callbacks registered before calling exit().
- * ----------------
- */
- for (i = onexit_index - 1; i >= 0; --i)
- (*onexit_list[i].function)(0, onexit_list[i].arg);
-
- onexit_index = 0;
- exitpg_inprogress = 0;
+ int i;
+
+ /* ----------------
+ * if exitpg_inprocess is true, then it means that we
+ * are being invoked from within an on_exit() handler
+ * and so we return immediately to avoid recursion.
+ * ----------------
+ */
+ if (exitpg_inprogress)
+ return;
+
+ exitpg_inprogress = 1;
+
+ /* ----------------
+ * call all the callbacks registered before calling exit().
+ * ----------------
+ */
+ for (i = onexit_index - 1; i >= 0; --i)
+ (*onexit_list[i].function) (0, onexit_list[i].arg);
+
+ onexit_index = 0;
+ exitpg_inprogress = 0;
}
/* ----------------------------------------------------------------
- * on_exitpg
+ * on_exitpg
*
- * this function adds a callback function to the list of
- * functions invoked by exitpg(). -cim 2/6/90
+ * this function adds a callback function to the list of
+ * functions invoked by exitpg(). -cim 2/6/90
* ----------------------------------------------------------------
*/
int
-on_exitpg(void (*function)(), caddr_t arg)
+ on_exitpg(void (*function) (), caddr_t arg)
{
- if (onexit_index >= MAX_ON_EXITS)
- return(-1);
-
- onexit_list[ onexit_index ].function = function;
- onexit_list[ onexit_index ].arg = arg;
-
- ++onexit_index;
-
- return(0);
+ if (onexit_index >= MAX_ON_EXITS)
+ return (-1);
+
+ onexit_list[onexit_index].function = function;
+ onexit_list[onexit_index].arg = arg;
+
+ ++onexit_index;
+
+ return (0);
}
/****************************************************************************/
-/* IPCPrivateSemaphoreKill(status, semId) */
-/* */
+/* IPCPrivateSemaphoreKill(status, semId) */
+/* */
/****************************************************************************/
static void
IPCPrivateSemaphoreKill(int status,
- int semId) /* caddr_t */
+ int semId) /* caddr_t */
{
- union semun semun;
- semctl(semId, 0, IPC_RMID, semun);
+ union semun semun;
+
+ semctl(semId, 0, IPC_RMID, semun);
}
/****************************************************************************/
-/* IPCPrivateMemoryKill(status, shmId) */
-/* */
+/* IPCPrivateMemoryKill(status, shmId) */
+/* */
/****************************************************************************/
static void
IPCPrivateMemoryKill(int status,
- int shmId) /* caddr_t */
+ int shmId) /* caddr_t */
{
- if ( UsePrivateMemory ) {
- /* free ( IpcPrivateMem[shmId].memptr ); */
- } else {
- if (shmctl(shmId, IPC_RMID, (struct shmid_ds *) NULL) < 0) {
- elog(NOTICE, "IPCPrivateMemoryKill: shmctl(%d, %d, 0) failed: %m",
- shmId, IPC_RMID);
+ if (UsePrivateMemory)
+ {
+ /* free ( IpcPrivateMem[shmId].memptr ); */
+ }
+ else
+ {
+ if (shmctl(shmId, IPC_RMID, (struct shmid_ds *) NULL) < 0)
+ {
+ elog(NOTICE, "IPCPrivateMemoryKill: shmctl(%d, %d, 0) failed: %m",
+ shmId, IPC_RMID);
+ }
}
- }
}
/****************************************************************************/
-/* IpcSemaphoreCreate(semKey, semNum, permission, semStartValue) */
-/* */
-/* - returns a semaphore identifier: */
-/* */
+/* IpcSemaphoreCreate(semKey, semNum, permission, semStartValue) */
+/* */
+/* - returns a semaphore identifier: */
+/* */
/* if key doesn't exist: return a new id, status:= IpcSemIdNotExist */
-/* if key exists: return the old id, status:= IpcSemIdExist */
-/* if semNum > MAX : return # of argument, status:=IpcInvalidArgument */
-/* */
+/* if key exists: return the old id, status:= IpcSemIdExist */
+/* if semNum > MAX : return # of argument, status:=IpcInvalidArgument */
+/* */
/****************************************************************************/
/*
* Note:
- * XXX This should be split into two different calls. One should
- * XXX be used to create a semaphore set. The other to "attach" a
+ * XXX This should be split into two different calls. One should
+ * XXX be used to create a semaphore set. The other to "attach" a
* XXX existing set. It should be an error for the semaphore set
* XXX to to already exist or for it not to, respectively.
*
- * Currently, the semaphore sets are "attached" and an error
- * is detected only when a later shared memory attach fails.
+ * Currently, the semaphore sets are "attached" and an error
+ * is detected only when a later shared memory attach fails.
*/
IpcSemaphoreId
IpcSemaphoreCreate(IpcSemaphoreKey semKey,
- int semNum,
- int permission,
- int semStartValue,
- int removeOnExit,
- int *status)
+ int semNum,
+ int permission,
+ int semStartValue,
+ int removeOnExit,
+ int *status)
{
- int i;
- int errStatus;
- int semId;
- u_short array[IPC_NMAXSEM];
- union semun semun;
-
- /* get a semaphore if non-existent */
- /* check arguments */
- if (semNum > IPC_NMAXSEM || semNum <= 0) {
- *status = IpcInvalidArgument;
- return(2); /* returns the number of the invalid argument */
- }
-
- semId = semget(semKey, 0, 0);
-
- if (semId == -1) {
- *status = IpcSemIdNotExist; /* there doesn't exist a semaphore */
+ int i;
+ int errStatus;
+ int semId;
+ u_short array[IPC_NMAXSEM];
+ union semun semun;
+
+ /* get a semaphore if non-existent */
+ /* check arguments */
+ if (semNum > IPC_NMAXSEM || semNum <= 0)
+ {
+ *status = IpcInvalidArgument;
+ return (2); /* returns the number of the invalid
+ * argument */
+ }
+
+ semId = semget(semKey, 0, 0);
+
+ if (semId == -1)
+ {
+ *status = IpcSemIdNotExist; /* there doesn't exist a semaphore */
#ifdef DEBUG_IPC
- fprintf(stderr,"calling semget with %d, %d , %d\n",
- semKey,
- semNum,
- IPC_CREAT|permission );
+ fprintf(stderr, "calling semget with %d, %d , %d\n",
+ semKey,
+ semNum,
+ IPC_CREAT | permission);
#endif
- semId = semget(semKey, semNum, IPC_CREAT|permission);
+ semId = semget(semKey, semNum, IPC_CREAT | permission);
+
+ if (semId < 0)
+ {
+ perror("semget");
+ IpcConfigTip();
+ exitpg(3);
+ }
+ for (i = 0; i < semNum; i++)
+ {
+ array[i] = semStartValue;
+ }
+ semun.array = array;
+ errStatus = semctl(semId, 0, SETALL, semun);
+ if (errStatus == -1)
+ {
+ perror("semctl");
+ IpcConfigTip();
+ }
+
+ if (removeOnExit)
+ on_exitpg(IPCPrivateSemaphoreKill, (caddr_t) semId);
- if (semId < 0) {
- perror("semget");
- IpcConfigTip();
- exitpg(3);
- }
- for (i = 0; i < semNum; i++) {
- array[i] = semStartValue;
}
- semun.array = array;
- errStatus = semctl(semId, 0, SETALL, semun);
- if (errStatus == -1) {
- perror("semctl");
- IpcConfigTip();
+ else
+ {
+ /* there is a semaphore id for this key */
+ *status = IpcSemIdExist;
}
-
- if (removeOnExit)
- on_exitpg(IPCPrivateSemaphoreKill, (caddr_t)semId);
-
- } else {
- /* there is a semaphore id for this key */
- *status = IpcSemIdExist;
- }
-
+
#ifdef DEBUG_IPC
- fprintf(stderr,"\nIpcSemaphoreCreate, status %d, returns %d\n",
- *status,
- semId );
- fflush(stdout);
- fflush(stderr);
+ fprintf(stderr, "\nIpcSemaphoreCreate, status %d, returns %d\n",
+ *status,
+ semId);
+ fflush(stdout);
+ fflush(stderr);
#endif
- return(semId);
+ return (semId);
}
/****************************************************************************/
-/* IpcSemaphoreSet() - sets the initial value of the semaphore */
-/* */
-/* note: the xxx_return variables are only used for debugging. */
+/* IpcSemaphoreSet() - sets the initial value of the semaphore */
+/* */
+/* note: the xxx_return variables are only used for debugging. */
/****************************************************************************/
#ifdef NOT_USED
-static int IpcSemaphoreSet_return;
+static int IpcSemaphoreSet_return;
void
IpcSemaphoreSet(int semId, int semno, int value)
{
- int errStatus;
- union semun semun;
-
- semun.val = value;
- errStatus = semctl(semId, semno, SETVAL, semun);
- IpcSemaphoreSet_return = errStatus;
-
- if (errStatus == -1)
- {
- perror("semctl");
- IpcConfigTip();
- }
+ int errStatus;
+ union semun semun;
+
+ semun.val = value;
+ errStatus = semctl(semId, semno, SETVAL, semun);
+ IpcSemaphoreSet_return = errStatus;
+
+ if (errStatus == -1)
+ {
+ perror("semctl");
+ IpcConfigTip();
+ }
}
+
#endif
/****************************************************************************/
-/* IpcSemaphoreKill(key) - removes a semaphore */
-/* */
+/* IpcSemaphoreKill(key) - removes a semaphore */
+/* */
/****************************************************************************/
void
IpcSemaphoreKill(IpcSemaphoreKey key)
{
- int semId;
- union semun semun;
-
- /* kill semaphore if existent */
-
- semId = semget(key, 0, 0);
- if (semId != -1)
- semctl(semId, 0, IPC_RMID, semun);
+ int semId;
+ union semun semun;
+
+ /* kill semaphore if existent */
+
+ semId = semget(key, 0, 0);
+ if (semId != -1)
+ semctl(semId, 0, IPC_RMID, semun);
}
/****************************************************************************/
-/* IpcSemaphoreLock(semId, sem, lock) - locks a semaphore */
-/* */
-/* note: the xxx_return variables are only used for debugging. */
+/* IpcSemaphoreLock(semId, sem, lock) - locks a semaphore */
+/* */
+/* note: the xxx_return variables are only used for debugging. */
/****************************************************************************/
-static int IpcSemaphoreLock_return;
+static int IpcSemaphoreLock_return;
void
IpcSemaphoreLock(IpcSemaphoreId semId, int sem, int lock)
{
- extern int errno;
- int errStatus;
- struct sembuf sops;
-
- sops.sem_op = lock;
- sops.sem_flg = 0;
- sops.sem_num = sem;
-
- /* ----------------
- * Note: if errStatus is -1 and errno == EINTR then it means we
- * returned from the operation prematurely because we were
- * sent a signal. So we try and lock the semaphore again.
- * I am not certain this is correct, but the semantics aren't
- * clear it fixes problems with parallel abort synchronization,
- * namely that after processing an abort signal, the semaphore
- * call returns with -1 (and errno == EINTR) before it should.
- * -cim 3/28/90
- * ----------------
- */
- do {
- errStatus = semop(semId, &sops, 1);
- } while (errStatus == -1 && errno == EINTR);
-
- IpcSemaphoreLock_return = errStatus;
-
- if (errStatus == -1) {
- perror("semop");
- IpcConfigTip();
- exitpg(255);
- }
+ extern int errno;
+ int errStatus;
+ struct sembuf sops;
+
+ sops.sem_op = lock;
+ sops.sem_flg = 0;
+ sops.sem_num = sem;
+
+ /* ----------------
+ * Note: if errStatus is -1 and errno == EINTR then it means we
+ * returned from the operation prematurely because we were
+ * sent a signal. So we try and lock the semaphore again.
+ * I am not certain this is correct, but the semantics aren't
+ * clear it fixes problems with parallel abort synchronization,
+ * namely that after processing an abort signal, the semaphore
+ * call returns with -1 (and errno == EINTR) before it should.
+ * -cim 3/28/90
+ * ----------------
+ */
+ do
+ {
+ errStatus = semop(semId, &sops, 1);
+ } while (errStatus == -1 && errno == EINTR);
+
+ IpcSemaphoreLock_return = errStatus;
+
+ if (errStatus == -1)
+ {
+ perror("semop");
+ IpcConfigTip();
+ exitpg(255);
+ }
}
/****************************************************************************/
-/* IpcSemaphoreUnlock(semId, sem, lock) - unlocks a semaphore */
-/* */
-/* note: the xxx_return variables are only used for debugging. */
+/* IpcSemaphoreUnlock(semId, sem, lock) - unlocks a semaphore */
+/* */
+/* note: the xxx_return variables are only used for debugging. */
/****************************************************************************/
-static int IpcSemaphoreUnlock_return;
+static int IpcSemaphoreUnlock_return;
void
IpcSemaphoreUnlock(IpcSemaphoreId semId, int sem, int lock)
{
- extern int errno;
- int errStatus;
- struct sembuf sops;
-
- sops.sem_op = -lock;
- sops.sem_flg = 0;
- sops.sem_num = sem;
-
-
- /* ----------------
- * Note: if errStatus is -1 and errno == EINTR then it means we
- * returned from the operation prematurely because we were
- * sent a signal. So we try and lock the semaphore again.
- * I am not certain this is correct, but the semantics aren't
- * clear it fixes problems with parallel abort synchronization,
- * namely that after processing an abort signal, the semaphore
- * call returns with -1 (and errno == EINTR) before it should.
- * -cim 3/28/90
- * ----------------
- */
- do {
- errStatus = semop(semId, &sops, 1);
- } while (errStatus == -1 && errno == EINTR);
-
- IpcSemaphoreUnlock_return = errStatus;
-
- if (errStatus == -1) {
- perror("semop");
- IpcConfigTip();
- exitpg(255);
- }
+ extern int errno;
+ int errStatus;
+ struct sembuf sops;
+
+ sops.sem_op = -lock;
+ sops.sem_flg = 0;
+ sops.sem_num = sem;
+
+
+ /* ----------------
+ * Note: if errStatus is -1 and errno == EINTR then it means we
+ * returned from the operation prematurely because we were
+ * sent a signal. So we try and lock the semaphore again.
+ * I am not certain this is correct, but the semantics aren't
+ * clear it fixes problems with parallel abort synchronization,
+ * namely that after processing an abort signal, the semaphore
+ * call returns with -1 (and errno == EINTR) before it should.
+ * -cim 3/28/90
+ * ----------------
+ */
+ do
+ {
+ errStatus = semop(semId, &sops, 1);
+ } while (errStatus == -1 && errno == EINTR);
+
+ IpcSemaphoreUnlock_return = errStatus;
+
+ if (errStatus == -1)
+ {
+ perror("semop");
+ IpcConfigTip();
+ exitpg(255);
+ }
}
int
-IpcSemaphoreGetCount(IpcSemaphoreId semId, int sem)
+IpcSemaphoreGetCount(IpcSemaphoreId semId, int sem)
{
- int semncnt;
- union semun dummy; /* for Solaris */
-
- semncnt = semctl(semId, sem, GETNCNT, dummy);
- return semncnt;
+ int semncnt;
+ union semun dummy; /* for Solaris */
+
+ semncnt = semctl(semId, sem, GETNCNT, dummy);
+ return semncnt;
}
int
-IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem)
+IpcSemaphoreGetValue(IpcSemaphoreId semId, int sem)
{
- int semval;
- union semun dummy; /* for Solaris */
-
- semval = semctl(semId, sem, GETVAL, dummy);
- return semval;
+ int semval;
+ union semun dummy; /* for Solaris */
+
+ semval = semctl(semId, sem, GETVAL, dummy);
+ return semval;
}
/****************************************************************************/
-/* IpcMemoryCreate(memKey) */
-/* */
-/* - returns the memory identifier, if creation succeeds */
-/* returns IpcMemCreationFailed, if failure */
+/* IpcMemoryCreate(memKey) */
+/* */
+/* - returns the memory identifier, if creation succeeds */
+/* returns IpcMemCreationFailed, if failure */
/****************************************************************************/
IpcMemoryId
IpcMemoryCreate(IpcMemoryKey memKey, uint32 size, int permission)
{
- IpcMemoryId shmid;
-
- if (memKey == PrivateIPCKey) {
- /* private */
- shmid = PrivateMemoryCreate(memKey, size);
- }else {
- shmid = shmget(memKey, size, IPC_CREAT|permission);
- }
-
- if (shmid < 0) {
- fprintf(stderr,"IpcMemoryCreate: memKey=%d , size=%d , permission=%d",
- memKey, size , permission );
- perror("IpcMemoryCreate: shmget(..., create, ...) failed");
- IpcConfigTip();
- return(IpcMemCreationFailed);
- }
-
- /* if (memKey == PrivateIPCKey) */
- on_exitpg(IPCPrivateMemoryKill, (caddr_t)shmid);
-
- return(shmid);
+ IpcMemoryId shmid;
+
+ if (memKey == PrivateIPCKey)
+ {
+ /* private */
+ shmid = PrivateMemoryCreate(memKey, size);
+ }
+ else
+ {
+ shmid = shmget(memKey, size, IPC_CREAT | permission);
+ }
+
+ if (shmid < 0)
+ {
+ fprintf(stderr, "IpcMemoryCreate: memKey=%d , size=%d , permission=%d",
+ memKey, size, permission);
+ perror("IpcMemoryCreate: shmget(..., create, ...) failed");
+ IpcConfigTip();
+ return (IpcMemCreationFailed);
+ }
+
+ /* if (memKey == PrivateIPCKey) */
+ on_exitpg(IPCPrivateMemoryKill, (caddr_t) shmid);
+
+ return (shmid);
}
/****************************************************************************/
-/* IpcMemoryIdGet(memKey, size) returns the shared memory Id */
-/* or IpcMemIdGetFailed */
+/* IpcMemoryIdGet(memKey, size) returns the shared memory Id */
+/* or IpcMemIdGetFailed */
/****************************************************************************/
IpcMemoryId
IpcMemoryIdGet(IpcMemoryKey memKey, uint32 size)
{
- IpcMemoryId shmid;
-
- shmid = shmget(memKey, size, 0);
-
- if (shmid < 0) {
- fprintf(stderr,"IpcMemoryIdGet: memKey=%d , size=%d , permission=%d",
- memKey, size , 0 );
- perror("IpcMemoryIdGet: shmget() failed");
- IpcConfigTip();
- return(IpcMemIdGetFailed);
- }
-
- return(shmid);
+ IpcMemoryId shmid;
+
+ shmid = shmget(memKey, size, 0);
+
+ if (shmid < 0)
+ {
+ fprintf(stderr, "IpcMemoryIdGet: memKey=%d , size=%d , permission=%d",
+ memKey, size, 0);
+ perror("IpcMemoryIdGet: shmget() failed");
+ IpcConfigTip();
+ return (IpcMemIdGetFailed);
+ }
+
+ return (shmid);
}
/****************************************************************************/
-/* IpcMemoryDetach(status, shmaddr) removes a shared memory segment */
-/* from a backend address space */
-/* (only called by backends running under the postmaster) */
+/* IpcMemoryDetach(status, shmaddr) removes a shared memory segment */
+/* from a backend address space */
+/* (only called by backends running under the postmaster) */
/****************************************************************************/
static void
IpcMemoryDetach(int status, char *shmaddr)
{
- if (shmdt(shmaddr) < 0) {
- elog(NOTICE, "IpcMemoryDetach: shmdt(0x%x): %m", shmaddr);
- }
+ if (shmdt(shmaddr) < 0)
+ {
+ elog(NOTICE, "IpcMemoryDetach: shmdt(0x%x): %m", shmaddr);
+ }
}
/****************************************************************************/
-/* IpcMemoryAttach(memId) returns the adress of shared memory */
-/* or IpcMemAttachFailed */
-/* */
-/* CALL IT: addr = (struct <MemoryStructure> *) IpcMemoryAttach(memId); */
-/* */
+/* IpcMemoryAttach(memId) returns the adress of shared memory */
+/* or IpcMemAttachFailed */
+/* */
+/* CALL IT: addr = (struct <MemoryStructure> *) IpcMemoryAttach(memId); */
+/* */
/****************************************************************************/
-char *
+char *
IpcMemoryAttach(IpcMemoryId memId)
{
- char *memAddress;
-
- if (UsePrivateMemory) {
- memAddress = (char *) PrivateMemoryAttach(memId);
- } else {
- memAddress = (char *) shmat(memId, 0, 0);
- }
-
- /* if ( *memAddress == -1) { XXX ??? */
- if ( memAddress == (char *)-1) {
- perror("IpcMemoryAttach: shmat() failed");
- IpcConfigTip();
- return(IpcMemAttachFailed);
- }
-
- if (!UsePrivateMemory)
- on_exitpg(IpcMemoryDetach, (caddr_t) memAddress);
-
- return((char *) memAddress);
+ char *memAddress;
+
+ if (UsePrivateMemory)
+ {
+ memAddress = (char *) PrivateMemoryAttach(memId);
+ }
+ else
+ {
+ memAddress = (char *) shmat(memId, 0, 0);
+ }
+
+ /* if ( *memAddress == -1) { XXX ??? */
+ if (memAddress == (char *) -1)
+ {
+ perror("IpcMemoryAttach: shmat() failed");
+ IpcConfigTip();
+ return (IpcMemAttachFailed);
+ }
+
+ if (!UsePrivateMemory)
+ on_exitpg(IpcMemoryDetach, (caddr_t) memAddress);
+
+ return ((char *) memAddress);
}
/****************************************************************************/
-/* IpcMemoryKill(memKey) removes a shared memory segment */
-/* (only called by the postmaster and standalone backends) */
+/* IpcMemoryKill(memKey) removes a shared memory segment */
+/* (only called by the postmaster and standalone backends) */
/****************************************************************************/
void
IpcMemoryKill(IpcMemoryKey memKey)
-{
- IpcMemoryId shmid;
-
- if (!UsePrivateMemory && (shmid = shmget(memKey, 0, 0)) >= 0) {
- if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL) < 0) {
- elog(NOTICE, "IpcMemoryKill: shmctl(%d, %d, 0) failed: %m",
- shmid, IPC_RMID);
+{
+ IpcMemoryId shmid;
+
+ if (!UsePrivateMemory && (shmid = shmget(memKey, 0, 0)) >= 0)
+ {
+ if (shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL) < 0)
+ {
+ elog(NOTICE, "IpcMemoryKill: shmctl(%d, %d, 0) failed: %m",
+ shmid, IPC_RMID);
+ }
}
- }
-}
+}
#ifdef HAS_TEST_AND_SET
/* ------------------
- * use hardware locks to replace semaphores for sequent machines
- * to avoid costs of swapping processes and to provide unlimited
- * supply of locks.
+ * use hardware locks to replace semaphores for sequent machines
+ * to avoid costs of swapping processes and to provide unlimited
+ * supply of locks.
* ------------------
*/
-static SLock *SLockArray = NULL;
-static SLock **FreeSLockPP;
-static int *UnusedSLockIP;
+static SLock *SLockArray = NULL;
+static SLock **FreeSLockPP;
+static int *UnusedSLockIP;
static slock_t *SLockMemoryLock;
static IpcMemoryId SLockMemoryId = -1;
-struct ipcdummy { /* to get alignment/size right */
- SLock *free;
- int unused;
- slock_t memlock;
- SLock slocks[NSLOCKS];
+struct ipcdummy
+{ /* to get alignment/size right */
+ SLock *free;
+ int unused;
+ slock_t memlock;
+ SLock slocks[NSLOCKS];
};
-static int SLockMemorySize = sizeof(struct ipcdummy);
+static int SLockMemorySize = sizeof(struct ipcdummy);
void
CreateAndInitSLockMemory(IPCKey key)
{
- int id;
- SLock *slckP;
-
- SLockMemoryId = IpcMemoryCreate(key,
- SLockMemorySize,
- 0700);
- AttachSLockMemory(key);
- *FreeSLockPP = NULL;
- *UnusedSLockIP = (int)FIRSTFREELOCKID;
- for (id=0; id<(int)FIRSTFREELOCKID; id++) {
- slckP = &(SLockArray[id]);
- S_INIT_LOCK(&(slckP->locklock));
- slckP->flag = NOLOCK;
- slckP->nshlocks = 0;
- S_INIT_LOCK(&(slckP->shlock));
- S_INIT_LOCK(&(slckP->exlock));
- S_INIT_LOCK(&(slckP->comlock));
- slckP->next = NULL;
- }
- return;
+ int id;
+ SLock *slckP;
+
+ SLockMemoryId = IpcMemoryCreate(key,
+ SLockMemorySize,
+ 0700);
+ AttachSLockMemory(key);
+ *FreeSLockPP = NULL;
+ *UnusedSLockIP = (int) FIRSTFREELOCKID;
+ for (id = 0; id < (int) FIRSTFREELOCKID; id++)
+ {
+ slckP = &(SLockArray[id]);
+ S_INIT_LOCK(&(slckP->locklock));
+ slckP->flag = NOLOCK;
+ slckP->nshlocks = 0;
+ S_INIT_LOCK(&(slckP->shlock));
+ S_INIT_LOCK(&(slckP->exlock));
+ S_INIT_LOCK(&(slckP->comlock));
+ slckP->next = NULL;
+ }
+ return;
}
void
AttachSLockMemory(IPCKey key)
{
- struct ipcdummy *slockM;
-
- if (SLockMemoryId == -1)
- SLockMemoryId = IpcMemoryIdGet(key,SLockMemorySize);
- if (SLockMemoryId == -1)
- elog(FATAL, "SLockMemory not in shared memory");
- slockM = (struct ipcdummy *) IpcMemoryAttach(SLockMemoryId);
- if (slockM == IpcMemAttachFailed)
- elog(FATAL, "AttachSLockMemory: could not attach segment");
- FreeSLockPP = (SLock **) &(slockM->free);
- UnusedSLockIP = (int *) &(slockM->unused);
- SLockMemoryLock = (slock_t *) &(slockM->memlock);
- S_INIT_LOCK(SLockMemoryLock);
- SLockArray = (SLock *) &(slockM->slocks[0]);
- return;
+ struct ipcdummy *slockM;
+
+ if (SLockMemoryId == -1)
+ SLockMemoryId = IpcMemoryIdGet(key, SLockMemorySize);
+ if (SLockMemoryId == -1)
+ elog(FATAL, "SLockMemory not in shared memory");
+ slockM = (struct ipcdummy *) IpcMemoryAttach(SLockMemoryId);
+ if (slockM == IpcMemAttachFailed)
+ elog(FATAL, "AttachSLockMemory: could not attach segment");
+ FreeSLockPP = (SLock **) & (slockM->free);
+ UnusedSLockIP = (int *) &(slockM->unused);
+ SLockMemoryLock = (slock_t *) & (slockM->memlock);
+ S_INIT_LOCK(SLockMemoryLock);
+ SLockArray = (SLock *) & (slockM->slocks[0]);
+ return;
}
#ifdef LOCKDEBUG
#define PRINT_LOCK(LOCK) printf("(locklock = %d, flag = %d, nshlocks = %d, \
shlock = %d, exlock =%d)\n", LOCK->locklock, \
- LOCK->flag, LOCK->nshlocks, LOCK->shlock, \
- LOCK->exlock)
+ LOCK->flag, LOCK->nshlocks, LOCK->shlock, \
+ LOCK->exlock)
#endif
void
ExclusiveLock(int lockid)
{
- SLock *slckP;
- slckP = &(SLockArray[lockid]);
+ SLock *slckP;
+
+ slckP = &(SLockArray[lockid]);
#ifdef LOCKDEBUG
- printf("ExclusiveLock(%d)\n", lockid);
- printf("IN: ");
- PRINT_LOCK(slckP);
+ printf("ExclusiveLock(%d)\n", lockid);
+ printf("IN: ");
+ PRINT_LOCK(slckP);
#endif
- ex_try_again:
- S_LOCK(&(slckP->locklock));
- switch (slckP->flag) {
- case NOLOCK:
- slckP->flag = EXCLUSIVELOCK;
- S_LOCK(&(slckP->exlock));
- S_LOCK(&(slckP->shlock));
- S_UNLOCK(&(slckP->locklock));
+ex_try_again:
+ S_LOCK(&(slckP->locklock));
+ switch (slckP->flag)
+ {
+ case NOLOCK:
+ slckP->flag = EXCLUSIVELOCK;
+ S_LOCK(&(slckP->exlock));
+ S_LOCK(&(slckP->shlock));
+ S_UNLOCK(&(slckP->locklock));
#ifdef LOCKDEBUG
- printf("OUT: ");
- PRINT_LOCK(slckP);
+ printf("OUT: ");
+ PRINT_LOCK(slckP);
#endif
- return;
- case SHAREDLOCK:
- case EXCLUSIVELOCK:
- S_UNLOCK(&(slckP->locklock));
- S_LOCK(&(slckP->exlock));
- S_UNLOCK(&(slckP->exlock));
- goto ex_try_again;
- }
+ return;
+ case SHAREDLOCK:
+ case EXCLUSIVELOCK:
+ S_UNLOCK(&(slckP->locklock));
+ S_LOCK(&(slckP->exlock));
+ S_UNLOCK(&(slckP->exlock));
+ goto ex_try_again;
+ }
}
void
ExclusiveUnlock(int lockid)
{
- SLock *slckP;
-
- slckP = &(SLockArray[lockid]);
+ SLock *slckP;
+
+ slckP = &(SLockArray[lockid]);
#ifdef LOCKDEBUG
- printf("ExclusiveUnlock(%d)\n", lockid);
- printf("IN: ");
- PRINT_LOCK(slckP);
+ printf("ExclusiveUnlock(%d)\n", lockid);
+ printf("IN: ");
+ PRINT_LOCK(slckP);
#endif
- S_LOCK(&(slckP->locklock));
- /* -------------
- * give favor to read processes
- * -------------
- */
- slckP->flag = NOLOCK;
- if (slckP->nshlocks > 0) {
- while (slckP->nshlocks > 0) {
- S_UNLOCK(&(slckP->shlock));
- S_LOCK(&(slckP->comlock));
+ S_LOCK(&(slckP->locklock));
+ /* -------------
+ * give favor to read processes
+ * -------------
+ */
+ slckP->flag = NOLOCK;
+ if (slckP->nshlocks > 0)
+ {
+ while (slckP->nshlocks > 0)
+ {
+ S_UNLOCK(&(slckP->shlock));
+ S_LOCK(&(slckP->comlock));
+ }
+ S_UNLOCK(&(slckP->shlock));
}
- S_UNLOCK(&(slckP->shlock));
- }
- else {
- S_UNLOCK(&(slckP->shlock));
- }
- S_UNLOCK(&(slckP->exlock));
- S_UNLOCK(&(slckP->locklock));
+ else
+ {
+ S_UNLOCK(&(slckP->shlock));
+ }
+ S_UNLOCK(&(slckP->exlock));
+ S_UNLOCK(&(slckP->locklock));
#ifdef LOCKDEBUG
- printf("OUT: ");
- PRINT_LOCK(slckP);
+ printf("OUT: ");
+ PRINT_LOCK(slckP);
#endif
- return;
+ return;
}
bool
LockIsFree(int lockid)
{
- return(SLockArray[lockid].flag == NOLOCK);
+ return (SLockArray[lockid].flag == NOLOCK);
}
-#endif /* HAS_TEST_AND_SET */
+#endif /* HAS_TEST_AND_SET */
static void
IpcConfigTip(void)
{
- fprintf(stderr,"This type of error is usually caused by improper\n");
- fprintf(stderr,"shared memory or System V IPC semaphore configuration.\n");
- fprintf(stderr,"See the FAQ for more detailed information\n");
+ fprintf(stderr, "This type of error is usually caused by improper\n");
+ fprintf(stderr, "shared memory or System V IPC semaphore configuration.\n");
+ fprintf(stderr, "See the FAQ for more detailed information\n");
}
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index f949041f44d..4aad8e85f54 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* ipci.c--
- * POSTGRES inter-process communication initialization code.
+ * POSTGRES inter-process communication initialization code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.5 1997/01/08 08:32:03 bryanh Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.6 1997/09/07 04:48:33 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,129 +23,131 @@
#include "storage/proc.h"
#include "storage/smgr.h"
#include "storage/lock.h"
-#include "miscadmin.h" /* for DebugLvl */
+#include "miscadmin.h" /* for DebugLvl */
/*
* SystemPortAddressCreateMemoryKey --
- * Returns a memory key given a port address.
+ * Returns a memory key given a port address.
*/
IPCKey
SystemPortAddressCreateIPCKey(SystemPortAddress address)
{
- Assert(address < 32768); /* XXX */
-
- return (SystemPortAddressGetIPCKey(address));
+ Assert(address < 32768); /* XXX */
+
+ return (SystemPortAddressGetIPCKey(address));
}
/*
* CreateSharedMemoryAndSemaphores --
- * Creates and initializes shared memory and semaphores.
+ * Creates and initializes shared memory and semaphores.
*/
/**************************************************
-
+
CreateSharedMemoryAndSemaphores
is called exactly *ONCE* by the postmaster.
It is *NEVER* called by the postgres backend
-
+
0) destroy any existing semaphores for both buffer
and lock managers.
1) create the appropriate *SHARED* memory segments
for the two resource managers.
-
+
**************************************************/
void
CreateSharedMemoryAndSemaphores(IPCKey key)
{
- int size;
-
+ int size;
+
#ifdef HAS_TEST_AND_SET
- /* ---------------
- * create shared memory for slocks
- * --------------
- */
- CreateAndInitSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
+ /* ---------------
+ * create shared memory for slocks
+ * --------------
+ */
+ CreateAndInitSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
#endif
- /* ----------------
- * kill and create the buffer manager buffer pool (and semaphore)
- * ----------------
- */
- CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key));
- size = BufferShmemSize() + LockShmemSize();
-
+ /* ----------------
+ * kill and create the buffer manager buffer pool (and semaphore)
+ * ----------------
+ */
+ CreateSpinlocks(IPCKeyGetSpinLockSemaphoreKey(key));
+ size = BufferShmemSize() + LockShmemSize();
+
#ifdef MAIN_MEMORY
- size += MMShmemSize();
-#endif /* MAIN_MEMORY */
-
- if (DebugLvl > 1) {
- fprintf(stderr, "binding ShmemCreate(key=%x, size=%d)\n",
- IPCKeyGetBufferMemoryKey(key), size);
- }
- ShmemCreate(IPCKeyGetBufferMemoryKey(key), size);
- ShmemBindingTabReset();
- InitShmem(key, size);
- InitBufferPool(key);
-
- /* ----------------
- * do the lock table stuff
- * ----------------
- */
- InitLocks();
- InitMultiLevelLockm();
- if (InitMultiLevelLockm() == INVALID_TABLEID)
- elog(FATAL, "Couldn't create the lock table");
-
- /* ----------------
- * do process table stuff
- * ----------------
- */
- InitProcGlobal(key);
- on_exitpg(ProcFreeAllSemaphores, 0);
-
- CreateSharedInvalidationState(key);
+ size += MMShmemSize();
+#endif /* MAIN_MEMORY */
+
+ if (DebugLvl > 1)
+ {
+ fprintf(stderr, "binding ShmemCreate(key=%x, size=%d)\n",
+ IPCKeyGetBufferMemoryKey(key), size);
+ }
+ ShmemCreate(IPCKeyGetBufferMemoryKey(key), size);
+ ShmemBindingTabReset();
+ InitShmem(key, size);
+ InitBufferPool(key);
+
+ /* ----------------
+ * do the lock table stuff
+ * ----------------
+ */
+ InitLocks();
+ InitMultiLevelLockm();
+ if (InitMultiLevelLockm() == INVALID_TABLEID)
+ elog(FATAL, "Couldn't create the lock table");
+
+ /* ----------------
+ * do process table stuff
+ * ----------------
+ */
+ InitProcGlobal(key);
+ on_exitpg(ProcFreeAllSemaphores, 0);
+
+ CreateSharedInvalidationState(key);
}
/*
* AttachSharedMemoryAndSemaphores --
- * Attachs existant shared memory and semaphores.
+ * Attachs existant shared memory and semaphores.
*/
void
AttachSharedMemoryAndSemaphores(IPCKey key)
{
- int size;
-
- /* ----------------
- * create rather than attach if using private key
- * ----------------
- */
- if (key == PrivateIPCKey) {
- CreateSharedMemoryAndSemaphores(key);
- return;
- }
-
+ int size;
+
+ /* ----------------
+ * create rather than attach if using private key
+ * ----------------
+ */
+ if (key == PrivateIPCKey)
+ {
+ CreateSharedMemoryAndSemaphores(key);
+ return;
+ }
+
#ifdef HAS_TEST_AND_SET
- /* ----------------
- * attach the slock shared memory
- * ----------------
- */
- AttachSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
+ /* ----------------
+ * attach the slock shared memory
+ * ----------------
+ */
+ AttachSLockMemory(IPCKeyGetSLockSharedMemoryKey(key));
#endif
- /* ----------------
- * attach the buffer manager buffer pool (and semaphore)
- * ----------------
- */
- size = BufferShmemSize() + LockShmemSize();
- InitShmem(key, size);
- InitBufferPool(key);
-
- /* ----------------
- * initialize lock table stuff
- * ----------------
- */
- InitLocks();
- if (InitMultiLevelLockm() == INVALID_TABLEID)
- elog(FATAL, "Couldn't attach to the lock table");
-
- AttachSharedInvalidationState(key);
+ /* ----------------
+ * attach the buffer manager buffer pool (and semaphore)
+ * ----------------
+ */
+ size = BufferShmemSize() + LockShmemSize();
+ InitShmem(key, size);
+ InitBufferPool(key);
+
+ /* ----------------
+ * initialize lock table stuff
+ * ----------------
+ */
+ InitLocks();
+ if (InitMultiLevelLockm() == INVALID_TABLEID)
+ elog(FATAL, "Couldn't attach to the lock table");
+
+ AttachSharedInvalidationState(key);
}
diff --git a/src/backend/storage/ipc/s_lock.c b/src/backend/storage/ipc/s_lock.c
index 146c2d7080a..70f0deb62c9 100644
--- a/src/backend/storage/ipc/s_lock.c
+++ b/src/backend/storage/ipc/s_lock.c
@@ -1,40 +1,40 @@
/*-------------------------------------------------------------------------
*
* s_lock.c--
- * This file contains the implementation (if any) for spinlocks.
+ * This file contains the implementation (if any) for spinlocks.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/s_lock.c,v 1.21 1997/09/05 18:10:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/s_lock.c,v 1.22 1997/09/07 04:48:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * DESCRIPTION
- * The following code fragment should be written (in assembly
- * language) on machines that have a native test-and-set instruction:
+ * DESCRIPTION
+ * The following code fragment should be written (in assembly
+ * language) on machines that have a native test-and-set instruction:
*
- * void
- * S_LOCK(char_address)
- * char *char_address;
- * {
- * while (test_and_set(char_address))
- * ;
- * }
+ * void
+ * S_LOCK(char_address)
+ * char *char_address;
+ * {
+ * while (test_and_set(char_address))
+ * ;
+ * }
*
- * If this is not done, POSTGRES will default to using System V
- * semaphores (and take a large performance hit -- around 40% of
- * its time on a DS5000/240 is spent in semop(3)...).
+ * If this is not done, POSTGRES will default to using System V
+ * semaphores (and take a large performance hit -- around 40% of
+ * its time on a DS5000/240 is spent in semop(3)...).
*
- * NOTES
- * AIX has a test-and-set but the recommended interface is the cs(3)
- * system call. This provides an 8-instruction (plus system call
- * overhead) uninterruptible compare-and-set operation. True
- * spinlocks might be faster but using cs(3) still speeds up the
- * regression test suite by about 25%. I don't have an assembler
- * manual for POWER in any case.
+ * NOTES
+ * AIX has a test-and-set but the recommended interface is the cs(3)
+ * system call. This provides an 8-instruction (plus system call
+ * overhead) uninterruptible compare-and-set operation. True
+ * spinlocks might be faster but using cs(3) still speeds up the
+ * regression test suite by about 25%. I don't have an assembler
+ * manual for POWER in any case.
*
*/
#include "postgres.h"
@@ -50,71 +50,71 @@
* slock_t is defined as a struct mutex.
*/
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
mutex_lock(lock);
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
mutex_unlock(lock);
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- mutex_init(lock);
+ mutex_init(lock);
}
/* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */
int
- S_LOCK_FREE(slock_t *lock)
+S_LOCK_FREE(slock_t * lock)
{
/* For Mach, we have to delve inside the entrails of `struct mutex'. Ick! */
- return (lock->lock == 0);
+ return (lock->lock == 0);
}
-#endif /* next */
+#endif /* next */
#if defined(irix5)
/*
* SGI IRIX 5
- * slock_t is defined as a struct abilock_t, which has a single unsigned long
+ * slock_t is defined as a struct abilock_t, which has a single unsigned long
* member.
- *
+ *
* This stuff may be supplemented in the future with Masato Kataoka's MIPS-II
* assembly from his NECEWS SVR4 port, but we probably ought to retain this
* for the R3000 chips out there.
*/
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
/* spin_lock(lock); */
while (!acquire_lock(lock))
- ;
+ ;
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
release_lock(lock);
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- init_lock(lock);
+ init_lock(lock);
}
/* S_LOCK_FREE should return 1 if lock is free; 0 if lock is locked */
int
-S_LOCK_FREE(slock_t *lock)
+S_LOCK_FREE(slock_t * lock)
{
- return(stat_lock(lock)==UNLOCKED);
+ return (stat_lock(lock) == UNLOCKED);
}
-#endif /* irix5 */
+#endif /* irix5 */
/*
@@ -127,62 +127,62 @@ S_LOCK_FREE(slock_t *lock)
#if defined(__alpha__) || defined(__alpha)
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
- while (msem_lock(lock, MSEM_IF_NOWAIT) < 0)
- ;
+ while (msem_lock(lock, MSEM_IF_NOWAIT) < 0)
+ ;
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- msem_unlock(lock, 0);
+ msem_unlock(lock, 0);
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- msem_init(lock, MSEM_UNLOCKED);
+ msem_init(lock, MSEM_UNLOCKED);
}
int
-S_LOCK_FREE(slock_t *lock)
+S_LOCK_FREE(slock_t * lock)
{
- return(lock->msem_state ? 0 : 1);
+ return (lock->msem_state ? 0 : 1);
}
-#endif /* alpha */
+#endif /* alpha */
/*
* Solaris 2
*/
#if defined(i386_solaris) || \
- defined(sparc_solaris)
+ defined(sparc_solaris)
/* for xxxxx_solaris, this is defined in port/.../tas.s */
-static int tas(slock_t *lock);
+static int tas(slock_t * lock);
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
- while (tas(lock))
- ;
+ while (tas(lock))
+ ;
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- *lock = 0;
+ *lock = 0;
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- S_UNLOCK(lock);
+ S_UNLOCK(lock);
}
-#endif /* i86pc_solaris || sparc_solaris */
+#endif /* i86pc_solaris || sparc_solaris */
/*
* AIX (POWER)
@@ -194,25 +194,25 @@ S_INIT_LOCK(slock_t *lock)
#if defined(aix)
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
- while (cs((int *) lock, 0, 1))
- ;
+ while (cs((int *) lock, 0, 1))
+ ;
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- *lock = 0;
+ *lock = 0;
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- S_UNLOCK(lock);
+ S_UNLOCK(lock);
}
-#endif /* aix */
+#endif /* aix */
/*
* HP-UX (PA-RISC)
@@ -224,90 +224,90 @@ S_INIT_LOCK(slock_t *lock)
#if defined(hpux)
/*
-* a "set" slock_t has a single word cleared. a "clear" slock_t has
+* a "set" slock_t has a single word cleared. a "clear" slock_t has
* all words set to non-zero.
*/
-static slock_t clear_lock = { -1, -1, -1, -1 };
+static slock_t clear_lock = {-1, -1, -1, -1};
-static int tas(slock_t *lock);
+static int tas(slock_t * lock);
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
- while (tas(lock))
- ;
+ while (tas(lock))
+ ;
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- *lock = clear_lock; /* struct assignment */
+ *lock = clear_lock; /* struct assignment */
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- S_UNLOCK(lock);
+ S_UNLOCK(lock);
}
int
-S_LOCK_FREE(slock_t *lock)
+S_LOCK_FREE(slock_t * lock)
{
- register int *lock_word = (int *) (((long) lock + 15) & ~15);
+ register int *lock_word = (int *) (((long) lock + 15) & ~15);
- return(*lock_word != 0);
+ return (*lock_word != 0);
}
-#endif /* hpux */
+#endif /* hpux */
/*
* sun3
*/
-
+
#if defined(sun3)
-static int tas(slock_t *lock);
+static int tas(slock_t * lock);
-void
-S_LOCK(slock_t *lock)
+void
+S_LOCK(slock_t * lock)
{
- while (tas(lock));
+ while (tas(lock));
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- *lock = 0;
+ *lock = 0;
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- S_UNLOCK(lock);
+ S_UNLOCK(lock);
}
static int
tas_dummy()
{
- asm("LLA0:");
- asm(" .data");
- asm(" .text");
- asm("|#PROC# 04");
- asm(" .globl _tas");
- asm("_tas:");
- asm("|#PROLOGUE# 1");
- asm(" movel sp@(0x4),a0");
- asm(" tas a0@");
- asm(" beq LLA1");
- asm(" moveq #-128,d0");
- asm(" rts");
- asm("LLA1:");
- asm(" moveq #0,d0");
- asm(" rts");
- asm(" .data");
-}
-
-#endif /* sun3 */
+ asm("LLA0:");
+ asm(" .data");
+ asm(" .text");
+ asm("|#PROC# 04");
+ asm(" .globl _tas");
+ asm("_tas:");
+ asm("|#PROLOGUE# 1");
+ asm(" movel sp@(0x4),a0");
+ asm(" tas a0@");
+ asm(" beq LLA1");
+ asm(" moveq #-128,d0");
+ asm(" rts");
+ asm("LLA1:");
+ asm(" moveq #0,d0");
+ asm(" rts");
+ asm(" .data");
+}
+
+#endif /* sun3 */
/*
* sparc machines
@@ -317,48 +317,48 @@ tas_dummy()
/* if we're using -ansi w/ gcc, use __asm__ instead of asm */
#if defined(__STRICT_ANSI__)
-#define asm(x) __asm__(x)
-#endif
+#define asm(x) __asm__(x)
+#endif
-static int tas(slock_t *lock);
+static int tas(slock_t * lock);
static int
tas_dummy()
{
- asm(".seg \"data\"");
- asm(".seg \"text\"");
- asm(".global _tas");
- asm("_tas:");
-
- /*
- * Sparc atomic test and set (sparc calls it "atomic load-store")
- */
-
- asm("ldstub [%r8], %r8");
-
- /*
- * Did test and set actually do the set?
- */
-
- asm("tst %r8");
-
- asm("be,a ReturnZero");
-
- /*
- * otherwise, just return.
- */
-
- asm("clr %r8");
- asm("mov 0x1, %r8");
- asm("ReturnZero:");
- asm("retl");
- asm("nop");
+ asm(".seg \"data\"");
+ asm(".seg \"text\"");
+ asm(".global _tas");
+ asm("_tas:");
+
+ /*
+ * Sparc atomic test and set (sparc calls it "atomic load-store")
+ */
+
+ asm("ldstub [%r8], %r8");
+
+ /*
+ * Did test and set actually do the set?
+ */
+
+ asm("tst %r8");
+
+ asm("be,a ReturnZero");
+
+ /*
+ * otherwise, just return.
+ */
+
+ asm("clr %r8");
+ asm("mov 0x1, %r8");
+ asm("ReturnZero:");
+ asm("retl");
+ asm("nop");
}
void
S_LOCK(unsigned char *addr)
{
- while (tas(addr));
+ while (tas(addr));
}
@@ -368,16 +368,16 @@ S_LOCK(unsigned char *addr)
void
S_UNLOCK(unsigned char *addr)
{
- *addr = 0;
+ *addr = 0;
}
void
S_INIT_LOCK(unsigned char *addr)
{
- *addr = 0;
+ *addr = 0;
}
-#endif /* NEED_SPARC_TAS_ASM */
+#endif /* NEED_SPARC_TAS_ASM */
/*
* i386 based things
@@ -386,39 +386,41 @@ S_INIT_LOCK(unsigned char *addr)
#if defined(NEED_I386_TAS_ASM)
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
- slock_t res;
+ slock_t res;
- do{
- __asm__("xchgb %0,%1":"=q" (res),"=m" (*lock):"0" (0x1));
- }while(res != 0);
+ do
+ {
+__asm__("xchgb %0,%1": "=q"(res), "=m"(*lock):"0"(0x1));
+ } while (res != 0);
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- *lock = 0;
+ *lock = 0;
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- S_UNLOCK(lock);
+ S_UNLOCK(lock);
}
-#endif /* NEED_I386_TAS_ASM */
+#endif /* NEED_I386_TAS_ASM */
#if defined(__alpha__) && defined(linux)
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
- slock_t res;
+ slock_t res;
- do{
- __asm__(" ldq $0, %0 \n\
+ do
+ {
+__asm__(" ldq $0, %0 \n\
bne $0, already_set \n\
ldq_l $0, %0 \n\
bne $0, already_set \n\
@@ -430,56 +432,58 @@ S_LOCK(slock_t *lock)
jmp $31, end \n\
stqc_fail: or $31, 1, $0 \n\
already_set: bis $0, $0, %1 \n\
- end: nop " : "=m" (*lock), "=r" (res) :: "0" );
- }while(res != 0);
+ end: nop ": "=m"(*lock), "=r"(res): :"0");
+ } while (res != 0);
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- __asm__("mb");
- *lock = 0;
+ __asm__("mb");
+ *lock = 0;
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- S_UNLOCK(lock);
+ S_UNLOCK(lock);
}
-#endif /* defined(__alpha__) && defined(linux) */
+#endif /* defined(__alpha__) && defined(linux) */
#if defined(linux) && defined(sparc)
-
+
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
- slock_t res;
+ slock_t res;
- do{
- __asm__("ldstub [%1], %0"
- : "=&r" (res)
- : "r" (lock));
- }while(!res != 0);
+ do
+ {
+ __asm__("ldstub [%1], %0"
+: "=&r"(res)
+: "r"(lock));
+ } while (!res != 0);
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- *lock = 0;
+ *lock = 0;
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- S_UNLOCK(lock);
+ S_UNLOCK(lock);
}
-#endif /* defined(linux) && defined(sparc) */
+#endif /* defined(linux) && defined(sparc) */
#if defined(linux) && defined(PPC)
-static int tas_dummy()
+static int
+tas_dummy()
{
__asm__(" \n\
tas: \n\
@@ -496,26 +500,26 @@ success: \n\
blr \n\
");
}
-
+
void
-S_LOCK(slock_t *lock)
+S_LOCK(slock_t * lock)
{
- while (tas(lock))
- ;
+ while (tas(lock))
+ ;
}
void
-S_UNLOCK(slock_t *lock)
+S_UNLOCK(slock_t * lock)
{
- *lock = 0;
+ *lock = 0;
}
void
-S_INIT_LOCK(slock_t *lock)
+S_INIT_LOCK(slock_t * lock)
{
- S_UNLOCK(lock);
+ S_UNLOCK(lock);
}
-#endif /* defined(linux) && defined(PPC) */
+#endif /* defined(linux) && defined(PPC) */
-#endif /* HAS_TEST_AND_SET */
+#endif /* HAS_TEST_AND_SET */
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index c839059ea9b..63848171a1f 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* shmem.c--
- * create shared memory and initialize shared memory data structures.
+ * create shared memory and initialize shared memory data structures.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.10 1997/08/12 22:53:56 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.11 1997/09/07 04:48:37 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,43 +18,43 @@
* allocating and binding to shared memory data structures.
*
* NOTES:
- * (a) There are three kinds of shared memory data structures
- * available to POSTGRES: fixed-size structures, queues and hash
- * tables. Fixed-size structures contain things like global variables
- * for a module and should never be allocated after the process
- * initialization phase. Hash tables have a fixed maximum size, but
- * their actual size can vary dynamically. When entries are added
- * to the table, more space is allocated. Queues link data structures
- * that have been allocated either as fixed size structures or as hash
- * buckets. Each shared data structure has a string name to identify
- * it (assigned in the module that declares it).
+ * (a) There are three kinds of shared memory data structures
+ * available to POSTGRES: fixed-size structures, queues and hash
+ * tables. Fixed-size structures contain things like global variables
+ * for a module and should never be allocated after the process
+ * initialization phase. Hash tables have a fixed maximum size, but
+ * their actual size can vary dynamically. When entries are added
+ * to the table, more space is allocated. Queues link data structures
+ * that have been allocated either as fixed size structures or as hash
+ * buckets. Each shared data structure has a string name to identify
+ * it (assigned in the module that declares it).
*
- * (b) During initialization, each module looks for its
- * shared data structures in a hash table called the "Binding Table".
- * If the data structure is not present, the caller can allocate
- * a new one and initialize it. If the data structure is present,
- * the caller "attaches" to the structure by initializing a pointer
- * in the local address space.
- * The binding table has two purposes: first, it gives us
- * a simple model of how the world looks when a backend process
- * initializes. If something is present in the binding table,
- * it is initialized. If it is not, it is uninitialized. Second,
- * the binding table allows us to allocate shared memory on demand
- * instead of trying to preallocate structures and hard-wire the
- * sizes and locations in header files. If you are using a lot
- * of shared memory in a lot of different places (and changing
- * things during development), this is important.
+ * (b) During initialization, each module looks for its
+ * shared data structures in a hash table called the "Binding Table".
+ * If the data structure is not present, the caller can allocate
+ * a new one and initialize it. If the data structure is present,
+ * the caller "attaches" to the structure by initializing a pointer
+ * in the local address space.
+ * The binding table has two purposes: first, it gives us
+ * a simple model of how the world looks when a backend process
+ * initializes. If something is present in the binding table,
+ * it is initialized. If it is not, it is uninitialized. Second,
+ * the binding table allows us to allocate shared memory on demand
+ * instead of trying to preallocate structures and hard-wire the
+ * sizes and locations in header files. If you are using a lot
+ * of shared memory in a lot of different places (and changing
+ * things during development), this is important.
*
- * (c) memory allocation model: shared memory can never be
- * freed, once allocated. Each hash table has its own free list,
- * so hash buckets can be reused when an item is deleted. However,
- * if one hash table grows very large and then shrinks, its space
- * cannot be redistributed to other tables. We could build a simple
- * hash bucket garbage collector if need be. Right now, it seems
- * unnecessary.
+ * (c) memory allocation model: shared memory can never be
+ * freed, once allocated. Each hash table has its own free list,
+ * so hash buckets can be reused when an item is deleted. However,
+ * if one hash table grows very large and then shrinks, its space
+ * cannot be redistributed to other tables. We could build a simple
+ * hash bucket garbage collector if need be. Right now, it seems
+ * unnecessary.
*
- * See InitSem() in sem.c for an example of how to use the
- * binding table.
+ * See InitSem() in sem.c for an example of how to use the
+ * binding table.
*
*/
#include <stdio.h>
@@ -70,27 +70,23 @@
/* shared memory global variables */
-unsigned long ShmemBase = 0; /* start and end address of
- * shared memory
- */
-static unsigned long ShmemEnd = 0;
-static unsigned long ShmemSize = 0; /* current size (and default) */
+unsigned long ShmemBase = 0; /* start and end address of shared memory */
+static unsigned long ShmemEnd = 0;
+static unsigned long ShmemSize = 0; /* current size (and default) */
-SPINLOCK ShmemLock; /* lock for shared memory allocation */
+SPINLOCK ShmemLock; /* lock for shared memory allocation */
-SPINLOCK BindingLock; /* lock for binding table access */
+SPINLOCK BindingLock; /* lock for binding table access */
-static unsigned long *ShmemFreeStart = NULL; /* pointer to the OFFSET of
- * first free shared memory
- */
-static unsigned long *ShmemBindingTabOffset = NULL; /* start of the binding
- * table (for bootstrap)
- */
-static int ShmemBootstrap = FALSE; /* flag becomes true when shared mem
- * is created by POSTMASTER
- */
+static unsigned long *ShmemFreeStart = NULL; /* pointer to the OFFSET
+ * of first free shared
+ * memory */
+static unsigned long *ShmemBindingTabOffset = NULL; /* start of the binding
+ * table (for bootstrap) */
+static int ShmemBootstrap = FALSE; /* flag becomes true when shared
+ * mem is created by POSTMASTER */
-static HTAB *BindingTable = NULL;
+static HTAB *BindingTable = NULL;
/* ---------------------
* ShmemBindingTabReset() - Resets the binding table to NULL....
@@ -101,16 +97,16 @@ static HTAB *BindingTable = NULL;
void
ShmemBindingTabReset(void)
{
- BindingTable = (HTAB *)NULL;
+ BindingTable = (HTAB *) NULL;
}
/*
- * CreateSharedRegion() --
+ * CreateSharedRegion() --
*
- * This routine is called once by the postmaster to
- * initialize the shared buffer pool. Assume there is
- * only one postmaster so no synchronization is necessary
- * until after this routine completes successfully.
+ * This routine is called once by the postmaster to
+ * initialize the shared buffer pool. Assume there is
+ * only one postmaster so no synchronization is necessary
+ * until after this routine completes successfully.
*
* key is a unique identifier for the shmem region.
* size is the size of the region.
@@ -120,202 +116,220 @@ static IpcMemoryId ShmemId;
void
ShmemCreate(unsigned int key, unsigned int size)
{
- if (size)
- ShmemSize = size;
- /* create shared mem region */
- if ((ShmemId=IpcMemoryCreate(key,ShmemSize,IPCProtection))
- ==IpcMemCreationFailed) {
- elog(FATAL,"ShmemCreate: cannot create region");
- exit(1);
- }
-
- /* ShmemBootstrap is true if shared memory has been
- * created, but not yet initialized. Only the
- * postmaster/creator-of-all-things should have
- * this flag set.
- */
- ShmemBootstrap = TRUE;
+ if (size)
+ ShmemSize = size;
+ /* create shared mem region */
+ if ((ShmemId = IpcMemoryCreate(key, ShmemSize, IPCProtection))
+ == IpcMemCreationFailed)
+ {
+ elog(FATAL, "ShmemCreate: cannot create region");
+ exit(1);
+ }
+
+ /*
+ * ShmemBootstrap is true if shared memory has been created, but not
+ * yet initialized. Only the postmaster/creator-of-all-things should
+ * have this flag set.
+ */
+ ShmemBootstrap = TRUE;
}
/*
- * InitShmem() -- map region into process address space
- * and initialize shared data structures.
+ * InitShmem() -- map region into process address space
+ * and initialize shared data structures.
*
*/
int
InitShmem(unsigned int key, unsigned int size)
{
- Pointer sharedRegion;
- unsigned long currFreeSpace;
-
- HASHCTL info;
- int hash_flags;
- BindingEnt * result,item;
- bool found;
- IpcMemoryId shmid;
-
- /* if zero key, use default memory size */
- if (size)
- ShmemSize = size;
-
- /* default key is 0 */
-
- /* attach to shared memory region (SysV or BSD OS specific) */
- if (ShmemBootstrap && key == PrivateIPCKey)
- /* if we are running backend alone */
- shmid = ShmemId;
- else
- shmid = IpcMemoryIdGet(IPCKeyGetBufferMemoryKey(key), ShmemSize);
- sharedRegion = IpcMemoryAttach(shmid);
- if (sharedRegion == NULL) {
- elog(FATAL,"AttachSharedRegion: couldn't attach to shmem\n");
- return(FALSE);
- }
-
- /* get pointers to the dimensions of shared memory */
- ShmemBase = (unsigned long) sharedRegion;
- ShmemEnd = (unsigned long) sharedRegion + ShmemSize;
- currFreeSpace = 0;
-
- /* First long in shared memory is the count of available space */
- ShmemFreeStart = (unsigned long *) ShmemBase;
- /* next is a shmem pointer to the binding table */
- ShmemBindingTabOffset = ShmemFreeStart + 1;
-
- currFreeSpace +=
- sizeof(ShmemFreeStart) + sizeof(ShmemBindingTabOffset);
-
- /* bootstrap initialize spin locks so we can start to use the
- * allocator and binding table.
- */
- if (! InitSpinLocks(ShmemBootstrap, IPCKeyGetSpinLockSemaphoreKey(key))) {
- return(FALSE);
- }
-
- /* We have just allocated additional space for two spinlocks.
- * Now setup the global free space count
- */
- if (ShmemBootstrap) {
- *ShmemFreeStart = currFreeSpace;
- }
-
- /* if ShmemFreeStart is NULL, then the allocator won't work */
- Assert(*ShmemFreeStart);
-
- /* create OR attach to the shared memory binding table */
- info.keysize = BTABLE_KEYSIZE;
- info.datasize = BTABLE_DATASIZE;
- hash_flags = (HASH_ELEM);
-
- /* This will acquire the binding table lock, but not release it. */
- BindingTable = ShmemInitHash("BindingTable",
- BTABLE_SIZE,BTABLE_SIZE,
- &info,hash_flags);
-
- if (! BindingTable) {
- elog(FATAL,"InitShmem: couldn't initialize Binding Table");
- return(FALSE);
- }
-
- /* Now, check the binding table for an entry to the binding
- * table. If there is an entry there, someone else created
- * the table. Otherwise, we did and we have to initialize it.
- */
- memset(item.key, 0, BTABLE_KEYSIZE);
- strncpy(item.key,"BindingTable",BTABLE_KEYSIZE);
-
- result = (BindingEnt *)
- hash_search(BindingTable,(char *) &item,HASH_ENTER, &found);
-
-
- if (! result ) {
- elog(FATAL,"InitShmem: corrupted binding table");
- return(FALSE);
- }
-
- if (! found) {
- /* bootstrapping shmem: we have to initialize the
- * binding table now.
+ Pointer sharedRegion;
+ unsigned long currFreeSpace;
+
+ HASHCTL info;
+ int hash_flags;
+ BindingEnt *result,
+ item;
+ bool found;
+ IpcMemoryId shmid;
+
+ /* if zero key, use default memory size */
+ if (size)
+ ShmemSize = size;
+
+ /* default key is 0 */
+
+ /* attach to shared memory region (SysV or BSD OS specific) */
+ if (ShmemBootstrap && key == PrivateIPCKey)
+ /* if we are running backend alone */
+ shmid = ShmemId;
+ else
+ shmid = IpcMemoryIdGet(IPCKeyGetBufferMemoryKey(key), ShmemSize);
+ sharedRegion = IpcMemoryAttach(shmid);
+ if (sharedRegion == NULL)
+ {
+ elog(FATAL, "AttachSharedRegion: couldn't attach to shmem\n");
+ return (FALSE);
+ }
+
+ /* get pointers to the dimensions of shared memory */
+ ShmemBase = (unsigned long) sharedRegion;
+ ShmemEnd = (unsigned long) sharedRegion + ShmemSize;
+ currFreeSpace = 0;
+
+ /* First long in shared memory is the count of available space */
+ ShmemFreeStart = (unsigned long *) ShmemBase;
+ /* next is a shmem pointer to the binding table */
+ ShmemBindingTabOffset = ShmemFreeStart + 1;
+
+ currFreeSpace +=
+ sizeof(ShmemFreeStart) + sizeof(ShmemBindingTabOffset);
+
+ /*
+ * bootstrap initialize spin locks so we can start to use the
+ * allocator and binding table.
*/
-
- Assert(ShmemBootstrap);
- result->location = MAKE_OFFSET(BindingTable->hctl);
- *ShmemBindingTabOffset = result->location;
- result->size = BTABLE_SIZE;
-
- ShmemBootstrap = FALSE;
-
- } else {
- Assert(! ShmemBootstrap);
- }
- /* now release the lock acquired in ShmemHashInit */
- SpinRelease (BindingLock);
-
- Assert (result->location == MAKE_OFFSET(BindingTable->hctl));
-
- return(TRUE);
+ if (!InitSpinLocks(ShmemBootstrap, IPCKeyGetSpinLockSemaphoreKey(key)))
+ {
+ return (FALSE);
+ }
+
+ /*
+ * We have just allocated additional space for two spinlocks. Now
+ * setup the global free space count
+ */
+ if (ShmemBootstrap)
+ {
+ *ShmemFreeStart = currFreeSpace;
+ }
+
+ /* if ShmemFreeStart is NULL, then the allocator won't work */
+ Assert(*ShmemFreeStart);
+
+ /* create OR attach to the shared memory binding table */
+ info.keysize = BTABLE_KEYSIZE;
+ info.datasize = BTABLE_DATASIZE;
+ hash_flags = (HASH_ELEM);
+
+ /* This will acquire the binding table lock, but not release it. */
+ BindingTable = ShmemInitHash("BindingTable",
+ BTABLE_SIZE, BTABLE_SIZE,
+ &info, hash_flags);
+
+ if (!BindingTable)
+ {
+ elog(FATAL, "InitShmem: couldn't initialize Binding Table");
+ return (FALSE);
+ }
+
+ /*
+ * Now, check the binding table for an entry to the binding table. If
+ * there is an entry there, someone else created the table.
+ * Otherwise, we did and we have to initialize it.
+ */
+ memset(item.key, 0, BTABLE_KEYSIZE);
+ strncpy(item.key, "BindingTable", BTABLE_KEYSIZE);
+
+ result = (BindingEnt *)
+ hash_search(BindingTable, (char *) &item, HASH_ENTER, &found);
+
+
+ if (!result)
+ {
+ elog(FATAL, "InitShmem: corrupted binding table");
+ return (FALSE);
+ }
+
+ if (!found)
+ {
+
+ /*
+ * bootstrapping shmem: we have to initialize the binding table
+ * now.
+ */
+
+ Assert(ShmemBootstrap);
+ result->location = MAKE_OFFSET(BindingTable->hctl);
+ *ShmemBindingTabOffset = result->location;
+ result->size = BTABLE_SIZE;
+
+ ShmemBootstrap = FALSE;
+
+ }
+ else
+ {
+ Assert(!ShmemBootstrap);
+ }
+ /* now release the lock acquired in ShmemHashInit */
+ SpinRelease(BindingLock);
+
+ Assert(result->location == MAKE_OFFSET(BindingTable->hctl));
+
+ return (TRUE);
}
/*
* ShmemAlloc -- allocate word-aligned byte string from
- * shared memory
+ * shared memory
*
* Assumes ShmemLock and ShmemFreeStart are initialized.
* Returns: real pointer to memory or NULL if we are out
- * of space. Has to return a real pointer in order
- * to be compatable with malloc().
+ * of space. Has to return a real pointer in order
+ * to be compatable with malloc().
*/
-long *
+long *
ShmemAlloc(unsigned long size)
{
- unsigned long tmpFree;
- long *newSpace;
-
- /*
- * ensure space is word aligned.
- *
- * Word-alignment is not good enough. We have to be more
- * conservative: doubles need 8-byte alignment. (We probably only need
- * this on RISC platforms but this is not a big waste of space.)
- * - ay 12/94
- */
- if (size % sizeof(double))
- size += sizeof(double) - (size % sizeof(double));
-
- Assert(*ShmemFreeStart);
-
- SpinAcquire(ShmemLock);
-
- tmpFree = *ShmemFreeStart + size;
- if (tmpFree <= ShmemSize) {
- newSpace = (long *)MAKE_PTR(*ShmemFreeStart);
- *ShmemFreeStart += size;
- } else {
- newSpace = NULL;
- }
-
- SpinRelease(ShmemLock);
-
- if (! newSpace) {
- elog(NOTICE,"ShmemAlloc: out of memory ");
- }
- return(newSpace);
+ unsigned long tmpFree;
+ long *newSpace;
+
+ /*
+ * ensure space is word aligned.
+ *
+ * Word-alignment is not good enough. We have to be more conservative:
+ * doubles need 8-byte alignment. (We probably only need this on RISC
+ * platforms but this is not a big waste of space.) - ay 12/94
+ */
+ if (size % sizeof(double))
+ size += sizeof(double) - (size % sizeof(double));
+
+ Assert(*ShmemFreeStart);
+
+ SpinAcquire(ShmemLock);
+
+ tmpFree = *ShmemFreeStart + size;
+ if (tmpFree <= ShmemSize)
+ {
+ newSpace = (long *) MAKE_PTR(*ShmemFreeStart);
+ *ShmemFreeStart += size;
+ }
+ else
+ {
+ newSpace = NULL;
+ }
+
+ SpinRelease(ShmemLock);
+
+ if (!newSpace)
+ {
+ elog(NOTICE, "ShmemAlloc: out of memory ");
+ }
+ return (newSpace);
}
/*
- * ShmemIsValid -- test if an offset refers to valid shared memory
- *
+ * ShmemIsValid -- test if an offset refers to valid shared memory
+ *
* Returns TRUE if the pointer is valid.
*/
int
ShmemIsValid(unsigned long addr)
{
- return ((addr<ShmemEnd) && (addr>=ShmemBase));
+ return ((addr < ShmemEnd) && (addr >= ShmemBase));
}
/*
- * ShmemInitHash -- Create/Attach to and initialize
- * shared memory hash table.
+ * ShmemInitHash -- Create/Attach to and initialize
+ * shared memory hash table.
*
* Notes:
*
@@ -324,281 +338,308 @@ ShmemIsValid(unsigned long addr)
* table at once. Use SpinAlloc() to create a spinlock
* for the structure before creating the structure itself.
*/
-HTAB *
-ShmemInitHash(char *name, /* table string name for binding */
- long init_size, /* initial size */
- long max_size, /* max size of the table */
- HASHCTL *infoP, /* info about key and bucket size */
- int hash_flags) /* info about infoP */
+HTAB *
+ShmemInitHash(char *name, /* table string name for binding */
+ long init_size, /* initial size */
+ long max_size, /* max size of the table */
+ HASHCTL * infoP, /* info about key and bucket size */
+ int hash_flags) /* info about infoP */
{
- bool found;
- long * location;
-
- /* shared memory hash tables have a fixed max size so that the
- * control structures don't try to grow. The segbase is for
- * calculating pointer values. The shared memory allocator
- * must be specified.
- */
- infoP->segbase = (long *) ShmemBase;
- infoP->alloc = ShmemAlloc;
- infoP->max_size = max_size;
- hash_flags |= HASH_SHARED_MEM;
-
- /* look it up in the binding table */
- location =
- ShmemInitStruct(name,my_log2(max_size) + sizeof(HHDR),&found);
-
- /* binding table is corrupted. Let someone else give the
- * error message since they have more information
- */
- if (location == NULL) {
- return(0);
- }
-
- /* it already exists, attach to it rather than allocate and
- * initialize new space
- */
- if (found) {
- hash_flags |= HASH_ATTACH;
- }
-
- /* these structures were allocated or bound in ShmemInitStruct */
- /* control information and parameters */
- infoP->hctl = (long *) location;
- /* directory for hash lookup */
- infoP->dir = (long *) (location + sizeof(HHDR));
-
- return(hash_create(init_size, infoP, hash_flags));;
+ bool found;
+ long *location;
+
+ /*
+ * shared memory hash tables have a fixed max size so that the control
+ * structures don't try to grow. The segbase is for calculating
+ * pointer values. The shared memory allocator must be specified.
+ */
+ infoP->segbase = (long *) ShmemBase;
+ infoP->alloc = ShmemAlloc;
+ infoP->max_size = max_size;
+ hash_flags |= HASH_SHARED_MEM;
+
+ /* look it up in the binding table */
+ location =
+ ShmemInitStruct(name, my_log2(max_size) + sizeof(HHDR), &found);
+
+ /*
+ * binding table is corrupted. Let someone else give the error
+ * message since they have more information
+ */
+ if (location == NULL)
+ {
+ return (0);
+ }
+
+ /*
+ * it already exists, attach to it rather than allocate and initialize
+ * new space
+ */
+ if (found)
+ {
+ hash_flags |= HASH_ATTACH;
+ }
+
+ /* these structures were allocated or bound in ShmemInitStruct */
+ /* control information and parameters */
+ infoP->hctl = (long *) location;
+ /* directory for hash lookup */
+ infoP->dir = (long *) (location + sizeof(HHDR));
+
+ return (hash_create(init_size, infoP, hash_flags));;
}
/*
* ShmemPIDLookup -- lookup process data structure using process id
*
* Returns: TRUE if no error. locationPtr is initialized if PID is
- * found in the binding table.
+ * found in the binding table.
*
* NOTES:
- * only information about success or failure is the value of
- * locationPtr.
+ * only information about success or failure is the value of
+ * locationPtr.
*/
bool
-ShmemPIDLookup(int pid, SHMEM_OFFSET* locationPtr)
+ShmemPIDLookup(int pid, SHMEM_OFFSET * locationPtr)
{
- BindingEnt * result,item;
- bool found;
-
- Assert (BindingTable);
- memset(item.key, 0, BTABLE_KEYSIZE);
- sprintf(item.key,"PID %d",pid);
-
- SpinAcquire(BindingLock);
- result = (BindingEnt *)
- hash_search(BindingTable,(char *) &item, HASH_ENTER, &found);
-
- if (! result) {
-
+ BindingEnt *result,
+ item;
+ bool found;
+
+ Assert(BindingTable);
+ memset(item.key, 0, BTABLE_KEYSIZE);
+ sprintf(item.key, "PID %d", pid);
+
+ SpinAcquire(BindingLock);
+ result = (BindingEnt *)
+ hash_search(BindingTable, (char *) &item, HASH_ENTER, &found);
+
+ if (!result)
+ {
+
+ SpinRelease(BindingLock);
+ elog(WARN, "ShmemInitPID: BindingTable corrupted");
+ return (FALSE);
+
+ }
+
+ if (found)
+ {
+ *locationPtr = result->location;
+ }
+ else
+ {
+ result->location = *locationPtr;
+ }
+
SpinRelease(BindingLock);
- elog(WARN,"ShmemInitPID: BindingTable corrupted");
- return(FALSE);
-
- }
-
- if (found) {
- *locationPtr = result->location;
- } else {
- result->location = *locationPtr;
- }
-
- SpinRelease(BindingLock);
- return (TRUE);
+ return (TRUE);
}
/*
* ShmemPIDDestroy -- destroy binding table entry for process
- * using process id
+ * using process id
*
* Returns: offset of the process struct in shared memory or
- * INVALID_OFFSET if not found.
+ * INVALID_OFFSET if not found.
*
* Side Effect: removes the entry from the binding table
*/
SHMEM_OFFSET
ShmemPIDDestroy(int pid)
{
- BindingEnt * result,item;
- bool found;
- SHMEM_OFFSET location = 0;
-
- Assert(BindingTable);
-
- memset(item.key, 0, BTABLE_KEYSIZE);
- sprintf(item.key,"PID %d",pid);
-
- SpinAcquire(BindingLock);
- result = (BindingEnt *)
- hash_search(BindingTable,(char *) &item, HASH_REMOVE, &found);
-
- if (found)
- location = result->location;
- SpinRelease(BindingLock);
-
- if (! result) {
-
- elog(WARN,"ShmemPIDDestroy: PID table corrupted");
- return(INVALID_OFFSET);
-
- }
-
- if (found)
- return (location);
- else {
- return(INVALID_OFFSET);
- }
+ BindingEnt *result,
+ item;
+ bool found;
+ SHMEM_OFFSET location = 0;
+
+ Assert(BindingTable);
+
+ memset(item.key, 0, BTABLE_KEYSIZE);
+ sprintf(item.key, "PID %d", pid);
+
+ SpinAcquire(BindingLock);
+ result = (BindingEnt *)
+ hash_search(BindingTable, (char *) &item, HASH_REMOVE, &found);
+
+ if (found)
+ location = result->location;
+ SpinRelease(BindingLock);
+
+ if (!result)
+ {
+
+ elog(WARN, "ShmemPIDDestroy: PID table corrupted");
+ return (INVALID_OFFSET);
+
+ }
+
+ if (found)
+ return (location);
+ else
+ {
+ return (INVALID_OFFSET);
+ }
}
/*
* ShmemInitStruct -- Create/attach to a structure in shared
- * memory.
+ * memory.
*
- * This is called during initialization to find or allocate
- * a data structure in shared memory. If no other processes
- * have created the structure, this routine allocates space
- * for it. If it exists already, a pointer to the existing
- * table is returned.
+ * This is called during initialization to find or allocate
+ * a data structure in shared memory. If no other processes
+ * have created the structure, this routine allocates space
+ * for it. If it exists already, a pointer to the existing
+ * table is returned.
*
- * Returns: real pointer to the object. FoundPtr is TRUE if
- * the object is already in the binding table (hence, already
- * initialized).
+ * Returns: real pointer to the object. FoundPtr is TRUE if
+ * the object is already in the binding table (hence, already
+ * initialized).
*/
-long *
-ShmemInitStruct(char *name, unsigned long size, bool *foundPtr)
+long *
+ShmemInitStruct(char *name, unsigned long size, bool * foundPtr)
{
- BindingEnt * result,item;
- long * structPtr;
-
- strncpy(item.key,name,BTABLE_KEYSIZE);
- item.location = BAD_LOCATION;
-
- SpinAcquire(BindingLock);
-
- if (! BindingTable) {
- /* Assert() is a macro now. substitutes inside quotes. */
-#ifndef NO_ASSERT_CHECKING
- char *strname = "BindingTable";
+ BindingEnt *result,
+ item;
+ long *structPtr;
+
+ strncpy(item.key, name, BTABLE_KEYSIZE);
+ item.location = BAD_LOCATION;
+
+ SpinAcquire(BindingLock);
+
+ if (!BindingTable)
+ {
+ /* Assert() is a macro now. substitutes inside quotes. */
+#ifndef NO_ASSERT_CHECKING
+ char *strname = "BindingTable";
+
#endif
-
- /* If the binding table doesnt exist, we fake it.
- *
- * If we are creating the first binding table, then let
- * shmemalloc() allocate the space for a new HTAB. Otherwise,
- * find the old one and return that. Notice that the
- * BindingLock is held until the binding table has been completely
- * initialized.
- */
- Assert (! strcmp(name,strname)) ;
- if (ShmemBootstrap) {
- /* in POSTMASTER/Single process */
-
- *foundPtr = FALSE;
- return((long *)ShmemAlloc(size));
-
- } else {
- Assert (ShmemBindingTabOffset);
-
- *foundPtr = TRUE;
- return((long *)MAKE_PTR(*ShmemBindingTabOffset));
+
+ /*
+ * If the binding table doesnt exist, we fake it.
+ *
+ * If we are creating the first binding table, then let shmemalloc()
+ * allocate the space for a new HTAB. Otherwise, find the old one
+ * and return that. Notice that the BindingLock is held until the
+ * binding table has been completely initialized.
+ */
+ Assert(!strcmp(name, strname));
+ if (ShmemBootstrap)
+ {
+ /* in POSTMASTER/Single process */
+
+ *foundPtr = FALSE;
+ return ((long *) ShmemAlloc(size));
+
+ }
+ else
+ {
+ Assert(ShmemBindingTabOffset);
+
+ *foundPtr = TRUE;
+ return ((long *) MAKE_PTR(*ShmemBindingTabOffset));
+ }
+
+
}
-
-
- } else {
- /* look it up in the bindint table */
- result = (BindingEnt *)
- hash_search(BindingTable,(char *) &item,HASH_ENTER, foundPtr);
- }
-
- if (! result) {
-
- SpinRelease(BindingLock);
-
- elog(WARN,"ShmemInitStruct: Binding Table corrupted");
- return(NULL);
-
- } else if (*foundPtr) {
- /*
- * Structure is in the binding table so someone else has allocated
- * it already. The size better be the same as the size we are
- * trying to initialize to or there is a name conflict (or worse).
- */
- if (result->size != size) {
- SpinRelease(BindingLock);
-
- elog(NOTICE,"ShmemInitStruct: BindingTable entry size is wrong");
- /* let caller print its message too */
- return(NULL);
+ else
+ {
+ /* look it up in the bindint table */
+ result = (BindingEnt *)
+ hash_search(BindingTable, (char *) &item, HASH_ENTER, foundPtr);
+ }
+
+ if (!result)
+ {
+
+ SpinRelease(BindingLock);
+
+ elog(WARN, "ShmemInitStruct: Binding Table corrupted");
+ return (NULL);
+
}
- structPtr = (long *)MAKE_PTR(result->location);
- } else {
-
- /* It isn't in the table yet. allocate and initialize it */
- structPtr = ShmemAlloc((long)size);
- if (! structPtr) {
- /* out of memory */
- Assert (BindingTable);
- hash_search(BindingTable,(char *) &item,HASH_REMOVE, foundPtr);
- SpinRelease(BindingLock);
- *foundPtr = FALSE;
-
- elog(NOTICE,"ShmemInitStruct: cannot allocate '%s'",
- name);
- return(NULL);
- }
- result->size = size;
- result->location = MAKE_OFFSET(structPtr);
- }
- Assert (ShmemIsValid((unsigned long)structPtr));
-
- SpinRelease(BindingLock);
- return(structPtr);
+ else if (*foundPtr)
+ {
+
+ /*
+ * Structure is in the binding table so someone else has allocated
+ * it already. The size better be the same as the size we are
+ * trying to initialize to or there is a name conflict (or worse).
+ */
+ if (result->size != size)
+ {
+ SpinRelease(BindingLock);
+
+ elog(NOTICE, "ShmemInitStruct: BindingTable entry size is wrong");
+ /* let caller print its message too */
+ return (NULL);
+ }
+ structPtr = (long *) MAKE_PTR(result->location);
+ }
+ else
+ {
+
+ /* It isn't in the table yet. allocate and initialize it */
+ structPtr = ShmemAlloc((long) size);
+ if (!structPtr)
+ {
+ /* out of memory */
+ Assert(BindingTable);
+ hash_search(BindingTable, (char *) &item, HASH_REMOVE, foundPtr);
+ SpinRelease(BindingLock);
+ *foundPtr = FALSE;
+
+ elog(NOTICE, "ShmemInitStruct: cannot allocate '%s'",
+ name);
+ return (NULL);
+ }
+ result->size = size;
+ result->location = MAKE_OFFSET(structPtr);
+ }
+ Assert(ShmemIsValid((unsigned long) structPtr));
+
+ SpinRelease(BindingLock);
+ return (structPtr);
}
/*
* TransactionIdIsInProgress -- is given transaction running by some backend
*
- * Strange place for this func, but we have to lookup process data structures
+ * Strange place for this func, but we have to lookup process data structures
* for all running backends. - vadim 11/26/96
*/
bool
-TransactionIdIsInProgress (TransactionId xid)
+TransactionIdIsInProgress(TransactionId xid)
{
- BindingEnt *result;
- PROC *proc;
-
- Assert (BindingTable);
-
- SpinAcquire(BindingLock);
-
- hash_seq ((HTAB *)NULL);
- while ( (result = (BindingEnt *) hash_seq (BindingTable)) != NULL )
- {
- if ( result == (BindingEnt *) TRUE )
- {
- SpinRelease(BindingLock);
- return (false);
- }
- if ( result->location == INVALID_OFFSET ||
- strncmp (result->key, "PID ", 4) != 0 )
- continue;
- proc = (PROC *) MAKE_PTR (result->location);
- if ( proc->xid == xid )
- {
- SpinRelease(BindingLock);
- return (true);
+ BindingEnt *result;
+ PROC *proc;
+
+ Assert(BindingTable);
+
+ SpinAcquire(BindingLock);
+
+ hash_seq((HTAB *) NULL);
+ while ((result = (BindingEnt *) hash_seq(BindingTable)) != NULL)
+ {
+ if (result == (BindingEnt *) TRUE)
+ {
+ SpinRelease(BindingLock);
+ return (false);
+ }
+ if (result->location == INVALID_OFFSET ||
+ strncmp(result->key, "PID ", 4) != 0)
+ continue;
+ proc = (PROC *) MAKE_PTR(result->location);
+ if (proc->xid == xid)
+ {
+ SpinRelease(BindingLock);
+ return (true);
+ }
}
- }
-
- SpinRelease(BindingLock);
- elog (WARN,"TransactionIdIsInProgress: BindingTable corrupted");
- return (false);
-}
+ SpinRelease(BindingLock);
+ elog(WARN, "TransactionIdIsInProgress: BindingTable corrupted");
+ return (false);
+}
diff --git a/src/backend/storage/ipc/shmqueue.c b/src/backend/storage/ipc/shmqueue.c
index f727b5719f5..8080fc70208 100644
--- a/src/backend/storage/ipc/shmqueue.c
+++ b/src/backend/storage/ipc/shmqueue.c
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* shmqueue.c--
- * shared memory linked lists
+ * shared memory linked lists
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.3 1997/08/19 21:33:06 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmqueue.c,v 1.4 1997/09/07 04:48:42 momjian Exp $
*
* NOTES
*
* Package for managing doubly-linked lists in shared memory.
- * The only tricky thing is that SHM_QUEUE will usually be a field
- * in a larger record. SHMQueueGetFirst has to return a pointer
+ * The only tricky thing is that SHM_QUEUE will usually be a field
+ * in a larger record. SHMQueueGetFirst has to return a pointer
* to the record itself instead of a pointer to the SHMQueue field
* of the record. It takes an extra pointer and does some extra
* pointer arithmetic to do this correctly.
@@ -22,178 +22,181 @@
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include "postgres.h"
-#include "storage/shmem.h" /* where the declarations go */
+#include "storage/shmem.h" /* where the declarations go */
/*#define SHMQUEUE_DEBUG*/
#ifdef SHMQUEUE_DEBUG
-#define SHMQUEUE_DEBUG_DEL /* deletions */
-#define SHMQUEUE_DEBUG_HD /* head inserts */
-#define SHMQUEUE_DEBUG_TL /* tail inserts */
+#define SHMQUEUE_DEBUG_DEL /* deletions */
+#define SHMQUEUE_DEBUG_HD /* head inserts */
+#define SHMQUEUE_DEBUG_TL /* tail inserts */
#define SHMQUEUE_DEBUG_ELOG NOTICE
-#endif /* SHMQUEUE_DEBUG */
+#endif /* SHMQUEUE_DEBUG */
/*
* ShmemQueueInit -- make the head of a new queue point
- * to itself
+ * to itself
*/
void
-SHMQueueInit(SHM_QUEUE *queue)
+SHMQueueInit(SHM_QUEUE * queue)
{
- Assert(SHM_PTR_VALID(queue));
- (queue)->prev = (queue)->next = MAKE_OFFSET(queue);
+ Assert(SHM_PTR_VALID(queue));
+ (queue)->prev = (queue)->next = MAKE_OFFSET(queue);
}
/*
* SHMQueueIsDetached -- TRUE if element is not currently
- * in a queue.
+ * in a queue.
*/
#ifdef NOT_USED
bool
-SHMQueueIsDetached(SHM_QUEUE *queue)
+SHMQueueIsDetached(SHM_QUEUE * queue)
{
- Assert(SHM_PTR_VALID(queue));
- return ((queue)->prev == INVALID_OFFSET);
+ Assert(SHM_PTR_VALID(queue));
+ return ((queue)->prev == INVALID_OFFSET);
}
+
#endif
/*
* SHMQueueElemInit -- clear an element's links
*/
void
-SHMQueueElemInit(SHM_QUEUE *queue)
+SHMQueueElemInit(SHM_QUEUE * queue)
{
- Assert(SHM_PTR_VALID(queue));
- (queue)->prev = (queue)->next = INVALID_OFFSET;
+ Assert(SHM_PTR_VALID(queue));
+ (queue)->prev = (queue)->next = INVALID_OFFSET;
}
/*
* SHMQueueDelete -- remove an element from the queue and
- * close the links
+ * close the links
*/
void
-SHMQueueDelete(SHM_QUEUE *queue)
+SHMQueueDelete(SHM_QUEUE * queue)
{
- SHM_QUEUE *nextElem = (SHM_QUEUE *) MAKE_PTR((queue)->next);
- SHM_QUEUE *prevElem = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
-
- Assert(SHM_PTR_VALID(queue));
- Assert(SHM_PTR_VALID(nextElem));
- Assert(SHM_PTR_VALID(prevElem));
-
+ SHM_QUEUE *nextElem = (SHM_QUEUE *) MAKE_PTR((queue)->next);
+ SHM_QUEUE *prevElem = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
+
+ Assert(SHM_PTR_VALID(queue));
+ Assert(SHM_PTR_VALID(nextElem));
+ Assert(SHM_PTR_VALID(prevElem));
+
#ifdef SHMQUEUE_DEBUG_DEL
- dumpQ(queue, "in SHMQueueDelete: begin");
-#endif /* SHMQUEUE_DEBUG_DEL */
-
- prevElem->next = (queue)->next;
- nextElem->prev = (queue)->prev;
-
+ dumpQ(queue, "in SHMQueueDelete: begin");
+#endif /* SHMQUEUE_DEBUG_DEL */
+
+ prevElem->next = (queue)->next;
+ nextElem->prev = (queue)->prev;
+
#ifdef SHMQUEUE_DEBUG_DEL
- dumpQ((SHM_QUEUE *)MAKE_PTR(queue->prev), "in SHMQueueDelete: end");
-#endif /* SHMQUEUE_DEBUG_DEL */
+ dumpQ((SHM_QUEUE *) MAKE_PTR(queue->prev), "in SHMQueueDelete: end");
+#endif /* SHMQUEUE_DEBUG_DEL */
}
#ifdef SHMQUEUE_DEBUG
void
-dumpQ(SHM_QUEUE *q, char *s)
+dumpQ(SHM_QUEUE * q, char *s)
{
- char elem[16];
- char buf[1024];
- SHM_QUEUE *start = q;
- int count = 0;
-
- sprintf(buf, "q prevs: %x", MAKE_OFFSET(q));
- q = (SHM_QUEUE *)MAKE_PTR(q->prev);
- while (q != start)
+ char elem[16];
+ char buf[1024];
+ SHM_QUEUE *start = q;
+ int count = 0;
+
+ sprintf(buf, "q prevs: %x", MAKE_OFFSET(q));
+ q = (SHM_QUEUE *) MAKE_PTR(q->prev);
+ while (q != start)
{
- sprintf(elem, "--->%x", MAKE_OFFSET(q));
- strcat(buf, elem);
- q = (SHM_QUEUE *)MAKE_PTR(q->prev);
- if (q->prev == MAKE_OFFSET(q))
- break;
- if (count++ > 40)
+ sprintf(elem, "--->%x", MAKE_OFFSET(q));
+ strcat(buf, elem);
+ q = (SHM_QUEUE *) MAKE_PTR(q->prev);
+ if (q->prev == MAKE_OFFSET(q))
+ break;
+ if (count++ > 40)
{
- strcat(buf, "BAD PREV QUEUE!!");
- break;
+ strcat(buf, "BAD PREV QUEUE!!");
+ break;
}
}
- sprintf(elem, "--->%x", MAKE_OFFSET(q));
- strcat(buf, elem);
- elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
-
- sprintf(buf, "q nexts: %x", MAKE_OFFSET(q));
- count = 0;
- q = (SHM_QUEUE *)MAKE_PTR(q->next);
- while (q != start)
+ sprintf(elem, "--->%x", MAKE_OFFSET(q));
+ strcat(buf, elem);
+ elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
+
+ sprintf(buf, "q nexts: %x", MAKE_OFFSET(q));
+ count = 0;
+ q = (SHM_QUEUE *) MAKE_PTR(q->next);
+ while (q != start)
{
- sprintf(elem, "--->%x", MAKE_OFFSET(q));
- strcat(buf, elem);
- q = (SHM_QUEUE *)MAKE_PTR(q->next);
- if (q->next == MAKE_OFFSET(q))
- break;
- if (count++ > 10)
+ sprintf(elem, "--->%x", MAKE_OFFSET(q));
+ strcat(buf, elem);
+ q = (SHM_QUEUE *) MAKE_PTR(q->next);
+ if (q->next == MAKE_OFFSET(q))
+ break;
+ if (count++ > 10)
{
- strcat(buf, "BAD NEXT QUEUE!!");
- break;
+ strcat(buf, "BAD NEXT QUEUE!!");
+ break;
}
}
- sprintf(elem, "--->%x", MAKE_OFFSET(q));
- strcat(buf, elem);
- elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
+ sprintf(elem, "--->%x", MAKE_OFFSET(q));
+ strcat(buf, elem);
+ elog(SHMQUEUE_DEBUG_ELOG, "%s: %s", s, buf);
}
-#endif /* SHMQUEUE_DEBUG */
+
+#endif /* SHMQUEUE_DEBUG */
/*
* SHMQueueInsertHD -- put elem in queue between the queue head
- * and its "prev" element.
+ * and its "prev" element.
*/
#ifdef NOT_USED
void
-SHMQueueInsertHD(SHM_QUEUE *queue, SHM_QUEUE *elem)
+SHMQueueInsertHD(SHM_QUEUE * queue, SHM_QUEUE * elem)
{
- SHM_QUEUE *prevPtr = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
- SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
-
- Assert(SHM_PTR_VALID(queue));
- Assert(SHM_PTR_VALID(elem));
-
+ SHM_QUEUE *prevPtr = (SHM_QUEUE *) MAKE_PTR((queue)->prev);
+ SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
+
+ Assert(SHM_PTR_VALID(queue));
+ Assert(SHM_PTR_VALID(elem));
+
#ifdef SHMQUEUE_DEBUG_HD
- dumpQ(queue, "in SHMQueueInsertHD: begin");
-#endif /* SHMQUEUE_DEBUG_HD */
-
- (elem)->next = prevPtr->next;
- (elem)->prev = queue->prev;
- (queue)->prev = elemOffset;
- prevPtr->next = elemOffset;
-
+ dumpQ(queue, "in SHMQueueInsertHD: begin");
+#endif /* SHMQUEUE_DEBUG_HD */
+
+ (elem)->next = prevPtr->next;
+ (elem)->prev = queue->prev;
+ (queue)->prev = elemOffset;
+ prevPtr->next = elemOffset;
+
#ifdef SHMQUEUE_DEBUG_HD
- dumpQ(queue, "in SHMQueueInsertHD: end");
-#endif /* SHMQUEUE_DEBUG_HD */
+ dumpQ(queue, "in SHMQueueInsertHD: end");
+#endif /* SHMQUEUE_DEBUG_HD */
}
+
#endif
void
-SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem)
+SHMQueueInsertTL(SHM_QUEUE * queue, SHM_QUEUE * elem)
{
- SHM_QUEUE *nextPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
- SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
-
- Assert(SHM_PTR_VALID(queue));
- Assert(SHM_PTR_VALID(elem));
-
+ SHM_QUEUE *nextPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
+ SHMEM_OFFSET elemOffset = MAKE_OFFSET(elem);
+
+ Assert(SHM_PTR_VALID(queue));
+ Assert(SHM_PTR_VALID(elem));
+
#ifdef SHMQUEUE_DEBUG_TL
- dumpQ(queue, "in SHMQueueInsertTL: begin");
-#endif /* SHMQUEUE_DEBUG_TL */
-
- (elem)->prev = nextPtr->prev;
- (elem)->next = queue->next;
- (queue)->next = elemOffset;
- nextPtr->prev = elemOffset;
-
+ dumpQ(queue, "in SHMQueueInsertTL: begin");
+#endif /* SHMQUEUE_DEBUG_TL */
+
+ (elem)->prev = nextPtr->prev;
+ (elem)->next = queue->next;
+ (queue)->next = elemOffset;
+ nextPtr->prev = elemOffset;
+
#ifdef SHMQUEUE_DEBUG_TL
- dumpQ(queue, "in SHMQueueInsertTL: end");
-#endif /* SHMQUEUE_DEBUG_TL */
+ dumpQ(queue, "in SHMQueueInsertTL: end");
+#endif /* SHMQUEUE_DEBUG_TL */
}
/*
@@ -203,52 +206,51 @@ SHMQueueInsertTL(SHM_QUEUE *queue, SHM_QUEUE *elem)
* a larger structure, we want to return a pointer to the
* whole structure rather than a pointer to its SHMQueue field.
* I.E. struct {
- * int stuff;
- * SHMQueue elem;
- * } ELEMType;
+ * int stuff;
+ * SHMQueue elem;
+ * } ELEMType;
* when this element is in a queue (queue->next) is struct.elem.
* nextQueue allows us to calculate the offset of the SHMQueue
* field in the structure.
*
* call to SHMQueueFirst should take these parameters:
*
- * &(queueHead),&firstElem,&(firstElem->next)
+ * &(queueHead),&firstElem,&(firstElem->next)
*
* Note that firstElem may well be uninitialized. if firstElem
* is initially K, &(firstElem->next) will be K+ the offset to
* next.
*/
void
-SHMQueueFirst(SHM_QUEUE *queue, Pointer *nextPtrPtr, SHM_QUEUE *nextQueue)
+SHMQueueFirst(SHM_QUEUE * queue, Pointer * nextPtrPtr, SHM_QUEUE * nextQueue)
{
- SHM_QUEUE *elemPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
-
- Assert(SHM_PTR_VALID(queue));
- *nextPtrPtr = (Pointer) (((unsigned long) *nextPtrPtr) +
- ((unsigned long) elemPtr) - ((unsigned long) nextQueue));
-
- /*
- nextPtrPtr a ptr to a structure linked in the queue
- nextQueue is the SHMQueue field of the structure
- *nextPtrPtr - nextQueue is 0 minus the offset of the queue
- field n the record
- elemPtr + (*nextPtrPtr - nexQueue) is the start of the
- structure containing elemPtr.
- */
+ SHM_QUEUE *elemPtr = (SHM_QUEUE *) MAKE_PTR((queue)->next);
+
+ Assert(SHM_PTR_VALID(queue));
+ *nextPtrPtr = (Pointer) (((unsigned long) *nextPtrPtr) +
+ ((unsigned long) elemPtr) - ((unsigned long) nextQueue));
+
+ /*
+ * nextPtrPtr a ptr to a structure linked in the queue nextQueue is
+ * the SHMQueue field of the structure nextPtrPtr - nextQueue is 0
+ * minus the offset of the queue field n the record elemPtr +
+ * (*nextPtrPtr - nexQueue) is the start of the structure containing
+ * elemPtr.
+ */
}
/*
* SHMQueueEmpty -- TRUE if queue head is only element, FALSE otherwise
*/
bool
-SHMQueueEmpty(SHM_QUEUE *queue)
+SHMQueueEmpty(SHM_QUEUE * queue)
{
- Assert(SHM_PTR_VALID(queue));
-
- if (queue->prev == MAKE_OFFSET(queue))
+ Assert(SHM_PTR_VALID(queue));
+
+ if (queue->prev == MAKE_OFFSET(queue))
{
- Assert(queue->next = MAKE_OFFSET(queue));
- return(TRUE);
+ Assert(queue->next = MAKE_OFFSET(queue));
+ return (TRUE);
}
- return(FALSE);
+ return (FALSE);
}
diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c
index 5f391669113..af16c8a7196 100644
--- a/src/backend/storage/ipc/sinval.c
+++ b/src/backend/storage/ipc/sinval.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* sinval.c--
- * POSTGRES shared cache invalidation communication code.
+ * POSTGRES shared cache invalidation communication code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.7 1997/08/12 22:53:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v 1.8 1997/09/07 04:48:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-/* #define INVALIDDEBUG 1 */
+/* #define INVALIDDEBUG 1 */
#include <sys/types.h>
@@ -22,150 +22,156 @@
#include "storage/sinvaladt.h"
#include "storage/spin.h"
-extern SISeg *shmInvalBuffer;/* the shared buffer segment, set by*/
- /* SISegmentAttach() */
-extern BackendId MyBackendId;
-extern BackendTag MyBackendTag;
+extern SISeg *shmInvalBuffer; /* the shared buffer segment, set by */
+
+ /* SISegmentAttach() */
+extern BackendId MyBackendId;
+extern BackendTag MyBackendTag;
SPINLOCK SInvalLock = (SPINLOCK) NULL;
/****************************************************************************/
-/* CreateSharedInvalidationState(key) Create a buffer segment */
-/* */
-/* should be called only by the POSTMASTER */
+/* CreateSharedInvalidationState(key) Create a buffer segment */
+/* */
+/* should be called only by the POSTMASTER */
/****************************************************************************/
void
CreateSharedInvalidationState(IPCKey key)
{
- int status;
-
- /* REMOVED
- SISyncKill(IPCKeyGetSIBufferMemorySemaphoreKey(key));
- SISyncInit(IPCKeyGetSIBufferMemorySemaphoreKey(key));
- */
-
- /* SInvalLock gets set in spin.c, during spinlock init */
- status = SISegmentInit(true, IPCKeyGetSIBufferMemoryBlock(key));
-
- if (status == -1) {
- elog(FATAL, "CreateSharedInvalidationState: failed segment init");
- }
+ int status;
+
+ /*
+ * REMOVED SISyncKill(IPCKeyGetSIBufferMemorySemaphoreKey(key));
+ * SISyncInit(IPCKeyGetSIBufferMemorySemaphoreKey(key));
+ */
+
+ /* SInvalLock gets set in spin.c, during spinlock init */
+ status = SISegmentInit(true, IPCKeyGetSIBufferMemoryBlock(key));
+
+ if (status == -1)
+ {
+ elog(FATAL, "CreateSharedInvalidationState: failed segment init");
+ }
}
+
/****************************************************************************/
-/* AttachSharedInvalidationState(key) Attach a buffer segment */
-/* */
-/* should be called only by the POSTMASTER */
+/* AttachSharedInvalidationState(key) Attach a buffer segment */
+/* */
+/* should be called only by the POSTMASTER */
/****************************************************************************/
void
AttachSharedInvalidationState(IPCKey key)
{
- int status;
-
- if (key == PrivateIPCKey) {
- CreateSharedInvalidationState(key);
- return;
- }
- /* SInvalLock gets set in spin.c, during spinlock init */
- status = SISegmentInit(false, IPCKeyGetSIBufferMemoryBlock(key));
-
- if (status == -1) {
- elog(FATAL, "AttachSharedInvalidationState: failed segment init");
- }
+ int status;
+
+ if (key == PrivateIPCKey)
+ {
+ CreateSharedInvalidationState(key);
+ return;
+ }
+ /* SInvalLock gets set in spin.c, during spinlock init */
+ status = SISegmentInit(false, IPCKeyGetSIBufferMemoryBlock(key));
+
+ if (status == -1)
+ {
+ elog(FATAL, "AttachSharedInvalidationState: failed segment init");
+ }
}
void
InitSharedInvalidationState(void)
{
- SpinAcquire(SInvalLock);
- if (!SIBackendInit(shmInvalBuffer))
+ SpinAcquire(SInvalLock);
+ if (!SIBackendInit(shmInvalBuffer))
{
- SpinRelease(SInvalLock);
- elog(FATAL, "Backend cache invalidation initialization failed");
+ SpinRelease(SInvalLock);
+ elog(FATAL, "Backend cache invalidation initialization failed");
}
- SpinRelease(SInvalLock);
+ SpinRelease(SInvalLock);
}
/*
* RegisterSharedInvalid --
- * Returns a new local cache invalidation state containing a new entry.
+ * Returns a new local cache invalidation state containing a new entry.
*
* Note:
- * Assumes hash index is valid.
- * Assumes item pointer is valid.
+ * Assumes hash index is valid.
+ * Assumes item pointer is valid.
*/
/****************************************************************************/
-/* RegisterSharedInvalid(cacheId, hashIndex, pointer) */
-/* */
-/* register a message in the buffer */
-/* should be called by a backend */
+/* RegisterSharedInvalid(cacheId, hashIndex, pointer) */
+/* */
+/* register a message in the buffer */
+/* should be called by a backend */
/****************************************************************************/
void
-RegisterSharedInvalid(int cacheId, /* XXX */
- Index hashIndex,
- ItemPointer pointer)
+RegisterSharedInvalid(int cacheId, /* XXX */
+ Index hashIndex,
+ ItemPointer pointer)
{
- SharedInvalidData newInvalid;
-
- /*
- * This code has been hacked to accept two types of messages. This might
- * be treated more generally in the future.
- *
- * (1)
- * cacheId= system cache id
- * hashIndex= system cache hash index for a (possibly) cached tuple
- * pointer= pointer of (possibly) cached tuple
- *
- * (2)
- * cacheId= special non-syscache id
- * hashIndex= object id contained in (possibly) cached relation descriptor
- * pointer= null
- */
-
- newInvalid.cacheId = cacheId;
- newInvalid.hashIndex = hashIndex;
-
- if (ItemPointerIsValid(pointer)) {
- ItemPointerCopy(pointer, &newInvalid.pointerData);
- } else {
- ItemPointerSetInvalid(&newInvalid.pointerData);
- }
-
- SpinAcquire(SInvalLock);
- if (!SISetDataEntry(shmInvalBuffer, &newInvalid)) {
- /* buffer full */
- /* release a message, mark process cache states to be invalid */
- SISetProcStateInvalid(shmInvalBuffer);
-
- if (!SIDelDataEntry(shmInvalBuffer)) {
- /* inconsistent buffer state -- shd never happen */
- SpinRelease(SInvalLock);
- elog(FATAL, "RegisterSharedInvalid: inconsistent buffer state");
- }
-
- /* write again */
- SISetDataEntry(shmInvalBuffer, &newInvalid);
- }
- SpinRelease(SInvalLock);
+ SharedInvalidData newInvalid;
+
+ /*
+ * This code has been hacked to accept two types of messages. This
+ * might be treated more generally in the future.
+ *
+ * (1) cacheId= system cache id hashIndex= system cache hash index for a
+ * (possibly) cached tuple pointer= pointer of (possibly) cached tuple
+ *
+ * (2) cacheId= special non-syscache id hashIndex= object id contained in
+ * (possibly) cached relation descriptor pointer= null
+ */
+
+ newInvalid.cacheId = cacheId;
+ newInvalid.hashIndex = hashIndex;
+
+ if (ItemPointerIsValid(pointer))
+ {
+ ItemPointerCopy(pointer, &newInvalid.pointerData);
+ }
+ else
+ {
+ ItemPointerSetInvalid(&newInvalid.pointerData);
+ }
+
+ SpinAcquire(SInvalLock);
+ if (!SISetDataEntry(shmInvalBuffer, &newInvalid))
+ {
+ /* buffer full */
+ /* release a message, mark process cache states to be invalid */
+ SISetProcStateInvalid(shmInvalBuffer);
+
+ if (!SIDelDataEntry(shmInvalBuffer))
+ {
+ /* inconsistent buffer state -- shd never happen */
+ SpinRelease(SInvalLock);
+ elog(FATAL, "RegisterSharedInvalid: inconsistent buffer state");
+ }
+
+ /* write again */
+ SISetDataEntry(shmInvalBuffer, &newInvalid);
+ }
+ SpinRelease(SInvalLock);
}
/*
* InvalidateSharedInvalid --
- * Processes all entries in a shared cache invalidation state.
+ * Processes all entries in a shared cache invalidation state.
*/
/****************************************************************************/
-/* InvalidateSharedInvalid(invalFunction, resetFunction) */
-/* */
-/* invalidate a message in the buffer (read and clean up) */
-/* should be called by a backend */
+/* InvalidateSharedInvalid(invalFunction, resetFunction) */
+/* */
+/* invalidate a message in the buffer (read and clean up) */
+/* should be called by a backend */
/****************************************************************************/
void
-InvalidateSharedInvalid(void (*invalFunction)(),
- void (*resetFunction)())
+ InvalidateSharedInvalid(void (*invalFunction) (),
+ void (*resetFunction) ())
{
- SpinAcquire(SInvalLock);
- SIReadEntryData(shmInvalBuffer, MyBackendId,
- invalFunction, resetFunction);
-
- SIDelExpiredDataEntries(shmInvalBuffer);
- SpinRelease(SInvalLock);
+ SpinAcquire(SInvalLock);
+ SIReadEntryData(shmInvalBuffer, MyBackendId,
+ invalFunction, resetFunction);
+
+ SIDelExpiredDataEntries(shmInvalBuffer);
+ SpinRelease(SInvalLock);
}
diff --git a/src/backend/storage/ipc/sinvaladt.c b/src/backend/storage/ipc/sinvaladt.c
index 9400e872617..43c4d7c0ac2 100644
--- a/src/backend/storage/ipc/sinvaladt.c
+++ b/src/backend/storage/ipc/sinvaladt.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* sinvaladt.c--
- * POSTGRES shared cache invalidation segment definitions.
+ * POSTGRES shared cache invalidation segment definitions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.5 1997/08/12 22:54:01 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.6 1997/09/07 04:48:44 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,420 +22,445 @@
#include "utils/palloc.h"
/* ----------------
- * global variable notes
+ * global variable notes
*
- * SharedInvalidationSemaphore
+ * SharedInvalidationSemaphore
*
- * shmInvalBuffer
- * the shared buffer segment, set by SISegmentAttach()
+ * shmInvalBuffer
+ * the shared buffer segment, set by SISegmentAttach()
*
- * MyBackendId
- * might be removed later, used only for
- * debugging in debug routines (end of file)
+ * MyBackendId
+ * might be removed later, used only for
+ * debugging in debug routines (end of file)
*
- * SIDbId
- * identification of buffer (disappears)
+ * SIDbId
+ * identification of buffer (disappears)
*
- * SIRelId \
- * SIDummyOid \ identification of buffer
- * SIXidData /
- * SIXid /
+ * SIRelId \
+ * SIDummyOid \ identification of buffer
+ * SIXidData /
+ * SIXid /
*
- * XXX This file really needs to be cleaned up. We switched to using
- * spinlocks to protect critical sections (as opposed to using fake
- * relations and going through the lock manager) and some of the old
- * cruft was 'ifdef'ed out, while other parts (now unused) are still
- * compiled into the system. -mer 5/24/92
+ * XXX This file really needs to be cleaned up. We switched to using
+ * spinlocks to protect critical sections (as opposed to using fake
+ * relations and going through the lock manager) and some of the old
+ * cruft was 'ifdef'ed out, while other parts (now unused) are still
+ * compiled into the system. -mer 5/24/92
* ----------------
*/
#ifdef HAS_TEST_AND_SET
-int SharedInvalidationLockId;
+int SharedInvalidationLockId;
+
#else
IpcSemaphoreId SharedInvalidationSemaphore;
+
#endif
-SISeg *shmInvalBuffer;
+SISeg *shmInvalBuffer;
extern BackendId MyBackendId;
-static void CleanupInvalidationState(int status, SISeg *segInOutP);
-static BackendId SIAssignBackendId(SISeg *segInOutP, BackendTag backendTag);
-static int SIGetNumEntries(SISeg *segP);
+static void CleanupInvalidationState(int status, SISeg * segInOutP);
+static BackendId SIAssignBackendId(SISeg * segInOutP, BackendTag backendTag);
+static int SIGetNumEntries(SISeg * segP);
/************************************************************************/
/* SISetActiveProcess(segP, backendId) set the backend status active */
-/* should be called only by the postmaster when creating a backend */
+/* should be called only by the postmaster when creating a backend */
/************************************************************************/
/* XXX I suspect that the segP parameter is extraneous. -hirohama */
static void
-SISetActiveProcess(SISeg *segInOutP, BackendId backendId)
+SISetActiveProcess(SISeg * segInOutP, BackendId backendId)
{
- /* mark all messages as read */
-
- /* Assert(segP->procState[backendId - 1].tag == MyBackendTag); */
-
- segInOutP->procState[backendId - 1].resetState = false;
- segInOutP->procState[backendId - 1].limit = SIGetNumEntries(segInOutP);
+ /* mark all messages as read */
+
+ /* Assert(segP->procState[backendId - 1].tag == MyBackendTag); */
+
+ segInOutP->procState[backendId - 1].resetState = false;
+ segInOutP->procState[backendId - 1].limit = SIGetNumEntries(segInOutP);
}
/****************************************************************************/
-/* SIBackendInit() initializes a backend to operate on the buffer */
+/* SIBackendInit() initializes a backend to operate on the buffer */
/****************************************************************************/
int
-SIBackendInit(SISeg *segInOutP)
-{
- LRelId LtCreateRelId();
- TransactionId LMITransactionIdCopy();
-
- Assert(MyBackendTag > 0);
-
- MyBackendId = SIAssignBackendId(segInOutP, MyBackendTag);
- if (MyBackendId == InvalidBackendTag)
- return 0;
-
+SIBackendInit(SISeg * segInOutP)
+{
+ LRelId LtCreateRelId();
+ TransactionId LMITransactionIdCopy();
+
+ Assert(MyBackendTag > 0);
+
+ MyBackendId = SIAssignBackendId(segInOutP, MyBackendTag);
+ if (MyBackendId == InvalidBackendTag)
+ return 0;
+
#ifdef INVALIDDEBUG
- elog(DEBUG, "SIBackendInit: backend tag %d; backend id %d.",
- MyBackendTag, MyBackendId);
-#endif /* INVALIDDEBUG */
-
- SISetActiveProcess(segInOutP, MyBackendId);
- on_exitpg(CleanupInvalidationState, (caddr_t)segInOutP);
- return 1;
+ elog(DEBUG, "SIBackendInit: backend tag %d; backend id %d.",
+ MyBackendTag, MyBackendId);
+#endif /* INVALIDDEBUG */
+
+ SISetActiveProcess(segInOutP, MyBackendId);
+ on_exitpg(CleanupInvalidationState, (caddr_t) segInOutP);
+ return 1;
}
/* ----------------
- * SIAssignBackendId
+ * SIAssignBackendId
* ----------------
*/
-static BackendId
-SIAssignBackendId(SISeg *segInOutP, BackendTag backendTag)
-{
- Index index;
- ProcState *stateP;
-
- stateP = NULL;
-
- for (index = 0; index < MaxBackendId; index += 1) {
- if (segInOutP->procState[index].tag == InvalidBackendTag ||
- segInOutP->procState[index].tag == backendTag)
- {
- stateP = &segInOutP->procState[index];
- break;
- }
-
- if (!PointerIsValid(stateP) ||
- (segInOutP->procState[index].resetState &&
- (!stateP->resetState ||
- stateP->tag < backendTag)) ||
- (!stateP->resetState &&
- (segInOutP->procState[index].limit <
- stateP->limit ||
- stateP->tag < backendTag)))
- {
- stateP = &segInOutP->procState[index];
- }
- }
-
- /* verify that all "procState" entries checked for matching tags */
-
- for (index += 1; index < MaxBackendId; index += 1) {
- if (segInOutP->procState[index].tag == backendTag) {
- elog (FATAL, "SIAssignBackendId: tag %d found twice",
- backendTag);
+static BackendId
+SIAssignBackendId(SISeg * segInOutP, BackendTag backendTag)
+{
+ Index index;
+ ProcState *stateP;
+
+ stateP = NULL;
+
+ for (index = 0; index < MaxBackendId; index += 1)
+ {
+ if (segInOutP->procState[index].tag == InvalidBackendTag ||
+ segInOutP->procState[index].tag == backendTag)
+ {
+ stateP = &segInOutP->procState[index];
+ break;
+ }
+
+ if (!PointerIsValid(stateP) ||
+ (segInOutP->procState[index].resetState &&
+ (!stateP->resetState ||
+ stateP->tag < backendTag)) ||
+ (!stateP->resetState &&
+ (segInOutP->procState[index].limit <
+ stateP->limit ||
+ stateP->tag < backendTag)))
+ {
+ stateP = &segInOutP->procState[index];
+ }
+ }
+
+ /* verify that all "procState" entries checked for matching tags */
+
+ for (index += 1; index < MaxBackendId; index += 1)
+ {
+ if (segInOutP->procState[index].tag == backendTag)
+ {
+ elog(FATAL, "SIAssignBackendId: tag %d found twice",
+ backendTag);
+ }
}
- }
-
- if (stateP->tag != InvalidBackendTag) {
- if (stateP->tag == backendTag) {
- elog(NOTICE, "SIAssignBackendId: reusing tag %d",
- backendTag);
- } else {
- elog(NOTICE,
- "SIAssignBackendId: discarding tag %d",
- stateP->tag);
- return InvalidBackendTag;
+
+ if (stateP->tag != InvalidBackendTag)
+ {
+ if (stateP->tag == backendTag)
+ {
+ elog(NOTICE, "SIAssignBackendId: reusing tag %d",
+ backendTag);
+ }
+ else
+ {
+ elog(NOTICE,
+ "SIAssignBackendId: discarding tag %d",
+ stateP->tag);
+ return InvalidBackendTag;
+ }
}
- }
-
- stateP->tag = backendTag;
-
- return (1 + stateP - &segInOutP->procState[0]);
+
+ stateP->tag = backendTag;
+
+ return (1 + stateP - &segInOutP->procState[0]);
}
/************************************************************************/
-/* The following function should be called only by the postmaster !! */
+/* The following function should be called only by the postmaster !! */
/************************************************************************/
/************************************************************************/
-/* SISetDeadProcess(segP, backendId) set the backend status DEAD */
-/* should be called only by the postmaster when a backend died */
+/* SISetDeadProcess(segP, backendId) set the backend status DEAD */
+/* should be called only by the postmaster when a backend died */
/************************************************************************/
static void
-SISetDeadProcess(SISeg *segP, int backendId)
+SISetDeadProcess(SISeg * segP, int backendId)
{
- /* XXX call me.... */
-
- segP->procState[backendId - 1].resetState = false;
- segP->procState[backendId - 1].limit = -1;
- segP->procState[backendId - 1].tag = InvalidBackendTag;
+ /* XXX call me.... */
+
+ segP->procState[backendId - 1].resetState = false;
+ segP->procState[backendId - 1].limit = -1;
+ segP->procState[backendId - 1].tag = InvalidBackendTag;
}
/*
* CleanupInvalidationState --
* Note:
- * This is a temporary hack. ExitBackend should call this instead
- * of exit (via on_exitpg).
+ * This is a temporary hack. ExitBackend should call this instead
+ * of exit (via on_exitpg).
*/
static void
-CleanupInvalidationState(int status, /* XXX */
- SISeg *segInOutP) /* XXX style */
+CleanupInvalidationState(int status, /* XXX */
+ SISeg * segInOutP) /* XXX style */
{
- Assert(PointerIsValid(segInOutP));
-
- SISetDeadProcess(segInOutP, MyBackendId);
+ Assert(PointerIsValid(segInOutP));
+
+ SISetDeadProcess(segInOutP, MyBackendId);
}
/************************************************************************/
-/* SIComputeSize() - retuns the size of a buffer segment */
+/* SIComputeSize() - retuns the size of a buffer segment */
/************************************************************************/
static SISegOffsets *
SIComputeSize(int *segSize)
{
- int A, B, a, b, totalSize;
- SISegOffsets *oP;
-
- A = 0;
- a = SizeSISeg; /* offset to first data entry */
- b = SizeOfOneSISegEntry * MAXNUMMESSAGES;
- B = A + a + b;
- totalSize = B - A;
- *segSize = totalSize;
-
- oP = (SISegOffsets *) palloc(sizeof(SISegOffsets));
- oP->startSegment = A;
- oP->offsetToFirstEntry = a; /* relatiove to A */
- oP->offsetToEndOfSegemnt = totalSize; /* relative to A */
- return(oP);
+ int A,
+ B,
+ a,
+ b,
+ totalSize;
+ SISegOffsets *oP;
+
+ A = 0;
+ a = SizeSISeg; /* offset to first data entry */
+ b = SizeOfOneSISegEntry * MAXNUMMESSAGES;
+ B = A + a + b;
+ totalSize = B - A;
+ *segSize = totalSize;
+
+ oP = (SISegOffsets *) palloc(sizeof(SISegOffsets));
+ oP->startSegment = A;
+ oP->offsetToFirstEntry = a; /* relatiove to A */
+ oP->offsetToEndOfSegemnt = totalSize; /* relative to A */
+ return (oP);
}
/************************************************************************/
-/* SISetStartEntrySection(segP, offset) - sets the offset */
+/* SISetStartEntrySection(segP, offset) - sets the offset */
/************************************************************************/
static void
-SISetStartEntrySection(SISeg *segP, Offset offset)
+SISetStartEntrySection(SISeg * segP, Offset offset)
{
- segP->startEntrySection = offset;
+ segP->startEntrySection = offset;
}
/************************************************************************/
-/* SIGetStartEntrySection(segP) - returnss the offset */
+/* SIGetStartEntrySection(segP) - returnss the offset */
/************************************************************************/
-static Offset
-SIGetStartEntrySection(SISeg *segP)
+static Offset
+SIGetStartEntrySection(SISeg * segP)
{
- return(segP->startEntrySection);
+ return (segP->startEntrySection);
}
/************************************************************************/
-/* SISetEndEntrySection(segP, offset) - sets the offset */
+/* SISetEndEntrySection(segP, offset) - sets the offset */
/************************************************************************/
static void
-SISetEndEntrySection(SISeg *segP, Offset offset)
+SISetEndEntrySection(SISeg * segP, Offset offset)
{
- segP->endEntrySection = offset;
+ segP->endEntrySection = offset;
}
/************************************************************************/
-/* SISetEndEntryChain(segP, offset) - sets the offset */
+/* SISetEndEntryChain(segP, offset) - sets the offset */
/************************************************************************/
static void
-SISetEndEntryChain(SISeg *segP, Offset offset)
+SISetEndEntryChain(SISeg * segP, Offset offset)
{
- segP->endEntryChain = offset;
+ segP->endEntryChain = offset;
}
/************************************************************************/
-/* SIGetEndEntryChain(segP) - returnss the offset */
+/* SIGetEndEntryChain(segP) - returnss the offset */
/************************************************************************/
-static Offset
-SIGetEndEntryChain(SISeg *segP)
+static Offset
+SIGetEndEntryChain(SISeg * segP)
{
- return(segP->endEntryChain);
+ return (segP->endEntryChain);
}
/************************************************************************/
-/* SISetStartEntryChain(segP, offset) - sets the offset */
+/* SISetStartEntryChain(segP, offset) - sets the offset */
/************************************************************************/
static void
-SISetStartEntryChain(SISeg *segP, Offset offset)
+SISetStartEntryChain(SISeg * segP, Offset offset)
{
- segP->startEntryChain = offset;
+ segP->startEntryChain = offset;
}
/************************************************************************/
-/* SIGetStartEntryChain(segP) - returns the offset */
+/* SIGetStartEntryChain(segP) - returns the offset */
/************************************************************************/
-static Offset
-SIGetStartEntryChain(SISeg *segP)
+static Offset
+SIGetStartEntryChain(SISeg * segP)
{
- return(segP->startEntryChain);
+ return (segP->startEntryChain);
}
/************************************************************************/
-/* SISetNumEntries(segP, num) sets the current nuber of entries */
+/* SISetNumEntries(segP, num) sets the current nuber of entries */
/************************************************************************/
-static bool
-SISetNumEntries(SISeg *segP, int num)
+static bool
+SISetNumEntries(SISeg * segP, int num)
{
- if ( num <= MAXNUMMESSAGES) {
- segP->numEntries = num;
- return(true);
- } else {
- return(false); /* table full */
- }
+ if (num <= MAXNUMMESSAGES)
+ {
+ segP->numEntries = num;
+ return (true);
+ }
+ else
+ {
+ return (false); /* table full */
+ }
}
/************************************************************************/
-/* SIGetNumEntries(segP) - returns the current nuber of entries */
+/* SIGetNumEntries(segP) - returns the current nuber of entries */
/************************************************************************/
static int
-SIGetNumEntries(SISeg *segP)
+SIGetNumEntries(SISeg * segP)
{
- return(segP->numEntries);
+ return (segP->numEntries);
}
/************************************************************************/
-/* SISetMaxNumEntries(segP, num) sets the maximal number of entries */
+/* SISetMaxNumEntries(segP, num) sets the maximal number of entries */
/************************************************************************/
-static bool
-SISetMaxNumEntries(SISeg *segP, int num)
+static bool
+SISetMaxNumEntries(SISeg * segP, int num)
{
- if ( num <= MAXNUMMESSAGES) {
- segP->maxNumEntries = num;
- return(true);
- } else {
- return(false); /* wrong number */
- }
+ if (num <= MAXNUMMESSAGES)
+ {
+ segP->maxNumEntries = num;
+ return (true);
+ }
+ else
+ {
+ return (false); /* wrong number */
+ }
}
/************************************************************************/
-/* SIGetProcStateLimit(segP, i) returns the limit of read messages */
+/* SIGetProcStateLimit(segP, i) returns the limit of read messages */
/************************************************************************/
static int
-SIGetProcStateLimit(SISeg *segP, int i)
+SIGetProcStateLimit(SISeg * segP, int i)
{
- return(segP->procState[i].limit);
+ return (segP->procState[i].limit);
}
/************************************************************************/
-/* SIIncNumEntries(segP, num) increments the current nuber of entries */
+/* SIIncNumEntries(segP, num) increments the current nuber of entries */
/************************************************************************/
-static bool
-SIIncNumEntries(SISeg *segP, int num)
+static bool
+SIIncNumEntries(SISeg * segP, int num)
{
- if ((segP->numEntries + num) <= MAXNUMMESSAGES) {
- segP->numEntries = segP->numEntries + num;
- return(true);
- } else {
- return(false); /* table full */
- }
+ if ((segP->numEntries + num) <= MAXNUMMESSAGES)
+ {
+ segP->numEntries = segP->numEntries + num;
+ return (true);
+ }
+ else
+ {
+ return (false); /* table full */
+ }
}
/************************************************************************/
-/* SIDecNumEntries(segP, num) decrements the current nuber of entries */
+/* SIDecNumEntries(segP, num) decrements the current nuber of entries */
/************************************************************************/
-static bool
-SIDecNumEntries(SISeg *segP, int num)
+static bool
+SIDecNumEntries(SISeg * segP, int num)
{
- if ((segP->numEntries - num) >= 0) {
- segP->numEntries = segP->numEntries - num;
- return(true);
- } else {
- return(false); /* not enough entries in table */
- }
+ if ((segP->numEntries - num) >= 0)
+ {
+ segP->numEntries = segP->numEntries - num;
+ return (true);
+ }
+ else
+ {
+ return (false); /* not enough entries in table */
+ }
}
/************************************************************************/
-/* SISetStartFreeSpace(segP, offset) - sets the offset */
+/* SISetStartFreeSpace(segP, offset) - sets the offset */
/************************************************************************/
static void
-SISetStartFreeSpace(SISeg *segP, Offset offset)
+SISetStartFreeSpace(SISeg * segP, Offset offset)
{
- segP->startFreeSpace = offset;
+ segP->startFreeSpace = offset;
}
/************************************************************************/
-/* SIGetStartFreeSpace(segP) - returns the offset */
+/* SIGetStartFreeSpace(segP) - returns the offset */
/************************************************************************/
-static Offset
-SIGetStartFreeSpace(SISeg *segP)
+static Offset
+SIGetStartFreeSpace(SISeg * segP)
{
- return(segP->startFreeSpace);
+ return (segP->startFreeSpace);
}
/************************************************************************/
-/* SIGetFirstDataEntry(segP) returns first data entry */
+/* SIGetFirstDataEntry(segP) returns first data entry */
/************************************************************************/
static SISegEntry *
-SIGetFirstDataEntry(SISeg *segP)
+SIGetFirstDataEntry(SISeg * segP)
{
- SISegEntry *eP;
- Offset startChain;
-
- startChain = SIGetStartEntryChain(segP);
-
- if (startChain == InvalidOffset)
- return(NULL);
-
- eP = (SISegEntry *) ((Pointer) segP +
- SIGetStartEntrySection(segP) +
- startChain );
- return(eP);
+ SISegEntry *eP;
+ Offset startChain;
+
+ startChain = SIGetStartEntryChain(segP);
+
+ if (startChain == InvalidOffset)
+ return (NULL);
+
+ eP = (SISegEntry *) ((Pointer) segP +
+ SIGetStartEntrySection(segP) +
+ startChain);
+ return (eP);
}
/************************************************************************/
-/* SIGetLastDataEntry(segP) returns last data entry in the chain */
+/* SIGetLastDataEntry(segP) returns last data entry in the chain */
/************************************************************************/
static SISegEntry *
-SIGetLastDataEntry(SISeg *segP)
+SIGetLastDataEntry(SISeg * segP)
{
- SISegEntry *eP;
- Offset endChain;
-
- endChain = SIGetEndEntryChain(segP);
-
- if (endChain == InvalidOffset)
- return(NULL);
-
- eP = (SISegEntry *) ((Pointer) segP +
- SIGetStartEntrySection(segP) +
- endChain );
- return(eP);
+ SISegEntry *eP;
+ Offset endChain;
+
+ endChain = SIGetEndEntryChain(segP);
+
+ if (endChain == InvalidOffset)
+ return (NULL);
+
+ eP = (SISegEntry *) ((Pointer) segP +
+ SIGetStartEntrySection(segP) +
+ endChain);
+ return (eP);
}
/************************************************************************/
-/* SIGetNextDataEntry(segP, offset) returns next data entry */
+/* SIGetNextDataEntry(segP, offset) returns next data entry */
/************************************************************************/
static SISegEntry *
-SIGetNextDataEntry(SISeg *segP, Offset offset)
+SIGetNextDataEntry(SISeg * segP, Offset offset)
{
- SISegEntry *eP;
-
- if (offset == InvalidOffset)
- return(NULL);
-
- eP = (SISegEntry *) ((Pointer) segP +
- SIGetStartEntrySection(segP) +
- offset);
- return(eP);
+ SISegEntry *eP;
+
+ if (offset == InvalidOffset)
+ return (NULL);
+
+ eP = (SISegEntry *) ((Pointer) segP +
+ SIGetStartEntrySection(segP) +
+ offset);
+ return (eP);
}
@@ -443,352 +468,396 @@ SIGetNextDataEntry(SISeg *segP, Offset offset)
/* SIGetNthDataEntry(segP, n) returns the n-th data entry in chain */
/************************************************************************/
static SISegEntry *
-SIGetNthDataEntry(SISeg *segP,
- int n) /* must range from 1 to MaxMessages */
+SIGetNthDataEntry(SISeg * segP,
+ int n) /* must range from 1 to MaxMessages */
{
- SISegEntry *eP;
- int i;
-
- if (n <= 0) return(NULL);
-
- eP = SIGetFirstDataEntry(segP);
- for (i = 1; i < n; i++) {
- /* skip one and get the next */
- eP = SIGetNextDataEntry(segP, eP->next);
- }
-
- return(eP);
+ SISegEntry *eP;
+ int i;
+
+ if (n <= 0)
+ return (NULL);
+
+ eP = SIGetFirstDataEntry(segP);
+ for (i = 1; i < n; i++)
+ {
+ /* skip one and get the next */
+ eP = SIGetNextDataEntry(segP, eP->next);
+ }
+
+ return (eP);
}
/************************************************************************/
-/* SIEntryOffset(segP, entryP) returns the offset for an pointer */
+/* SIEntryOffset(segP, entryP) returns the offset for an pointer */
/************************************************************************/
-static Offset
-SIEntryOffset(SISeg *segP, SISegEntry *entryP)
+static Offset
+SIEntryOffset(SISeg * segP, SISegEntry * entryP)
{
- /* relative to B !! */
- return ((Offset) ((Pointer) entryP -
- (Pointer) segP -
- SIGetStartEntrySection(segP) ));
+ /* relative to B !! */
+ return ((Offset) ((Pointer) entryP -
+ (Pointer) segP -
+ SIGetStartEntrySection(segP)));
}
/************************************************************************/
-/* SISetDataEntry(segP, data) - sets a message in the segemnt */
+/* SISetDataEntry(segP, data) - sets a message in the segemnt */
/************************************************************************/
bool
-SISetDataEntry(SISeg *segP, SharedInvalidData *data)
-{
- Offset offsetToNewData;
- SISegEntry *eP, *lastP;
-
- if (!SIIncNumEntries(segP, 1))
- return(false); /* no space */
-
- /* get a free entry */
- offsetToNewData = SIGetStartFreeSpace(segP);
- eP = SIGetNextDataEntry(segP, offsetToNewData); /* it's a free one */
- SISetStartFreeSpace(segP, eP->next);
- /* fill it up */
- eP->entryData = *data;
- eP->isfree = false;
- eP->next = InvalidOffset;
-
- /* handle insertion point at the end of the chain !!*/
- lastP = SIGetLastDataEntry(segP);
- if (lastP == NULL) {
- /* there is no chain, insert the first entry */
- SISetStartEntryChain(segP, SIEntryOffset(segP, eP));
- } else {
- /* there is a last entry in the chain */
- lastP->next = SIEntryOffset(segP, eP);
- }
- SISetEndEntryChain(segP, SIEntryOffset(segP, eP));
- return(true);
-}
-
-
-/************************************************************************/
-/* SIDecProcLimit(segP, num) decrements all process limits */
+SISetDataEntry(SISeg * segP, SharedInvalidData * data)
+{
+ Offset offsetToNewData;
+ SISegEntry *eP,
+ *lastP;
+
+ if (!SIIncNumEntries(segP, 1))
+ return (false); /* no space */
+
+ /* get a free entry */
+ offsetToNewData = SIGetStartFreeSpace(segP);
+ eP = SIGetNextDataEntry(segP, offsetToNewData); /* it's a free one */
+ SISetStartFreeSpace(segP, eP->next);
+ /* fill it up */
+ eP->entryData = *data;
+ eP->isfree = false;
+ eP->next = InvalidOffset;
+
+ /* handle insertion point at the end of the chain !! */
+ lastP = SIGetLastDataEntry(segP);
+ if (lastP == NULL)
+ {
+ /* there is no chain, insert the first entry */
+ SISetStartEntryChain(segP, SIEntryOffset(segP, eP));
+ }
+ else
+ {
+ /* there is a last entry in the chain */
+ lastP->next = SIEntryOffset(segP, eP);
+ }
+ SISetEndEntryChain(segP, SIEntryOffset(segP, eP));
+ return (true);
+}
+
+
+/************************************************************************/
+/* SIDecProcLimit(segP, num) decrements all process limits */
/************************************************************************/
static void
-SIDecProcLimit(SISeg *segP, int num)
-{
- int i;
- for (i=0; i < MaxBackendId; i++) {
- /* decrement only, if there is a limit > 0 */
- if (segP->procState[i].limit > 0) {
- segP->procState[i].limit = segP->procState[i].limit - num;
- if (segP->procState[i].limit < 0) {
- /* limit was not high enough, reset to zero */
- /* negative means it's a dead backend */
- segP->procState[i].limit = 0;
- }
- }
- }
+SIDecProcLimit(SISeg * segP, int num)
+{
+ int i;
+
+ for (i = 0; i < MaxBackendId; i++)
+ {
+ /* decrement only, if there is a limit > 0 */
+ if (segP->procState[i].limit > 0)
+ {
+ segP->procState[i].limit = segP->procState[i].limit - num;
+ if (segP->procState[i].limit < 0)
+ {
+ /* limit was not high enough, reset to zero */
+ /* negative means it's a dead backend */
+ segP->procState[i].limit = 0;
+ }
+ }
+ }
}
/************************************************************************/
-/* SIDelDataEntry(segP) - free the FIRST entry */
+/* SIDelDataEntry(segP) - free the FIRST entry */
/************************************************************************/
bool
-SIDelDataEntry(SISeg *segP)
+SIDelDataEntry(SISeg * segP)
{
- SISegEntry *e1P;
-
- if (!SIDecNumEntries(segP, 1)) {
- /* no entries in buffer */
- return(false);
- }
-
- e1P = SIGetFirstDataEntry(segP);
- SISetStartEntryChain(segP, e1P->next);
- if (SIGetStartEntryChain(segP) == InvalidOffset) {
- /* it was the last entry */
- SISetEndEntryChain(segP, InvalidOffset);
- }
- /* free the entry */
- e1P->isfree = true;
- e1P->next = SIGetStartFreeSpace(segP);
- SISetStartFreeSpace(segP, SIEntryOffset(segP, e1P));
- SIDecProcLimit(segP, 1);
- return(true);
+ SISegEntry *e1P;
+
+ if (!SIDecNumEntries(segP, 1))
+ {
+ /* no entries in buffer */
+ return (false);
+ }
+
+ e1P = SIGetFirstDataEntry(segP);
+ SISetStartEntryChain(segP, e1P->next);
+ if (SIGetStartEntryChain(segP) == InvalidOffset)
+ {
+ /* it was the last entry */
+ SISetEndEntryChain(segP, InvalidOffset);
+ }
+ /* free the entry */
+ e1P->isfree = true;
+ e1P->next = SIGetStartFreeSpace(segP);
+ SISetStartFreeSpace(segP, SIEntryOffset(segP, e1P));
+ SIDecProcLimit(segP, 1);
+ return (true);
}
/************************************************************************/
-/* SISetProcStateInvalid(segP) checks and marks a backends state as */
-/* invalid */
+/* SISetProcStateInvalid(segP) checks and marks a backends state as */
+/* invalid */
/************************************************************************/
void
-SISetProcStateInvalid(SISeg *segP)
-{
- int i;
-
- for (i=0; i < MaxBackendId; i++) {
- if (segP->procState[i].limit == 0) {
- /* backend i didn't read any message */
- segP->procState[i].resetState = true;
- /*XXX signal backend that it has to reset its internal cache ? */
- }
- }
+SISetProcStateInvalid(SISeg * segP)
+{
+ int i;
+
+ for (i = 0; i < MaxBackendId; i++)
+ {
+ if (segP->procState[i].limit == 0)
+ {
+ /* backend i didn't read any message */
+ segP->procState[i].resetState = true;
+
+ /*
+ * XXX signal backend that it has to reset its internal cache
+ * ?
+ */
+ }
+ }
}
/************************************************************************/
-/* SIReadEntryData(segP, backendId, function) */
-/* - marks messages to be read by id */
-/* and executes function */
+/* SIReadEntryData(segP, backendId, function) */
+/* - marks messages to be read by id */
+/* and executes function */
/************************************************************************/
void
-SIReadEntryData(SISeg *segP,
- int backendId,
- void (*invalFunction)(),
- void (*resetFunction)())
-{
- int i = 0;
- SISegEntry *data;
-
- Assert(segP->procState[backendId - 1].tag == MyBackendTag);
-
- if (!segP->procState[backendId - 1].resetState) {
- /* invalidate data, but only those, you have not seen yet !!*/
- /* therefore skip read messages */
- data = SIGetNthDataEntry(segP,
- SIGetProcStateLimit(segP, backendId - 1) + 1);
- while (data != NULL) {
- i++;
- segP->procState[backendId - 1].limit++; /* one more message read */
- invalFunction(data->entryData.cacheId,
- data->entryData.hashIndex,
- &data->entryData.pointerData);
- data = SIGetNextDataEntry(segP, data->next);
- }
- /* SIDelExpiredDataEntries(segP); */
- } else {
- /*backend must not read messages, its own state has to be reset */
- elog(NOTICE, "SIMarkEntryData: cache state reset");
- resetFunction(); /* XXXX call it here, parameters? */
-
- /* new valid state--mark all messages "read" */
- segP->procState[backendId - 1].resetState = false;
- segP->procState[backendId - 1].limit = SIGetNumEntries(segP);
- }
- /* check whether we can remove dead messages */
- if (i > MAXNUMMESSAGES) {
- elog(FATAL, "SIReadEntryData: Invalid segment state");
- }
+SIReadEntryData(SISeg * segP,
+ int backendId,
+ void (*invalFunction) (),
+ void (*resetFunction) ())
+{
+ int i = 0;
+ SISegEntry *data;
+
+ Assert(segP->procState[backendId - 1].tag == MyBackendTag);
+
+ if (!segP->procState[backendId - 1].resetState)
+ {
+ /* invalidate data, but only those, you have not seen yet !! */
+ /* therefore skip read messages */
+ data = SIGetNthDataEntry(segP,
+ SIGetProcStateLimit(segP, backendId - 1) + 1);
+ while (data != NULL)
+ {
+ i++;
+ segP->procState[backendId - 1].limit++; /* one more message read */
+ invalFunction(data->entryData.cacheId,
+ data->entryData.hashIndex,
+ &data->entryData.pointerData);
+ data = SIGetNextDataEntry(segP, data->next);
+ }
+ /* SIDelExpiredDataEntries(segP); */
+ }
+ else
+ {
+ /* backend must not read messages, its own state has to be reset */
+ elog(NOTICE, "SIMarkEntryData: cache state reset");
+ resetFunction(); /* XXXX call it here, parameters? */
+
+ /* new valid state--mark all messages "read" */
+ segP->procState[backendId - 1].resetState = false;
+ segP->procState[backendId - 1].limit = SIGetNumEntries(segP);
+ }
+ /* check whether we can remove dead messages */
+ if (i > MAXNUMMESSAGES)
+ {
+ elog(FATAL, "SIReadEntryData: Invalid segment state");
+ }
}
/************************************************************************/
-/* SIDelExpiredDataEntries (segP) - removes irrelevant messages */
+/* SIDelExpiredDataEntries (segP) - removes irrelevant messages */
/************************************************************************/
void
-SIDelExpiredDataEntries(SISeg *segP)
-{
- int min, i, h;
-
- min = 9999999;
- for (i = 0; i < MaxBackendId; i++) {
- h = SIGetProcStateLimit(segP, i);
- if (h >= 0) { /* backend active */
- if (h < min ) min = h;
- }
- }
- if (min != 9999999) {
- /* we can remove min messages */
- for (i = 1; i <= min; i++) {
- /* this adjusts also the state limits!*/
- if (!SIDelDataEntry(segP)) {
- elog(FATAL, "SIDelExpiredDataEntries: Invalid segment state");
- }
- }
- }
+SIDelExpiredDataEntries(SISeg * segP)
+{
+ int min,
+ i,
+ h;
+
+ min = 9999999;
+ for (i = 0; i < MaxBackendId; i++)
+ {
+ h = SIGetProcStateLimit(segP, i);
+ if (h >= 0)
+ { /* backend active */
+ if (h < min)
+ min = h;
+ }
+ }
+ if (min != 9999999)
+ {
+ /* we can remove min messages */
+ for (i = 1; i <= min; i++)
+ {
+ /* this adjusts also the state limits! */
+ if (!SIDelDataEntry(segP))
+ {
+ elog(FATAL, "SIDelExpiredDataEntries: Invalid segment state");
+ }
+ }
+ }
}
/************************************************************************/
-/* SISegInit(segP) - initializes the segment */
+/* SISegInit(segP) - initializes the segment */
/************************************************************************/
static void
-SISegInit(SISeg *segP)
-{
- SISegOffsets *oP;
- int segSize, i;
- SISegEntry *eP;
-
- oP = SIComputeSize(&segSize);
- /* set sempahore ids in the segment */
- /* XXX */
- SISetStartEntrySection(segP, oP->offsetToFirstEntry);
- SISetEndEntrySection(segP, oP->offsetToEndOfSegemnt);
- SISetStartFreeSpace(segP, 0);
- SISetStartEntryChain(segP, InvalidOffset);
- SISetEndEntryChain(segP, InvalidOffset);
- SISetNumEntries(segP, 0);
- SISetMaxNumEntries(segP, MAXNUMMESSAGES);
- for (i = 0; i < MaxBackendId; i++) {
- segP->procState[i].limit = -1; /* no backend active !!*/
- segP->procState[i].resetState = false;
- segP->procState[i].tag = InvalidBackendTag;
- }
- /* construct a chain of free entries */
- for (i = 1; i < MAXNUMMESSAGES; i++) {
- eP = (SISegEntry *) ((Pointer) segP +
- SIGetStartEntrySection(segP) +
- (i - 1) * sizeof(SISegEntry));
- eP->isfree = true;
- eP->next = i * sizeof(SISegEntry); /* relative to B */
- }
- /* handle the last free entry separate */
- eP = (SISegEntry *) ((Pointer) segP +
- SIGetStartEntrySection(segP) +
- (MAXNUMMESSAGES - 1) * sizeof(SISegEntry));
- eP->isfree = true;
- eP->next = InvalidOffset; /* it's the end of the chain !! */
- /*
- * Be tidy
- */
- pfree(oP);
-
-}
-
-
-
-/************************************************************************/
-/* SISegmentKill(key) - kill any segment */
+SISegInit(SISeg * segP)
+{
+ SISegOffsets *oP;
+ int segSize,
+ i;
+ SISegEntry *eP;
+
+ oP = SIComputeSize(&segSize);
+ /* set sempahore ids in the segment */
+ /* XXX */
+ SISetStartEntrySection(segP, oP->offsetToFirstEntry);
+ SISetEndEntrySection(segP, oP->offsetToEndOfSegemnt);
+ SISetStartFreeSpace(segP, 0);
+ SISetStartEntryChain(segP, InvalidOffset);
+ SISetEndEntryChain(segP, InvalidOffset);
+ SISetNumEntries(segP, 0);
+ SISetMaxNumEntries(segP, MAXNUMMESSAGES);
+ for (i = 0; i < MaxBackendId; i++)
+ {
+ segP->procState[i].limit = -1; /* no backend active !! */
+ segP->procState[i].resetState = false;
+ segP->procState[i].tag = InvalidBackendTag;
+ }
+ /* construct a chain of free entries */
+ for (i = 1; i < MAXNUMMESSAGES; i++)
+ {
+ eP = (SISegEntry *) ((Pointer) segP +
+ SIGetStartEntrySection(segP) +
+ (i - 1) * sizeof(SISegEntry));
+ eP->isfree = true;
+ eP->next = i * sizeof(SISegEntry); /* relative to B */
+ }
+ /* handle the last free entry separate */
+ eP = (SISegEntry *) ((Pointer) segP +
+ SIGetStartEntrySection(segP) +
+ (MAXNUMMESSAGES - 1) * sizeof(SISegEntry));
+ eP->isfree = true;
+ eP->next = InvalidOffset; /* it's the end of the chain !! */
+
+ /*
+ * Be tidy
+ */
+ pfree(oP);
+
+}
+
+
+
+/************************************************************************/
+/* SISegmentKill(key) - kill any segment */
/************************************************************************/
static void
-SISegmentKill(int key) /* the corresponding key for the segment */
-{
- IpcMemoryKill(key);
-}
+SISegmentKill(int key) /* the corresponding key for the segment */
+{
+ IpcMemoryKill(key);
+}
/************************************************************************/
-/* SISegmentGet(key, size) - get a shared segment of size <size> */
-/* returns a segment id */
+/* SISegmentGet(key, size) - get a shared segment of size <size> */
+/* returns a segment id */
/************************************************************************/
-static IpcMemoryId
-SISegmentGet(int key, /* the corresponding key for the segment */
- int size, /* size of segment in bytes */
- bool create)
+static IpcMemoryId
+SISegmentGet(int key, /* the corresponding key for the segment */
+ int size, /* size of segment in bytes */
+ bool create)
{
- IpcMemoryId shmid;
-
- if (create) {
- shmid = IpcMemoryCreate(key, size, IPCProtection);
- } else {
- shmid = IpcMemoryIdGet(key, size);
- }
- return(shmid);
+ IpcMemoryId shmid;
+
+ if (create)
+ {
+ shmid = IpcMemoryCreate(key, size, IPCProtection);
+ }
+ else
+ {
+ shmid = IpcMemoryIdGet(key, size);
+ }
+ return (shmid);
}
/************************************************************************/
-/* SISegmentAttach(shmid) - attach a shared segment with id shmid */
+/* SISegmentAttach(shmid) - attach a shared segment with id shmid */
/************************************************************************/
static void
SISegmentAttach(IpcMemoryId shmid)
{
- shmInvalBuffer = (struct SISeg *) IpcMemoryAttach(shmid);
- if (shmInvalBuffer == IpcMemAttachFailed) {
- /* XXX use validity function */
- elog(NOTICE, "SISegmentAttach: Could not attach segment");
- elog(FATAL, "SISegmentAttach: %m");
- }
+ shmInvalBuffer = (struct SISeg *) IpcMemoryAttach(shmid);
+ if (shmInvalBuffer == IpcMemAttachFailed)
+ {
+ /* XXX use validity function */
+ elog(NOTICE, "SISegmentAttach: Could not attach segment");
+ elog(FATAL, "SISegmentAttach: %m");
+ }
}
/************************************************************************/
-/* SISegmentInit(killExistingSegment, key) initialize segment */
+/* SISegmentInit(killExistingSegment, key) initialize segment */
/************************************************************************/
int
SISegmentInit(bool killExistingSegment, IPCKey key)
-{
- SISegOffsets *oP;
- int segSize;
- IpcMemoryId shmId;
- bool create;
-
- if (killExistingSegment) {
- /* Kill existing segment */
- /* set semaphore */
- SISegmentKill(key);
-
- /* Get a shared segment */
-
- oP = SIComputeSize(&segSize);
- /*
- * Be tidy
- */
- pfree(oP);
-
- create = true;
- shmId = SISegmentGet(key,segSize, create);
- if (shmId < 0) {
- perror("SISegmentGet: failed");
- return(-1); /* an error */
- }
-
- /* Attach the shared cache invalidation segment */
- /* sets the global variable shmInvalBuffer */
- SISegmentAttach(shmId);
-
- /* Init shared memory table */
- SISegInit(shmInvalBuffer);
- } else {
- /* use an existing segment */
- create = false;
- shmId = SISegmentGet(key, 0, create);
- if (shmId < 0) {
- perror("SISegmentGet: getting an existent segment failed");
- return(-1); /* an error */
- }
- /* Attach the shared cache invalidation segment */
- SISegmentAttach(shmId);
- }
- return(1);
-}
+{
+ SISegOffsets *oP;
+ int segSize;
+ IpcMemoryId shmId;
+ bool create;
+
+ if (killExistingSegment)
+ {
+ /* Kill existing segment */
+ /* set semaphore */
+ SISegmentKill(key);
+
+ /* Get a shared segment */
+
+ oP = SIComputeSize(&segSize);
+
+ /*
+ * Be tidy
+ */
+ pfree(oP);
+ create = true;
+ shmId = SISegmentGet(key, segSize, create);
+ if (shmId < 0)
+ {
+ perror("SISegmentGet: failed");
+ return (-1); /* an error */
+ }
+
+ /* Attach the shared cache invalidation segment */
+ /* sets the global variable shmInvalBuffer */
+ SISegmentAttach(shmId);
+
+ /* Init shared memory table */
+ SISegInit(shmInvalBuffer);
+ }
+ else
+ {
+ /* use an existing segment */
+ create = false;
+ shmId = SISegmentGet(key, 0, create);
+ if (shmId < 0)
+ {
+ perror("SISegmentGet: getting an existent segment failed");
+ return (-1); /* an error */
+ }
+ /* Attach the shared cache invalidation segment */
+ SISegmentAttach(shmId);
+ }
+ return (1);
+}
diff --git a/src/backend/storage/ipc/spin.c b/src/backend/storage/ipc/spin.c
index b50d5d9500f..e93d5894a58 100644
--- a/src/backend/storage/ipc/spin.c
+++ b/src/backend/storage/ipc/spin.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* spin.c--
- * routines for managing spin locks
+ * routines for managing spin locks
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.6 1997/08/21 13:43:46 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/ipc/Attic/spin.c,v 1.7 1997/09/07 04:48:45 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,8 +21,8 @@
* term semaphores separately anyway.
*
* NOTE: These routines are not supposed to be widely used in Postgres.
- * They are preserved solely for the purpose of porting Mark Sullivan's
- * buffer manager to Postgres.
+ * They are preserved solely for the purpose of porting Mark Sullivan's
+ * buffer manager to Postgres.
*/
#include <errno.h>
#include "postgres.h"
@@ -43,61 +43,62 @@ IpcSemaphoreId SpinLockId;
bool
CreateSpinlocks(IPCKey key)
-{
- /* the spin lock shared memory must have been created by now */
- return(TRUE);
+{
+ /* the spin lock shared memory must have been created by now */
+ return (TRUE);
}
bool
InitSpinLocks(int init, IPCKey key)
{
- extern SPINLOCK ShmemLock;
- extern SPINLOCK BindingLock;
- extern SPINLOCK BufMgrLock;
- extern SPINLOCK LockMgrLock;
- extern SPINLOCK ProcStructLock;
- extern SPINLOCK SInvalLock;
- extern SPINLOCK OidGenLockId;
-
+ extern SPINLOCK ShmemLock;
+ extern SPINLOCK BindingLock;
+ extern SPINLOCK BufMgrLock;
+ extern SPINLOCK LockMgrLock;
+ extern SPINLOCK ProcStructLock;
+ extern SPINLOCK SInvalLock;
+ extern SPINLOCK OidGenLockId;
+
#ifdef MAIN_MEMORY
- extern SPINLOCK MMCacheLock;
-#endif /* SONY_JUKEBOX */
-
- /* These six spinlocks have fixed location is shmem */
- ShmemLock = (SPINLOCK) SHMEMLOCKID;
- BindingLock = (SPINLOCK) BINDINGLOCKID;
- BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
- LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
- ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
- SInvalLock = (SPINLOCK) SINVALLOCKID;
- OidGenLockId = (SPINLOCK) OIDGENLOCKID;
-
+ extern SPINLOCK MMCacheLock;
+
+#endif /* SONY_JUKEBOX */
+
+ /* These six spinlocks have fixed location is shmem */
+ ShmemLock = (SPINLOCK) SHMEMLOCKID;
+ BindingLock = (SPINLOCK) BINDINGLOCKID;
+ BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
+ LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
+ ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
+ SInvalLock = (SPINLOCK) SINVALLOCKID;
+ OidGenLockId = (SPINLOCK) OIDGENLOCKID;
+
#ifdef MAIN_MEMORY
- MMCacheLock = (SPINLOCK) MMCACHELOCKID;
-#endif /* MAIN_MEMORY */
-
- return(TRUE);
+ MMCacheLock = (SPINLOCK) MMCACHELOCKID;
+#endif /* MAIN_MEMORY */
+
+ return (TRUE);
}
void
SpinAcquire(SPINLOCK lock)
{
- ExclusiveLock(lock);
- PROC_INCR_SLOCK(lock);
+ ExclusiveLock(lock);
+ PROC_INCR_SLOCK(lock);
}
void
SpinRelease(SPINLOCK lock)
{
- PROC_DECR_SLOCK(lock);
- ExclusiveUnlock(lock);
+ PROC_DECR_SLOCK(lock);
+ ExclusiveUnlock(lock);
}
-#else /* HAS_TEST_AND_SET */
+#else /* HAS_TEST_AND_SET */
/* Spinlocks are implemented using SysV semaphores */
-static bool AttachSpinLocks(IPCKey key);
-static bool SpinIsLocked(SPINLOCK lock);
+static bool AttachSpinLocks(IPCKey key);
+static bool SpinIsLocked(SPINLOCK lock);
/*
* SpinAcquire -- try to grab a spinlock
@@ -107,86 +108,91 @@ static bool SpinIsLocked(SPINLOCK lock);
void
SpinAcquire(SPINLOCK lock)
{
- IpcSemaphoreLock(SpinLockId, lock, IpcExclusiveLock);
- PROC_INCR_SLOCK(lock);
+ IpcSemaphoreLock(SpinLockId, lock, IpcExclusiveLock);
+ PROC_INCR_SLOCK(lock);
}
/*
* SpinRelease -- release a spin lock
- *
+ *
* FAILS if the semaphore is corrupted
*/
void
SpinRelease(SPINLOCK lock)
{
- Assert(SpinIsLocked(lock))
+ Assert(SpinIsLocked(lock))
PROC_DECR_SLOCK(lock);
- IpcSemaphoreUnlock(SpinLockId, lock, IpcExclusiveLock);
+ IpcSemaphoreUnlock(SpinLockId, lock, IpcExclusiveLock);
}
-static bool
+static bool
SpinIsLocked(SPINLOCK lock)
{
- int semval;
-
- semval = IpcSemaphoreGetValue(SpinLockId, lock);
- return(semval < IpcSemaphoreDefaultStartValue);
+ int semval;
+
+ semval = IpcSemaphoreGetValue(SpinLockId, lock);
+ return (semval < IpcSemaphoreDefaultStartValue);
}
/*
* CreateSpinlocks -- Create a sysV semaphore array for
- * the spinlocks
+ * the spinlocks
*
*/
bool
CreateSpinlocks(IPCKey key)
{
-
- int status;
- IpcSemaphoreId semid;
- semid = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
- IpcSemaphoreDefaultStartValue, 1, &status);
- if (status == IpcSemIdExist) {
- IpcSemaphoreKill(key);
- elog(NOTICE,"Destroying old spinlock semaphore");
- semid = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
- IpcSemaphoreDefaultStartValue, 1, &status);
- }
-
- if (semid >= 0) {
- SpinLockId = semid;
- return(TRUE);
- }
- /* cannot create spinlocks */
- elog(FATAL,"CreateSpinlocks: cannot create spin locks");
- return(FALSE);
+
+ int status;
+ IpcSemaphoreId semid;
+
+ semid = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
+ IpcSemaphoreDefaultStartValue, 1, &status);
+ if (status == IpcSemIdExist)
+ {
+ IpcSemaphoreKill(key);
+ elog(NOTICE, "Destroying old spinlock semaphore");
+ semid = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
+ IpcSemaphoreDefaultStartValue, 1, &status);
+ }
+
+ if (semid >= 0)
+ {
+ SpinLockId = semid;
+ return (TRUE);
+ }
+ /* cannot create spinlocks */
+ elog(FATAL, "CreateSpinlocks: cannot create spin locks");
+ return (FALSE);
}
/*
* Attach to existing spinlock set
*/
-static bool
+static bool
AttachSpinLocks(IPCKey key)
{
- IpcSemaphoreId id;
-
- id = semget (key, MAX_SPINS, 0);
- if (id < 0) {
- if (errno == EEXIST) {
- /* key is the name of someone else's semaphore */
- elog (FATAL,"AttachSpinlocks: SPIN_KEY belongs to someone else");
+ IpcSemaphoreId id;
+
+ id = semget(key, MAX_SPINS, 0);
+ if (id < 0)
+ {
+ if (errno == EEXIST)
+ {
+ /* key is the name of someone else's semaphore */
+ elog(FATAL, "AttachSpinlocks: SPIN_KEY belongs to someone else");
+ }
+ /* cannot create spinlocks */
+ elog(FATAL, "AttachSpinlocks: cannot create spin locks");
+ return (FALSE);
}
- /* cannot create spinlocks */
- elog(FATAL,"AttachSpinlocks: cannot create spin locks");
- return(FALSE);
- }
- SpinLockId = id;
- return(TRUE);
+ SpinLockId = id;
+ return (TRUE);
}
/*
* InitSpinLocks -- Spinlock bootstrapping
- *
+ *
* We need several spinlocks for bootstrapping:
* BindingLock (for the shmem binding table) and
* ShmemLock (for the shmem allocator), BufMgrLock (for buffer
@@ -199,41 +205,47 @@ AttachSpinLocks(IPCKey key)
bool
InitSpinLocks(int init, IPCKey key)
{
- extern SPINLOCK ShmemLock;
- extern SPINLOCK BindingLock;
- extern SPINLOCK BufMgrLock;
- extern SPINLOCK LockMgrLock;
- extern SPINLOCK ProcStructLock;
- extern SPINLOCK SInvalLock;
- extern SPINLOCK OidGenLockId;
-
+ extern SPINLOCK ShmemLock;
+ extern SPINLOCK BindingLock;
+ extern SPINLOCK BufMgrLock;
+ extern SPINLOCK LockMgrLock;
+ extern SPINLOCK ProcStructLock;
+ extern SPINLOCK SInvalLock;
+ extern SPINLOCK OidGenLockId;
+
#ifdef MAIN_MEMORY
- extern SPINLOCK MMCacheLock;
-#endif /* MAIN_MEMORY */
-
- if (!init || key != IPC_PRIVATE) {
- /* if bootstrap and key is IPC_PRIVATE, it means that we are running
- * backend by itself. no need to attach spinlocks
- */
- if (! AttachSpinLocks(key)) {
- elog(FATAL,"InitSpinLocks: couldnt attach spin locks");
- return(FALSE);
+ extern SPINLOCK MMCacheLock;
+
+#endif /* MAIN_MEMORY */
+
+ if (!init || key != IPC_PRIVATE)
+ {
+
+ /*
+ * if bootstrap and key is IPC_PRIVATE, it means that we are
+ * running backend by itself. no need to attach spinlocks
+ */
+ if (!AttachSpinLocks(key))
+ {
+ elog(FATAL, "InitSpinLocks: couldnt attach spin locks");
+ return (FALSE);
+ }
}
- }
-
- /* These five (or six) spinlocks have fixed location is shmem */
- ShmemLock = (SPINLOCK) SHMEMLOCKID;
- BindingLock = (SPINLOCK) BINDINGLOCKID;
- BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
- LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
- ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
- SInvalLock = (SPINLOCK) SINVALLOCKID;
- OidGenLockId = (SPINLOCK) OIDGENLOCKID;
-
+
+ /* These five (or six) spinlocks have fixed location is shmem */
+ ShmemLock = (SPINLOCK) SHMEMLOCKID;
+ BindingLock = (SPINLOCK) BINDINGLOCKID;
+ BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
+ LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
+ ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
+ SInvalLock = (SPINLOCK) SINVALLOCKID;
+ OidGenLockId = (SPINLOCK) OIDGENLOCKID;
+
#ifdef MAIN_MEMORY
- MMCacheLock = (SPINLOCK) MMCACHELOCKID;
-#endif /* MAIN_MEMORY */
-
- return(TRUE);
+ MMCacheLock = (SPINLOCK) MMCACHELOCKID;
+#endif /* MAIN_MEMORY */
+
+ return (TRUE);
}
-#endif /* HAS_TEST_AND_SET */
+
+#endif /* HAS_TEST_AND_SET */
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index ddf69a6527e..dfde8f469c5 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* inv_api.c--
- * routines for manipulating inversion fs large objects. This file
- * contains the user-level large object application interface routines.
+ * routines for manipulating inversion fs large objects. This file
+ * contains the user-level large object application interface routines.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.13 1997/08/19 21:33:10 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.14 1997/09/07 04:48:46 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/types.h>
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
@@ -28,11 +28,11 @@
#include "access/xact.h"
#include "access/nbtree.h"
#include "access/tupdesc.h"
-#include "catalog/index.h" /* for index_create() */
+#include "catalog/index.h" /* for index_create() */
#include "catalog/catalog.h" /* for newoid() */
-#include "catalog/pg_am.h" /* for BTREE_AM_OID */
+#include "catalog/pg_am.h" /* for BTREE_AM_OID */
#include "catalog/pg_opclass.h" /* for INT4_OPS_OID */
-#include "catalog/pg_proc.h" /* for INT4GE_PROC_OID */
+#include "catalog/pg_proc.h" /* for INT4GE_PROC_OID */
#include "storage/itemptr.h"
#include "storage/bufpage.h"
#include "storage/bufmgr.h"
@@ -43,226 +43,241 @@
#include "storage/large_object.h"
#include "storage/lmgr.h"
#include "utils/syscache.h"
-#include "utils/builtins.h" /* for namestrcpy() */
+#include "utils/builtins.h" /* for namestrcpy() */
#include "catalog/heap.h"
#include "nodes/pg_list.h"
/*
- * Warning, Will Robinson... In order to pack data into an inversion
- * file as densely as possible, we violate the class abstraction here.
- * When we're appending a new tuple to the end of the table, we check
- * the last page to see how much data we can put on it. If it's more
- * than IMINBLK, we write enough to fill the page. This limits external
- * fragmentation. In no case can we write more than IMAXBLK, since
- * the 8K postgres page size less overhead leaves only this much space
- * for data.
+ * Warning, Will Robinson... In order to pack data into an inversion
+ * file as densely as possible, we violate the class abstraction here.
+ * When we're appending a new tuple to the end of the table, we check
+ * the last page to see how much data we can put on it. If it's more
+ * than IMINBLK, we write enough to fill the page. This limits external
+ * fragmentation. In no case can we write more than IMAXBLK, since
+ * the 8K postgres page size less overhead leaves only this much space
+ * for data.
*/
-#define IFREESPC(p) (PageGetFreeSpace(p) - sizeof(HeapTupleData) - sizeof(struct varlena) - sizeof(int32))
-#define IMAXBLK 8092
-#define IMINBLK 512
+#define IFREESPC(p) (PageGetFreeSpace(p) - sizeof(HeapTupleData) - sizeof(struct varlena) - sizeof(int32))
+#define IMAXBLK 8092
+#define IMINBLK 512
/* non-export function prototypes */
-static HeapTuple inv_newtuple(LargeObjectDesc *obj_desc, Buffer buffer,
- Page page, char *dbuf, int nwrite);
-static HeapTuple inv_fetchtup(LargeObjectDesc *obj_desc, Buffer *bufP);
-static int inv_wrnew(LargeObjectDesc *obj_desc, char *buf, int nbytes);
-static int inv_wrold(LargeObjectDesc *obj_desc, char *dbuf, int nbytes,
- HeapTuple htup, Buffer buffer);
-static void inv_indextup(LargeObjectDesc *obj_desc, HeapTuple htup);
-static int _inv_getsize(Relation hreln, TupleDesc hdesc, Relation ireln);
+static HeapTuple
+inv_newtuple(LargeObjectDesc * obj_desc, Buffer buffer,
+ Page page, char *dbuf, int nwrite);
+static HeapTuple inv_fetchtup(LargeObjectDesc * obj_desc, Buffer * bufP);
+static int inv_wrnew(LargeObjectDesc * obj_desc, char *buf, int nbytes);
+static int
+inv_wrold(LargeObjectDesc * obj_desc, char *dbuf, int nbytes,
+ HeapTuple htup, Buffer buffer);
+static void inv_indextup(LargeObjectDesc * obj_desc, HeapTuple htup);
+static int _inv_getsize(Relation hreln, TupleDesc hdesc, Relation ireln);
/*
- * inv_create -- create a new large object.
+ * inv_create -- create a new large object.
*
- * Arguments:
- * flags -- storage manager to use, archive mode, etc.
+ * Arguments:
+ * flags -- storage manager to use, archive mode, etc.
*
- * Returns:
- * large object descriptor, appropriately filled in.
+ * Returns:
+ * large object descriptor, appropriately filled in.
*/
LargeObjectDesc *
inv_create(int flags)
{
- int file_oid;
- LargeObjectDesc *retval;
- Relation r;
- Relation indr;
- int smgr;
- char archchar;
- TupleDesc tupdesc;
- AttrNumber attNums[1];
- Oid classObjectId[1];
- char objname[NAMEDATALEN];
- char indname[NAMEDATALEN];
-
- /* parse flags */
- smgr = flags & INV_SMGRMASK;
- if (flags & INV_ARCHIVE)
- archchar = 'h';
- else
- archchar = 'n';
-
- /* add one here since the pg_class tuple created
- will have the next oid and we want to have the relation name
- to correspond to the tuple OID */
- file_oid = newoid()+1;
-
- /* come up with some table names */
- sprintf(objname, "xinv%d", file_oid);
- sprintf(indname, "xinx%d", file_oid);
-
- if (SearchSysCacheTuple(RELNAME, PointerGetDatum(objname),
- 0,0,0) != NULL) {
- elog(WARN,
- "internal error: %s already exists -- cannot create large obj",
- objname);
- }
- if (SearchSysCacheTuple(RELNAME, PointerGetDatum(indname),
- 0,0,0) != NULL) {
- elog(WARN,
- "internal error: %s already exists -- cannot create large obj",
- indname);
- }
-
- /* this is pretty painful... want a tuple descriptor */
- tupdesc = CreateTemplateTupleDesc(2);
- TupleDescInitEntry(tupdesc, (AttrNumber) 1,
- "olastbye",
- "int4",
- 0, false);
- TupleDescInitEntry(tupdesc, (AttrNumber) 2,
- "odata",
- "bytea",
- 0, false);
- /*
- * First create the table to hold the inversion large object. It
- * will be located on whatever storage manager the user requested.
- */
-
- heap_create(objname,
- objname,
- (int) archchar, smgr,
- tupdesc);
-
- /* make the relation visible in this transaction */
- CommandCounterIncrement();
- r = heap_openr(objname);
-
- if (!RelationIsValid(r)) {
- elog(WARN, "cannot create large object on %s under inversion",
- smgrout(smgr));
- }
-
- /*
- * Now create a btree index on the relation's olastbyte attribute to
- * make seeks go faster. The hardwired constants are embarassing
- * to me, and are symptomatic of the pressure under which this code
- * was written.
- *
- * ok, mao, let's put in some symbolic constants - jolly
- */
-
- attNums[0] = 1;
- classObjectId[0] = INT4_OPS_OID;
- index_create(objname, indname, NULL, NULL, BTREE_AM_OID,
- 1, &attNums[0], &classObjectId[0],
- 0, (Datum) NULL, NULL, FALSE, FALSE);
-
- /* make the index visible in this transaction */
- CommandCounterIncrement();
- indr = index_openr(indname);
-
- if (!RelationIsValid(indr)) {
- elog(WARN, "cannot create index for large obj on %s under inversion",
- smgrout(smgr));
- }
-
- retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
-
- retval->heap_r = r;
- retval->index_r = indr;
- retval->iscan = (IndexScanDesc) NULL;
- retval->hdesc = RelationGetTupleDescriptor(r);
- retval->idesc = RelationGetTupleDescriptor(indr);
- retval->offset = retval->lowbyte =
- retval->highbyte = 0;
- ItemPointerSetInvalid(&(retval->htid));
-
- if (flags & INV_WRITE) {
- RelationSetLockForWrite(r);
- retval->flags = IFS_WRLOCK|IFS_RDLOCK;
- } else if (flags & INV_READ) {
- RelationSetLockForRead(r);
- retval->flags = IFS_RDLOCK;
- }
- retval->flags |= IFS_ATEOF;
-
- return(retval);
+ int file_oid;
+ LargeObjectDesc *retval;
+ Relation r;
+ Relation indr;
+ int smgr;
+ char archchar;
+ TupleDesc tupdesc;
+ AttrNumber attNums[1];
+ Oid classObjectId[1];
+ char objname[NAMEDATALEN];
+ char indname[NAMEDATALEN];
+
+ /* parse flags */
+ smgr = flags & INV_SMGRMASK;
+ if (flags & INV_ARCHIVE)
+ archchar = 'h';
+ else
+ archchar = 'n';
+
+ /*
+ * add one here since the pg_class tuple created will have the next
+ * oid and we want to have the relation name to correspond to the
+ * tuple OID
+ */
+ file_oid = newoid() + 1;
+
+ /* come up with some table names */
+ sprintf(objname, "xinv%d", file_oid);
+ sprintf(indname, "xinx%d", file_oid);
+
+ if (SearchSysCacheTuple(RELNAME, PointerGetDatum(objname),
+ 0, 0, 0) != NULL)
+ {
+ elog(WARN,
+ "internal error: %s already exists -- cannot create large obj",
+ objname);
+ }
+ if (SearchSysCacheTuple(RELNAME, PointerGetDatum(indname),
+ 0, 0, 0) != NULL)
+ {
+ elog(WARN,
+ "internal error: %s already exists -- cannot create large obj",
+ indname);
+ }
+
+ /* this is pretty painful... want a tuple descriptor */
+ tupdesc = CreateTemplateTupleDesc(2);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1,
+ "olastbye",
+ "int4",
+ 0, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2,
+ "odata",
+ "bytea",
+ 0, false);
+
+ /*
+ * First create the table to hold the inversion large object. It will
+ * be located on whatever storage manager the user requested.
+ */
+
+ heap_create(objname,
+ objname,
+ (int) archchar, smgr,
+ tupdesc);
+
+ /* make the relation visible in this transaction */
+ CommandCounterIncrement();
+ r = heap_openr(objname);
+
+ if (!RelationIsValid(r))
+ {
+ elog(WARN, "cannot create large object on %s under inversion",
+ smgrout(smgr));
+ }
+
+ /*
+ * Now create a btree index on the relation's olastbyte attribute to
+ * make seeks go faster. The hardwired constants are embarassing to
+ * me, and are symptomatic of the pressure under which this code was
+ * written.
+ *
+ * ok, mao, let's put in some symbolic constants - jolly
+ */
+
+ attNums[0] = 1;
+ classObjectId[0] = INT4_OPS_OID;
+ index_create(objname, indname, NULL, NULL, BTREE_AM_OID,
+ 1, &attNums[0], &classObjectId[0],
+ 0, (Datum) NULL, NULL, FALSE, FALSE);
+
+ /* make the index visible in this transaction */
+ CommandCounterIncrement();
+ indr = index_openr(indname);
+
+ if (!RelationIsValid(indr))
+ {
+ elog(WARN, "cannot create index for large obj on %s under inversion",
+ smgrout(smgr));
+ }
+
+ retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
+
+ retval->heap_r = r;
+ retval->index_r = indr;
+ retval->iscan = (IndexScanDesc) NULL;
+ retval->hdesc = RelationGetTupleDescriptor(r);
+ retval->idesc = RelationGetTupleDescriptor(indr);
+ retval->offset = retval->lowbyte =
+ retval->highbyte = 0;
+ ItemPointerSetInvalid(&(retval->htid));
+
+ if (flags & INV_WRITE)
+ {
+ RelationSetLockForWrite(r);
+ retval->flags = IFS_WRLOCK | IFS_RDLOCK;
+ }
+ else if (flags & INV_READ)
+ {
+ RelationSetLockForRead(r);
+ retval->flags = IFS_RDLOCK;
+ }
+ retval->flags |= IFS_ATEOF;
+
+ return (retval);
}
LargeObjectDesc *
inv_open(Oid lobjId, int flags)
{
- LargeObjectDesc *retval;
- Relation r;
- char *indname;
- Relation indrel;
-
- r = heap_open(lobjId);
-
- if (!RelationIsValid(r))
- return ((LargeObjectDesc *) NULL);
-
- indname = pstrdup((r->rd_rel->relname).data);
-
- /*
- * hack hack hack... we know that the fourth character of the relation
- * name is a 'v', and that the fourth character of the index name is an
- * 'x', and that they're otherwise identical.
- */
- indname[3] = 'x';
- indrel = index_openr(indname);
-
- if (!RelationIsValid(indrel))
- return ((LargeObjectDesc *) NULL);
-
- retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
-
- retval->heap_r = r;
- retval->index_r = indrel;
- retval->iscan = (IndexScanDesc) NULL;
- retval->hdesc = RelationGetTupleDescriptor(r);
- retval->idesc = RelationGetTupleDescriptor(indrel);
- retval->offset = retval->lowbyte = retval->highbyte = 0;
- ItemPointerSetInvalid(&(retval->htid));
-
- if (flags & INV_WRITE) {
- RelationSetLockForWrite(r);
- retval->flags = IFS_WRLOCK|IFS_RDLOCK;
- } else if (flags & INV_READ) {
- RelationSetLockForRead(r);
- retval->flags = IFS_RDLOCK;
- }
-
- return(retval);
+ LargeObjectDesc *retval;
+ Relation r;
+ char *indname;
+ Relation indrel;
+
+ r = heap_open(lobjId);
+
+ if (!RelationIsValid(r))
+ return ((LargeObjectDesc *) NULL);
+
+ indname = pstrdup((r->rd_rel->relname).data);
+
+ /*
+ * hack hack hack... we know that the fourth character of the
+ * relation name is a 'v', and that the fourth character of the index
+ * name is an 'x', and that they're otherwise identical.
+ */
+ indname[3] = 'x';
+ indrel = index_openr(indname);
+
+ if (!RelationIsValid(indrel))
+ return ((LargeObjectDesc *) NULL);
+
+ retval = (LargeObjectDesc *) palloc(sizeof(LargeObjectDesc));
+
+ retval->heap_r = r;
+ retval->index_r = indrel;
+ retval->iscan = (IndexScanDesc) NULL;
+ retval->hdesc = RelationGetTupleDescriptor(r);
+ retval->idesc = RelationGetTupleDescriptor(indrel);
+ retval->offset = retval->lowbyte = retval->highbyte = 0;
+ ItemPointerSetInvalid(&(retval->htid));
+
+ if (flags & INV_WRITE)
+ {
+ RelationSetLockForWrite(r);
+ retval->flags = IFS_WRLOCK | IFS_RDLOCK;
+ }
+ else if (flags & INV_READ)
+ {
+ RelationSetLockForRead(r);
+ retval->flags = IFS_RDLOCK;
+ }
+
+ return (retval);
}
/*
* Closes an existing large object descriptor.
*/
void
-inv_close(LargeObjectDesc *obj_desc)
+inv_close(LargeObjectDesc * obj_desc)
{
- Assert(PointerIsValid(obj_desc));
+ Assert(PointerIsValid(obj_desc));
- if (obj_desc->iscan != (IndexScanDesc) NULL)
- index_endscan(obj_desc->iscan);
+ if (obj_desc->iscan != (IndexScanDesc) NULL)
+ index_endscan(obj_desc->iscan);
- heap_close(obj_desc->heap_r);
- index_close(obj_desc->index_r);
+ heap_close(obj_desc->heap_r);
+ index_close(obj_desc->index_r);
- pfree(obj_desc);
+ pfree(obj_desc);
}
/*
@@ -273,897 +288,941 @@ inv_close(LargeObjectDesc *obj_desc)
int
inv_destroy(Oid lobjId)
{
- Relation r;
+ Relation r;
- r = (Relation) RelationIdGetRelation(lobjId);
- if (!RelationIsValid(r) || r->rd_rel->relkind == RELKIND_INDEX)
- return -1;
+ r = (Relation) RelationIdGetRelation(lobjId);
+ if (!RelationIsValid(r) || r->rd_rel->relkind == RELKIND_INDEX)
+ return -1;
- heap_destroy(r->rd_rel->relname.data);
- return 1;
+ heap_destroy(r->rd_rel->relname.data);
+ return 1;
}
/*
- * inv_stat() -- do a stat on an inversion file.
+ * inv_stat() -- do a stat on an inversion file.
*
- * For the time being, this is an insanely expensive operation. In
- * order to find the size of the file, we seek to the last block in
- * it and compute the size from that. We scan pg_class to determine
- * the file's owner and create time. We don't maintain mod time or
- * access time, yet.
+ * For the time being, this is an insanely expensive operation. In
+ * order to find the size of the file, we seek to the last block in
+ * it and compute the size from that. We scan pg_class to determine
+ * the file's owner and create time. We don't maintain mod time or
+ * access time, yet.
*
- * These fields aren't stored in a table anywhere because they're
- * updated so frequently, and postgres only appends tuples at the
- * end of relations. Once clustering works, we should fix this.
+ * These fields aren't stored in a table anywhere because they're
+ * updated so frequently, and postgres only appends tuples at the
+ * end of relations. Once clustering works, we should fix this.
*/
#ifdef NOT_USED
int
-inv_stat(LargeObjectDesc *obj_desc, struct pgstat *stbuf)
+inv_stat(LargeObjectDesc * obj_desc, struct pgstat * stbuf)
{
- Assert(PointerIsValid(obj_desc));
- Assert(stbuf != NULL);
-
- /* need read lock for stat */
- if (!(obj_desc->flags & IFS_RDLOCK)) {
- RelationSetLockForRead(obj_desc->heap_r);
- obj_desc->flags |= IFS_RDLOCK;
- }
+ Assert(PointerIsValid(obj_desc));
+ Assert(stbuf != NULL);
+
+ /* need read lock for stat */
+ if (!(obj_desc->flags & IFS_RDLOCK))
+ {
+ RelationSetLockForRead(obj_desc->heap_r);
+ obj_desc->flags |= IFS_RDLOCK;
+ }
- stbuf->st_ino = obj_desc->heap_r->rd_id;
+ stbuf->st_ino = obj_desc->heap_r->rd_id;
#if 1
- stbuf->st_mode = (S_IFREG | 0666); /* IFREG|rw-rw-rw- */
+ stbuf->st_mode = (S_IFREG | 0666); /* IFREG|rw-rw-rw- */
#else
- stbuf->st_mode = 100666; /* IFREG|rw-rw-rw- */
+ stbuf->st_mode = 100666; /* IFREG|rw-rw-rw- */
#endif
- stbuf->st_size = _inv_getsize(obj_desc->heap_r,
- obj_desc->hdesc,
- obj_desc->index_r);
+ stbuf->st_size = _inv_getsize(obj_desc->heap_r,
+ obj_desc->hdesc,
+ obj_desc->index_r);
- stbuf->st_uid = obj_desc->heap_r->rd_rel->relowner;
+ stbuf->st_uid = obj_desc->heap_r->rd_rel->relowner;
- /* we have no good way of computing access times right now */
- stbuf->st_atime_s = stbuf->st_mtime_s = stbuf->st_ctime_s = 0;
+ /* we have no good way of computing access times right now */
+ stbuf->st_atime_s = stbuf->st_mtime_s = stbuf->st_ctime_s = 0;
- return (0);
+ return (0);
}
+
#endif
int
-inv_seek(LargeObjectDesc *obj_desc, int offset, int whence)
+inv_seek(LargeObjectDesc * obj_desc, int offset, int whence)
{
- int oldOffset;
- Datum d;
- ScanKeyData skey;
-
- Assert(PointerIsValid(obj_desc));
-
- if (whence == SEEK_CUR) {
- offset += obj_desc->offset; /* calculate absolute position */
- return (inv_seek(obj_desc, offset, SEEK_SET));
- }
-
- /*
- * if you seek past the end (offset > 0) I have
- * no clue what happens :-( B.L. 9/1/93
- */
- if (whence == SEEK_END) {
- /* need read lock for getsize */
- if (!(obj_desc->flags & IFS_RDLOCK)) {
- RelationSetLockForRead(obj_desc->heap_r);
- obj_desc->flags |= IFS_RDLOCK;
- }
- offset += _inv_getsize(obj_desc->heap_r,
- obj_desc->hdesc,
- obj_desc->index_r );
- return (inv_seek(obj_desc, offset, SEEK_SET));
- }
-
- /*
- * Whenever we do a seek, we turn off the EOF flag bit to force
- * ourselves to check for real on the next read.
- */
-
- obj_desc->flags &= ~IFS_ATEOF;
- oldOffset = obj_desc->offset;
- obj_desc->offset = offset;
-
- /* try to avoid doing any work, if we can manage it */
- if (offset >= obj_desc->lowbyte
- && offset <= obj_desc->highbyte
- && oldOffset <= obj_desc->highbyte
- && obj_desc->iscan != (IndexScanDesc) NULL)
- return (offset);
-
- /*
- * To do a seek on an inversion file, we start an index scan that
- * will bring us to the right place. Each tuple in an inversion file
- * stores the offset of the last byte that appears on it, and we have
- * an index on this.
- */
-
-
- /* right now, just assume that the operation is SEEK_SET */
- if (obj_desc->iscan != (IndexScanDesc) NULL) {
- d = Int32GetDatum(offset);
- btmovescan(obj_desc->iscan, d);
- } else {
-
- ScanKeyEntryInitialize(&skey, 0x0, 1, INT4GE_PROC_OID,
- Int32GetDatum(offset));
-
- obj_desc->iscan = index_beginscan(obj_desc->index_r,
- (bool) 0, (uint16) 1,
- &skey);
- }
-
- return (offset);
-}
+ int oldOffset;
+ Datum d;
+ ScanKeyData skey;
-int
-inv_tell(LargeObjectDesc *obj_desc)
-{
- Assert(PointerIsValid(obj_desc));
+ Assert(PointerIsValid(obj_desc));
- return (obj_desc->offset);
-}
+ if (whence == SEEK_CUR)
+ {
+ offset += obj_desc->offset; /* calculate absolute position */
+ return (inv_seek(obj_desc, offset, SEEK_SET));
+ }
-int
-inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes)
-{
- HeapTuple htup;
- Buffer b;
- int nread;
- int off;
- int ncopy;
- Datum d;
- struct varlena *fsblock;
- bool isNull;
-
- Assert(PointerIsValid(obj_desc));
- Assert(buf != NULL);
-
- /* if we're already at EOF, we don't need to do any work here */
- if (obj_desc->flags & IFS_ATEOF)
- return (0);
+ /*
+ * if you seek past the end (offset > 0) I have no clue what happens
+ * :-( B.L. 9/1/93
+ */
+ if (whence == SEEK_END)
+ {
+ /* need read lock for getsize */
+ if (!(obj_desc->flags & IFS_RDLOCK))
+ {
+ RelationSetLockForRead(obj_desc->heap_r);
+ obj_desc->flags |= IFS_RDLOCK;
+ }
+ offset += _inv_getsize(obj_desc->heap_r,
+ obj_desc->hdesc,
+ obj_desc->index_r);
+ return (inv_seek(obj_desc, offset, SEEK_SET));
+ }
- /* make sure we obey two-phase locking */
- if (!(obj_desc->flags & IFS_RDLOCK)) {
- RelationSetLockForRead(obj_desc->heap_r);
- obj_desc->flags |= IFS_RDLOCK;
- }
+ /*
+ * Whenever we do a seek, we turn off the EOF flag bit to force
+ * ourselves to check for real on the next read.
+ */
- nread = 0;
+ obj_desc->flags &= ~IFS_ATEOF;
+ oldOffset = obj_desc->offset;
+ obj_desc->offset = offset;
- /* fetch a block at a time */
- while (nread < nbytes) {
+ /* try to avoid doing any work, if we can manage it */
+ if (offset >= obj_desc->lowbyte
+ && offset <= obj_desc->highbyte
+ && oldOffset <= obj_desc->highbyte
+ && obj_desc->iscan != (IndexScanDesc) NULL)
+ return (offset);
+
+ /*
+ * To do a seek on an inversion file, we start an index scan that will
+ * bring us to the right place. Each tuple in an inversion file
+ * stores the offset of the last byte that appears on it, and we have
+ * an index on this.
+ */
- /* fetch an inversion file system block */
- htup = inv_fetchtup(obj_desc, &b);
- if (!HeapTupleIsValid(htup)) {
- obj_desc->flags |= IFS_ATEOF;
- break;
+ /* right now, just assume that the operation is SEEK_SET */
+ if (obj_desc->iscan != (IndexScanDesc) NULL)
+ {
+ d = Int32GetDatum(offset);
+ btmovescan(obj_desc->iscan, d);
}
+ else
+ {
- /* copy the data from this block into the buffer */
- d = (Datum) heap_getattr(htup, b, 2, obj_desc->hdesc, &isNull);
- fsblock = (struct varlena *) DatumGetPointer(d);
+ ScanKeyEntryInitialize(&skey, 0x0, 1, INT4GE_PROC_OID,
+ Int32GetDatum(offset));
- off = obj_desc->offset - obj_desc->lowbyte;
- ncopy = obj_desc->highbyte - obj_desc->offset + 1;
- if (ncopy > (nbytes - nread))
- ncopy = (nbytes - nread);
- memmove(buf, &(fsblock->vl_dat[off]), ncopy);
+ obj_desc->iscan = index_beginscan(obj_desc->index_r,
+ (bool) 0, (uint16) 1,
+ &skey);
+ }
- /* be a good citizen */
- ReleaseBuffer(b);
+ return (offset);
+}
- /* move pointers past the amount we just read */
- buf += ncopy;
- nread += ncopy;
- obj_desc->offset += ncopy;
- }
+int
+inv_tell(LargeObjectDesc * obj_desc)
+{
+ Assert(PointerIsValid(obj_desc));
- /* that's it */
- return (nread);
+ return (obj_desc->offset);
}
int
-inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes)
+inv_read(LargeObjectDesc * obj_desc, char *buf, int nbytes)
{
- HeapTuple htup;
- Buffer b;
- int nwritten;
- int tuplen;
+ HeapTuple htup;
+ Buffer b;
+ int nread;
+ int off;
+ int ncopy;
+ Datum d;
+ struct varlena *fsblock;
+ bool isNull;
+
+ Assert(PointerIsValid(obj_desc));
+ Assert(buf != NULL);
+
+ /* if we're already at EOF, we don't need to do any work here */
+ if (obj_desc->flags & IFS_ATEOF)
+ return (0);
+
+ /* make sure we obey two-phase locking */
+ if (!(obj_desc->flags & IFS_RDLOCK))
+ {
+ RelationSetLockForRead(obj_desc->heap_r);
+ obj_desc->flags |= IFS_RDLOCK;
+ }
+
+ nread = 0;
+
+ /* fetch a block at a time */
+ while (nread < nbytes)
+ {
+
+ /* fetch an inversion file system block */
+ htup = inv_fetchtup(obj_desc, &b);
- Assert(PointerIsValid(obj_desc));
- Assert(buf != NULL);
+ if (!HeapTupleIsValid(htup))
+ {
+ obj_desc->flags |= IFS_ATEOF;
+ break;
+ }
- /*
- * Make sure we obey two-phase locking. A write lock entitles you
- * to read the relation, as well.
- */
+ /* copy the data from this block into the buffer */
+ d = (Datum) heap_getattr(htup, b, 2, obj_desc->hdesc, &isNull);
+ fsblock = (struct varlena *) DatumGetPointer(d);
- if (!(obj_desc->flags & IFS_WRLOCK)) {
- RelationSetLockForRead(obj_desc->heap_r);
- obj_desc->flags |= (IFS_WRLOCK|IFS_RDLOCK);
- }
+ off = obj_desc->offset - obj_desc->lowbyte;
+ ncopy = obj_desc->highbyte - obj_desc->offset + 1;
+ if (ncopy > (nbytes - nread))
+ ncopy = (nbytes - nread);
+ memmove(buf, &(fsblock->vl_dat[off]), ncopy);
- nwritten = 0;
+ /* be a good citizen */
+ ReleaseBuffer(b);
- /* write a block at a time */
- while (nwritten < nbytes) {
+ /* move pointers past the amount we just read */
+ buf += ncopy;
+ nread += ncopy;
+ obj_desc->offset += ncopy;
+ }
+
+ /* that's it */
+ return (nread);
+}
+
+int
+inv_write(LargeObjectDesc * obj_desc, char *buf, int nbytes)
+{
+ HeapTuple htup;
+ Buffer b;
+ int nwritten;
+ int tuplen;
+
+ Assert(PointerIsValid(obj_desc));
+ Assert(buf != NULL);
/*
- * Fetch the current inversion file system block. If the
- * class storing the inversion file is empty, we don't want
- * to do an index lookup, since index lookups choke on empty
- * files (should be fixed someday).
+ * Make sure we obey two-phase locking. A write lock entitles you to
+ * read the relation, as well.
*/
- if ((obj_desc->flags & IFS_ATEOF)
- || obj_desc->heap_r->rd_nblocks == 0)
- htup = (HeapTuple) NULL;
- else
- htup = inv_fetchtup(obj_desc, &b);
-
- /* either append or replace a block, as required */
- if (!HeapTupleIsValid(htup)) {
- tuplen = inv_wrnew(obj_desc, buf, nbytes - nwritten);
- } else {
- if (obj_desc->offset > obj_desc->highbyte)
- tuplen = inv_wrnew(obj_desc, buf, nbytes - nwritten);
- else
- tuplen = inv_wrold(obj_desc, buf, nbytes - nwritten, htup, b);
+ if (!(obj_desc->flags & IFS_WRLOCK))
+ {
+ RelationSetLockForRead(obj_desc->heap_r);
+ obj_desc->flags |= (IFS_WRLOCK | IFS_RDLOCK);
}
- /* move pointers past the amount we just wrote */
- buf += tuplen;
- nwritten += tuplen;
- obj_desc->offset += tuplen;
- }
+ nwritten = 0;
+
+ /* write a block at a time */
+ while (nwritten < nbytes)
+ {
+
+ /*
+ * Fetch the current inversion file system block. If the class
+ * storing the inversion file is empty, we don't want to do an
+ * index lookup, since index lookups choke on empty files (should
+ * be fixed someday).
+ */
+
+ if ((obj_desc->flags & IFS_ATEOF)
+ || obj_desc->heap_r->rd_nblocks == 0)
+ htup = (HeapTuple) NULL;
+ else
+ htup = inv_fetchtup(obj_desc, &b);
+
+ /* either append or replace a block, as required */
+ if (!HeapTupleIsValid(htup))
+ {
+ tuplen = inv_wrnew(obj_desc, buf, nbytes - nwritten);
+ }
+ else
+ {
+ if (obj_desc->offset > obj_desc->highbyte)
+ tuplen = inv_wrnew(obj_desc, buf, nbytes - nwritten);
+ else
+ tuplen = inv_wrold(obj_desc, buf, nbytes - nwritten, htup, b);
+ }
+
+ /* move pointers past the amount we just wrote */
+ buf += tuplen;
+ nwritten += tuplen;
+ obj_desc->offset += tuplen;
+ }
- /* that's it */
- return (nwritten);
+ /* that's it */
+ return (nwritten);
}
/*
- * inv_fetchtup -- Fetch an inversion file system block.
+ * inv_fetchtup -- Fetch an inversion file system block.
*
- * This routine finds the file system block containing the offset
- * recorded in the obj_desc structure. Later, we need to think about
- * the effects of non-functional updates (can you rewrite the same
- * block twice in a single transaction?), but for now, we won't bother.
+ * This routine finds the file system block containing the offset
+ * recorded in the obj_desc structure. Later, we need to think about
+ * the effects of non-functional updates (can you rewrite the same
+ * block twice in a single transaction?), but for now, we won't bother.
*
- * Parameters:
- * obj_desc -- the object descriptor.
- * bufP -- pointer to a buffer in the buffer cache; caller
- * must free this.
+ * Parameters:
+ * obj_desc -- the object descriptor.
+ * bufP -- pointer to a buffer in the buffer cache; caller
+ * must free this.
*
- * Returns:
- * A heap tuple containing the desired block, or NULL if no
- * such tuple exists.
+ * Returns:
+ * A heap tuple containing the desired block, or NULL if no
+ * such tuple exists.
*/
-static HeapTuple
-inv_fetchtup(LargeObjectDesc *obj_desc, Buffer *bufP)
+static HeapTuple
+inv_fetchtup(LargeObjectDesc * obj_desc, Buffer * bufP)
{
- HeapTuple htup;
- RetrieveIndexResult res;
- Datum d;
- int firstbyte, lastbyte;
- struct varlena *fsblock;
- bool isNull;
-
- /*
- * If we've exhausted the current block, we need to get the next one.
- * When we support time travel and non-functional updates, we will
- * need to loop over the blocks, rather than just have an 'if', in
- * order to find the one we're really interested in.
- */
-
- if (obj_desc->offset > obj_desc->highbyte
- || obj_desc->offset < obj_desc->lowbyte
- || !ItemPointerIsValid(&(obj_desc->htid))) {
-
- /* initialize scan key if not done */
- if (obj_desc->iscan==(IndexScanDesc)NULL) {
- ScanKeyData skey;
-
- ScanKeyEntryInitialize(&skey, 0x0, 1, INT4GE_PROC_OID,
- Int32GetDatum(0));
- obj_desc->iscan =
- index_beginscan(obj_desc->index_r,
- (bool) 0, (uint16) 1,
- &skey);
- }
+ HeapTuple htup;
+ RetrieveIndexResult res;
+ Datum d;
+ int firstbyte,
+ lastbyte;
+ struct varlena *fsblock;
+ bool isNull;
- do {
- res = index_getnext(obj_desc->iscan, ForwardScanDirection);
+ /*
+ * If we've exhausted the current block, we need to get the next one.
+ * When we support time travel and non-functional updates, we will
+ * need to loop over the blocks, rather than just have an 'if', in
+ * order to find the one we're really interested in.
+ */
+
+ if (obj_desc->offset > obj_desc->highbyte
+ || obj_desc->offset < obj_desc->lowbyte
+ || !ItemPointerIsValid(&(obj_desc->htid)))
+ {
- if (res == (RetrieveIndexResult) NULL) {
- ItemPointerSetInvalid(&(obj_desc->htid));
- return ((HeapTuple) NULL);
- }
+ /* initialize scan key if not done */
+ if (obj_desc->iscan == (IndexScanDesc) NULL)
+ {
+ ScanKeyData skey;
- /*
- * For time travel, we need to use the actual time qual here,
- * rather that NowTimeQual. We currently have no way to pass
- * a time qual in.
- */
+ ScanKeyEntryInitialize(&skey, 0x0, 1, INT4GE_PROC_OID,
+ Int32GetDatum(0));
+ obj_desc->iscan =
+ index_beginscan(obj_desc->index_r,
+ (bool) 0, (uint16) 1,
+ &skey);
+ }
- htup = heap_fetch(obj_desc->heap_r, NowTimeQual,
- &(res->heap_iptr), bufP);
+ do
+ {
+ res = index_getnext(obj_desc->iscan, ForwardScanDirection);
- } while (htup == (HeapTuple) NULL);
+ if (res == (RetrieveIndexResult) NULL)
+ {
+ ItemPointerSetInvalid(&(obj_desc->htid));
+ return ((HeapTuple) NULL);
+ }
- /* remember this tid -- we may need it for later reads/writes */
- ItemPointerCopy(&(res->heap_iptr), &(obj_desc->htid));
+ /*
+ * For time travel, we need to use the actual time qual here,
+ * rather that NowTimeQual. We currently have no way to pass
+ * a time qual in.
+ */
- } else {
- htup = heap_fetch(obj_desc->heap_r, NowTimeQual,
- &(obj_desc->htid), bufP);
- }
+ htup = heap_fetch(obj_desc->heap_r, NowTimeQual,
+ &(res->heap_iptr), bufP);
- /*
- * By here, we have the heap tuple we're interested in. We cache
- * the upper and lower bounds for this block in the object descriptor
- * and return the tuple.
- */
+ } while (htup == (HeapTuple) NULL);
+
+ /* remember this tid -- we may need it for later reads/writes */
+ ItemPointerCopy(&(res->heap_iptr), &(obj_desc->htid));
+
+ }
+ else
+ {
+ htup = heap_fetch(obj_desc->heap_r, NowTimeQual,
+ &(obj_desc->htid), bufP);
+ }
+
+ /*
+ * By here, we have the heap tuple we're interested in. We cache the
+ * upper and lower bounds for this block in the object descriptor and
+ * return the tuple.
+ */
- d = (Datum)heap_getattr(htup, *bufP, 1, obj_desc->hdesc, &isNull);
- lastbyte = (int32) DatumGetInt32(d);
- d = (Datum)heap_getattr(htup, *bufP, 2, obj_desc->hdesc, &isNull);
- fsblock = (struct varlena *) DatumGetPointer(d);
+ d = (Datum) heap_getattr(htup, *bufP, 1, obj_desc->hdesc, &isNull);
+ lastbyte = (int32) DatumGetInt32(d);
+ d = (Datum) heap_getattr(htup, *bufP, 2, obj_desc->hdesc, &isNull);
+ fsblock = (struct varlena *) DatumGetPointer(d);
- /* order of + and - is important -- these are unsigned quantites near 0 */
- firstbyte = (lastbyte + 1 + sizeof(fsblock->vl_len)) - fsblock->vl_len;
+ /*
+ * order of + and - is important -- these are unsigned quantites near
+ * 0
+ */
+ firstbyte = (lastbyte + 1 + sizeof(fsblock->vl_len)) - fsblock->vl_len;
- obj_desc->lowbyte = firstbyte;
- obj_desc->highbyte = lastbyte;
+ obj_desc->lowbyte = firstbyte;
+ obj_desc->highbyte = lastbyte;
- /* done */
- return (htup);
+ /* done */
+ return (htup);
}
/*
- * inv_wrnew() -- append a new filesystem block tuple to the inversion
- * file.
+ * inv_wrnew() -- append a new filesystem block tuple to the inversion
+ * file.
*
- * In response to an inv_write, we append one or more file system
- * blocks to the class containing the large object. We violate the
- * class abstraction here in order to pack things as densely as we
- * are able. We examine the last page in the relation, and write
- * just enough to fill it, assuming that it has above a certain
- * threshold of space available. If the space available is less than
- * the threshold, we allocate a new page by writing a big tuple.
+ * In response to an inv_write, we append one or more file system
+ * blocks to the class containing the large object. We violate the
+ * class abstraction here in order to pack things as densely as we
+ * are able. We examine the last page in the relation, and write
+ * just enough to fill it, assuming that it has above a certain
+ * threshold of space available. If the space available is less than
+ * the threshold, we allocate a new page by writing a big tuple.
*
- * By the time we get here, we know all the parameters passed in
- * are valid, and that we hold the appropriate lock on the heap
- * relation.
+ * By the time we get here, we know all the parameters passed in
+ * are valid, and that we hold the appropriate lock on the heap
+ * relation.
*
- * Parameters:
- * obj_desc: large object descriptor for which to append block.
- * buf: buffer containing data to write.
- * nbytes: amount to write
+ * Parameters:
+ * obj_desc: large object descriptor for which to append block.
+ * buf: buffer containing data to write.
+ * nbytes: amount to write
*
- * Returns:
- * number of bytes actually written to the new tuple.
+ * Returns:
+ * number of bytes actually written to the new tuple.
*/
static int
-inv_wrnew(LargeObjectDesc *obj_desc, char *buf, int nbytes)
+inv_wrnew(LargeObjectDesc * obj_desc, char *buf, int nbytes)
{
- Relation hr;
- HeapTuple ntup;
- Buffer buffer;
- Page page;
- int nblocks;
- int nwritten;
-
- hr = obj_desc->heap_r;
-
- /*
- * Get the last block in the relation. If there's no data in the
- * relation at all, then we just get a new block. Otherwise, we
- * check the last block to see whether it has room to accept some
- * or all of the data that the user wants to write. If it doesn't,
- * then we allocate a new block.
- */
-
- nblocks = RelationGetNumberOfBlocks(hr);
-
- if (nblocks > 0)
- buffer = ReadBuffer(hr, nblocks - 1);
- else
- buffer = ReadBuffer(hr, P_NEW);
-
- page = BufferGetPage(buffer);
-
- /*
- * If the last page is too small to hold all the data, and it's too
- * small to hold IMINBLK, then we allocate a new page. If it will
- * hold at least IMINBLK, but less than all the data requested, then
- * we write IMINBLK here. The caller is responsible for noticing that
- * less than the requested number of bytes were written, and calling
- * this routine again.
- */
-
- nwritten = IFREESPC(page);
- if (nwritten < nbytes) {
- if (nwritten < IMINBLK) {
- ReleaseBuffer(buffer);
- buffer = ReadBuffer(hr, P_NEW);
- page = BufferGetPage(buffer);
- PageInit(page, BufferGetPageSize(buffer), 0);
- if (nbytes > IMAXBLK)
- nwritten = IMAXBLK;
- else
+ Relation hr;
+ HeapTuple ntup;
+ Buffer buffer;
+ Page page;
+ int nblocks;
+ int nwritten;
+
+ hr = obj_desc->heap_r;
+
+ /*
+ * Get the last block in the relation. If there's no data in the
+ * relation at all, then we just get a new block. Otherwise, we check
+ * the last block to see whether it has room to accept some or all of
+ * the data that the user wants to write. If it doesn't, then we
+ * allocate a new block.
+ */
+
+ nblocks = RelationGetNumberOfBlocks(hr);
+
+ if (nblocks > 0)
+ buffer = ReadBuffer(hr, nblocks - 1);
+ else
+ buffer = ReadBuffer(hr, P_NEW);
+
+ page = BufferGetPage(buffer);
+
+ /*
+ * If the last page is too small to hold all the data, and it's too
+ * small to hold IMINBLK, then we allocate a new page. If it will
+ * hold at least IMINBLK, but less than all the data requested, then
+ * we write IMINBLK here. The caller is responsible for noticing that
+ * less than the requested number of bytes were written, and calling
+ * this routine again.
+ */
+
+ nwritten = IFREESPC(page);
+ if (nwritten < nbytes)
+ {
+ if (nwritten < IMINBLK)
+ {
+ ReleaseBuffer(buffer);
+ buffer = ReadBuffer(hr, P_NEW);
+ page = BufferGetPage(buffer);
+ PageInit(page, BufferGetPageSize(buffer), 0);
+ if (nbytes > IMAXBLK)
+ nwritten = IMAXBLK;
+ else
+ nwritten = nbytes;
+ }
+ }
+ else
+ {
nwritten = nbytes;
}
- } else {
- nwritten = nbytes;
- }
- /*
- * Insert a new file system block tuple, index it, and write it out.
- */
+ /*
+ * Insert a new file system block tuple, index it, and write it out.
+ */
- ntup = inv_newtuple(obj_desc, buffer, page, buf, nwritten);
- inv_indextup(obj_desc, ntup);
+ ntup = inv_newtuple(obj_desc, buffer, page, buf, nwritten);
+ inv_indextup(obj_desc, ntup);
- /* new tuple is inserted */
- WriteBuffer(buffer);
+ /* new tuple is inserted */
+ WriteBuffer(buffer);
- return (nwritten);
+ return (nwritten);
}
static int
-inv_wrold(LargeObjectDesc *obj_desc,
- char *dbuf,
- int nbytes,
- HeapTuple htup,
- Buffer buffer)
+inv_wrold(LargeObjectDesc * obj_desc,
+ char *dbuf,
+ int nbytes,
+ HeapTuple htup,
+ Buffer buffer)
{
- Relation hr;
- HeapTuple ntup;
- Buffer newbuf;
- Page page;
- Page newpage;
- int tupbytes;
- Datum d;
- struct varlena *fsblock;
- int nwritten, nblocks, freespc;
- bool isNull;
- int keep_offset;
-
- /*
- * Since we're using a no-overwrite storage manager, the way we
- * overwrite blocks is to mark the old block invalid and append
- * a new block. First mark the old block invalid. This violates
- * the tuple abstraction.
- */
-
- TransactionIdStore(GetCurrentTransactionId(), &(htup->t_xmax));
- htup->t_cmax = GetCurrentCommandId();
-
- /*
- * If we're overwriting the entire block, we're lucky. All we need
- * to do is to insert a new block.
- */
-
- if (obj_desc->offset == obj_desc->lowbyte
- && obj_desc->lowbyte + nbytes >= obj_desc->highbyte) {
- WriteBuffer(buffer);
- return (inv_wrnew(obj_desc, dbuf, nbytes));
- }
-
- /*
- * By here, we need to overwrite part of the data in the current
- * tuple. In order to reduce the degree to which we fragment blocks,
- * we guarantee that no block will be broken up due to an overwrite.
- * This means that we need to allocate a tuple on a new page, if
- * there's not room for the replacement on this one.
- */
-
- newbuf = buffer;
- page = BufferGetPage(buffer);
- newpage = BufferGetPage(newbuf);
- hr = obj_desc->heap_r;
- freespc = IFREESPC(page);
- d = (Datum)heap_getattr(htup, buffer, 2, obj_desc->hdesc, &isNull);
- fsblock = (struct varlena *) DatumGetPointer(d);
- tupbytes = fsblock->vl_len - sizeof(fsblock->vl_len);
-
- if (freespc < tupbytes) {
+ Relation hr;
+ HeapTuple ntup;
+ Buffer newbuf;
+ Page page;
+ Page newpage;
+ int tupbytes;
+ Datum d;
+ struct varlena *fsblock;
+ int nwritten,
+ nblocks,
+ freespc;
+ bool isNull;
+ int keep_offset;
/*
- * First see if there's enough space on the last page of the
- * table to put this tuple.
+ * Since we're using a no-overwrite storage manager, the way we
+ * overwrite blocks is to mark the old block invalid and append a new
+ * block. First mark the old block invalid. This violates the tuple
+ * abstraction.
*/
- nblocks = RelationGetNumberOfBlocks(hr);
+ TransactionIdStore(GetCurrentTransactionId(), &(htup->t_xmax));
+ htup->t_cmax = GetCurrentCommandId();
- if (nblocks > 0)
- newbuf = ReadBuffer(hr, nblocks - 1);
- else
- newbuf = ReadBuffer(hr, P_NEW);
+ /*
+ * If we're overwriting the entire block, we're lucky. All we need to
+ * do is to insert a new block.
+ */
- newpage = BufferGetPage(newbuf);
- freespc = IFREESPC(newpage);
+ if (obj_desc->offset == obj_desc->lowbyte
+ && obj_desc->lowbyte + nbytes >= obj_desc->highbyte)
+ {
+ WriteBuffer(buffer);
+ return (inv_wrnew(obj_desc, dbuf, nbytes));
+ }
/*
- * If there's no room on the last page, allocate a new last
- * page for the table, and put it there.
+ * By here, we need to overwrite part of the data in the current
+ * tuple. In order to reduce the degree to which we fragment blocks,
+ * we guarantee that no block will be broken up due to an overwrite.
+ * This means that we need to allocate a tuple on a new page, if
+ * there's not room for the replacement on this one.
*/
- if (freespc < tupbytes) {
- ReleaseBuffer(newbuf);
- newbuf = ReadBuffer(hr, P_NEW);
- newpage = BufferGetPage(newbuf);
- PageInit(newpage, BufferGetPageSize(newbuf), 0);
+ newbuf = buffer;
+ page = BufferGetPage(buffer);
+ newpage = BufferGetPage(newbuf);
+ hr = obj_desc->heap_r;
+ freespc = IFREESPC(page);
+ d = (Datum) heap_getattr(htup, buffer, 2, obj_desc->hdesc, &isNull);
+ fsblock = (struct varlena *) DatumGetPointer(d);
+ tupbytes = fsblock->vl_len - sizeof(fsblock->vl_len);
+
+ if (freespc < tupbytes)
+ {
+
+ /*
+ * First see if there's enough space on the last page of the table
+ * to put this tuple.
+ */
+
+ nblocks = RelationGetNumberOfBlocks(hr);
+
+ if (nblocks > 0)
+ newbuf = ReadBuffer(hr, nblocks - 1);
+ else
+ newbuf = ReadBuffer(hr, P_NEW);
+
+ newpage = BufferGetPage(newbuf);
+ freespc = IFREESPC(newpage);
+
+ /*
+ * If there's no room on the last page, allocate a new last page
+ * for the table, and put it there.
+ */
+
+ if (freespc < tupbytes)
+ {
+ ReleaseBuffer(newbuf);
+ newbuf = ReadBuffer(hr, P_NEW);
+ newpage = BufferGetPage(newbuf);
+ PageInit(newpage, BufferGetPageSize(newbuf), 0);
+ }
}
- }
-
- nwritten = nbytes;
- if (nwritten > obj_desc->highbyte - obj_desc->offset + 1)
- nwritten = obj_desc->highbyte - obj_desc->offset + 1;
- memmove(VARDATA(fsblock)+ (obj_desc->offset - obj_desc->lowbyte),
- dbuf,nwritten);
- /* we are rewriting the entire old block, therefore
- we reset offset to the lowbyte of the original block
- before jumping into inv_newtuple() */
- keep_offset = obj_desc->offset;
- obj_desc->offset = obj_desc->lowbyte;
- ntup = inv_newtuple(obj_desc, newbuf, newpage, VARDATA(fsblock),
- tupbytes);
- /* after we are done, we restore to the true offset */
- obj_desc->offset = keep_offset;
-
- /*
- * By here, we have a page (newpage) that's guaranteed to have
- * enough space on it to put the new tuple. Call inv_newtuple
- * to do the work. Passing NULL as a buffer to inv_newtuple()
- * keeps it from copying any data into the new tuple. When it
- * returns, the tuple is ready to receive data from the old
- * tuple and the user's data buffer.
- */
-/*
- ntup = inv_newtuple(obj_desc, newbuf, newpage, (char *) NULL, tupbytes);
- dptr = ((char *) ntup) + ntup->t_hoff - sizeof(ntup->t_bits) + sizeof(int4)
- + sizeof(fsblock->vl_len);
- if (obj_desc->offset > obj_desc->lowbyte) {
- memmove(dptr,
- &(fsblock->vl_dat[0]),
- obj_desc->offset - obj_desc->lowbyte);
- dptr += obj_desc->offset - obj_desc->lowbyte;
- }
+ nwritten = nbytes;
+ if (nwritten > obj_desc->highbyte - obj_desc->offset + 1)
+ nwritten = obj_desc->highbyte - obj_desc->offset + 1;
+ memmove(VARDATA(fsblock) + (obj_desc->offset - obj_desc->lowbyte),
+ dbuf, nwritten);
+
+ /*
+ * we are rewriting the entire old block, therefore we reset offset to
+ * the lowbyte of the original block before jumping into
+ * inv_newtuple()
+ */
+ keep_offset = obj_desc->offset;
+ obj_desc->offset = obj_desc->lowbyte;
+ ntup = inv_newtuple(obj_desc, newbuf, newpage, VARDATA(fsblock),
+ tupbytes);
+ /* after we are done, we restore to the true offset */
+ obj_desc->offset = keep_offset;
+
+ /*
+ * By here, we have a page (newpage) that's guaranteed to have enough
+ * space on it to put the new tuple. Call inv_newtuple to do the
+ * work. Passing NULL as a buffer to inv_newtuple() keeps it from
+ * copying any data into the new tuple. When it returns, the tuple is
+ * ready to receive data from the old tuple and the user's data
+ * buffer.
+ */
+/*
+ ntup = inv_newtuple(obj_desc, newbuf, newpage, (char *) NULL, tupbytes);
+ dptr = ((char *) ntup) + ntup->t_hoff - sizeof(ntup->t_bits) + sizeof(int4)
+ + sizeof(fsblock->vl_len);
+
+ if (obj_desc->offset > obj_desc->lowbyte) {
+ memmove(dptr,
+ &(fsblock->vl_dat[0]),
+ obj_desc->offset - obj_desc->lowbyte);
+ dptr += obj_desc->offset - obj_desc->lowbyte;
+ }
- nwritten = nbytes;
- if (nwritten > obj_desc->highbyte - obj_desc->offset + 1)
- nwritten = obj_desc->highbyte - obj_desc->offset + 1;
+ nwritten = nbytes;
+ if (nwritten > obj_desc->highbyte - obj_desc->offset + 1)
+ nwritten = obj_desc->highbyte - obj_desc->offset + 1;
- memmove(dptr, dbuf, nwritten);
- dptr += nwritten;
+ memmove(dptr, dbuf, nwritten);
+ dptr += nwritten;
- if (obj_desc->offset + nwritten < obj_desc->highbyte + 1) {
+ if (obj_desc->offset + nwritten < obj_desc->highbyte + 1) {
*/
/*
- loc = (obj_desc->highbyte - obj_desc->offset)
- + nwritten;
- sz = obj_desc->highbyte - (obj_desc->lowbyte + loc);
+ loc = (obj_desc->highbyte - obj_desc->offset)
+ + nwritten;
+ sz = obj_desc->highbyte - (obj_desc->lowbyte + loc);
- what's going on here?? - jolly
+ what's going on here?? - jolly
*/
/*
- sz = (obj_desc->highbyte + 1) - (obj_desc->offset + nwritten);
- memmove(&(fsblock->vl_dat[0]), dptr, sz);
- }
+ sz = (obj_desc->highbyte + 1) - (obj_desc->offset + nwritten);
+ memmove(&(fsblock->vl_dat[0]), dptr, sz);
+ }
*/
- /* index the new tuple */
- inv_indextup(obj_desc, ntup);
+ /* index the new tuple */
+ inv_indextup(obj_desc, ntup);
- /* move the scandesc forward so we don't reread the newly inserted
- tuple on the next index scan */
- if (obj_desc->iscan)
- index_getnext(obj_desc->iscan, ForwardScanDirection);
+ /*
+ * move the scandesc forward so we don't reread the newly inserted
+ * tuple on the next index scan
+ */
+ if (obj_desc->iscan)
+ index_getnext(obj_desc->iscan, ForwardScanDirection);
- /*
- * Okay, by here, a tuple for the new block is correctly placed,
- * indexed, and filled. Write the changed pages out.
- */
+ /*
+ * Okay, by here, a tuple for the new block is correctly placed,
+ * indexed, and filled. Write the changed pages out.
+ */
- WriteBuffer(buffer);
- if (newbuf != buffer)
- WriteBuffer(newbuf);
+ WriteBuffer(buffer);
+ if (newbuf != buffer)
+ WriteBuffer(newbuf);
- /* done */
- return (nwritten);
+ /* done */
+ return (nwritten);
}
-static HeapTuple
-inv_newtuple(LargeObjectDesc *obj_desc,
- Buffer buffer,
- Page page,
- char *dbuf,
- int nwrite)
+static HeapTuple
+inv_newtuple(LargeObjectDesc * obj_desc,
+ Buffer buffer,
+ Page page,
+ char *dbuf,
+ int nwrite)
{
- HeapTuple ntup;
- PageHeader ph;
- int tupsize;
- int hoff;
- Offset lower;
- Offset upper;
- ItemId itemId;
- OffsetNumber off;
- OffsetNumber limit;
- char *attptr;
-
- /* compute tuple size -- no nulls */
- hoff = sizeof(HeapTupleData) - sizeof(ntup->t_bits);
-
- /* add in olastbyte, varlena.vl_len, varlena.vl_dat */
- tupsize = hoff + (2 * sizeof(int32)) + nwrite;
- tupsize = LONGALIGN(tupsize);
-
- /*
- * Allocate the tuple on the page, violating the page abstraction.
- * This code was swiped from PageAddItem().
- */
-
- ph = (PageHeader) page;
- limit = OffsetNumberNext(PageGetMaxOffsetNumber(page));
-
- /* look for "recyclable" (unused & deallocated) ItemId */
- for (off = FirstOffsetNumber; off < limit; off = OffsetNumberNext(off)) {
+ HeapTuple ntup;
+ PageHeader ph;
+ int tupsize;
+ int hoff;
+ Offset lower;
+ Offset upper;
+ ItemId itemId;
+ OffsetNumber off;
+ OffsetNumber limit;
+ char *attptr;
+
+ /* compute tuple size -- no nulls */
+ hoff = sizeof(HeapTupleData) - sizeof(ntup->t_bits);
+
+ /* add in olastbyte, varlena.vl_len, varlena.vl_dat */
+ tupsize = hoff + (2 * sizeof(int32)) + nwrite;
+ tupsize = LONGALIGN(tupsize);
+
+ /*
+ * Allocate the tuple on the page, violating the page abstraction.
+ * This code was swiped from PageAddItem().
+ */
+
+ ph = (PageHeader) page;
+ limit = OffsetNumberNext(PageGetMaxOffsetNumber(page));
+
+ /* look for "recyclable" (unused & deallocated) ItemId */
+ for (off = FirstOffsetNumber; off < limit; off = OffsetNumberNext(off))
+ {
+ itemId = &ph->pd_linp[off - 1];
+ if ((((*itemId).lp_flags & LP_USED) == 0) &&
+ ((*itemId).lp_len == 0))
+ break;
+ }
+
+ if (off > limit)
+ lower = (Offset) (((char *) (&ph->pd_linp[off])) - ((char *) page));
+ else if (off == limit)
+ lower = ph->pd_lower + sizeof(ItemIdData);
+ else
+ lower = ph->pd_lower;
+
+ upper = ph->pd_upper - tupsize;
+
itemId = &ph->pd_linp[off - 1];
- if ((((*itemId).lp_flags & LP_USED) == 0) &&
- ((*itemId).lp_len == 0))
- break;
- }
-
- if (off > limit)
- lower = (Offset) (((char *) (&ph->pd_linp[off])) - ((char *) page));
- else if (off == limit)
- lower = ph->pd_lower + sizeof (ItemIdData);
- else
- lower = ph->pd_lower;
-
- upper = ph->pd_upper - tupsize;
-
- itemId = &ph->pd_linp[off - 1];
- (*itemId).lp_off = upper;
- (*itemId).lp_len = tupsize;
- (*itemId).lp_flags = LP_USED;
- ph->pd_lower = lower;
- ph->pd_upper = upper;
-
- ntup = (HeapTuple) ((char *) page + upper);
-
- /*
- * Tuple is now allocated on the page. Next, fill in the tuple
- * header. This block of code violates the tuple abstraction.
- */
-
- ntup->t_len = tupsize;
- ItemPointerSet(&(ntup->t_ctid), BufferGetBlockNumber(buffer), off);
- ItemPointerSetInvalid(&(ntup->t_chain));
- LastOidProcessed = ntup->t_oid = newoid();
- TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_xmin));
- ntup->t_cmin = GetCurrentCommandId();
- StoreInvalidTransactionId(&(ntup->t_xmax));
- ntup->t_cmax = 0;
- ntup->t_tmin = INVALID_ABSTIME;
- ntup->t_tmax = CURRENT_ABSTIME;
- ntup->t_natts = 2;
- ntup->t_hoff = hoff;
- ntup->t_vtype = 0;
- ntup->t_infomask = 0x0;
-
- /* if a NULL is passed in, avoid the calculations below */
- if (dbuf == NULL)
- return ntup;
-
- /*
- * Finally, copy the user's data buffer into the tuple. This violates
- * the tuple and class abstractions.
- */
-
- attptr = ((char *) ntup) + hoff;
- *((int32 *) attptr) = obj_desc->offset + nwrite - 1;
- attptr += sizeof(int32);
-
- /*
- ** mer fixed disk layout of varlenas to get rid of the need for this.
- **
- ** *((int32 *) attptr) = nwrite + sizeof(int32);
- ** attptr += sizeof(int32);
- */
-
- *((int32 *) attptr) = nwrite + sizeof(int32);
- attptr += sizeof(int32);
-
- /*
- * If a data buffer was passed in, then copy the data from the buffer
- * to the tuple. Some callers (eg, inv_wrold()) may not pass in a
- * buffer, since they have to copy part of the old tuple data and
- * part of the user's new data into the new tuple.
- */
-
- if (dbuf != (char *) NULL)
- memmove(attptr, dbuf, nwrite);
-
- /* keep track of boundary of current tuple */
- obj_desc->lowbyte = obj_desc->offset;
- obj_desc->highbyte = obj_desc->offset + nwrite - 1;
-
- /* new tuple is filled -- return it */
- return (ntup);
+ (*itemId).lp_off = upper;
+ (*itemId).lp_len = tupsize;
+ (*itemId).lp_flags = LP_USED;
+ ph->pd_lower = lower;
+ ph->pd_upper = upper;
+
+ ntup = (HeapTuple) ((char *) page + upper);
+
+ /*
+ * Tuple is now allocated on the page. Next, fill in the tuple
+ * header. This block of code violates the tuple abstraction.
+ */
+
+ ntup->t_len = tupsize;
+ ItemPointerSet(&(ntup->t_ctid), BufferGetBlockNumber(buffer), off);
+ ItemPointerSetInvalid(&(ntup->t_chain));
+ LastOidProcessed = ntup->t_oid = newoid();
+ TransactionIdStore(GetCurrentTransactionId(), &(ntup->t_xmin));
+ ntup->t_cmin = GetCurrentCommandId();
+ StoreInvalidTransactionId(&(ntup->t_xmax));
+ ntup->t_cmax = 0;
+ ntup->t_tmin = INVALID_ABSTIME;
+ ntup->t_tmax = CURRENT_ABSTIME;
+ ntup->t_natts = 2;
+ ntup->t_hoff = hoff;
+ ntup->t_vtype = 0;
+ ntup->t_infomask = 0x0;
+
+ /* if a NULL is passed in, avoid the calculations below */
+ if (dbuf == NULL)
+ return ntup;
+
+ /*
+ * Finally, copy the user's data buffer into the tuple. This violates
+ * the tuple and class abstractions.
+ */
+
+ attptr = ((char *) ntup) + hoff;
+ *((int32 *) attptr) = obj_desc->offset + nwrite - 1;
+ attptr += sizeof(int32);
+
+ /*
+ * * mer fixed disk layout of varlenas to get rid of the need for
+ * this. *
+ *
+ * *((int32 *) attptr) = nwrite + sizeof(int32); * attptr +=
+ * sizeof(int32);
+ */
+
+ *((int32 *) attptr) = nwrite + sizeof(int32);
+ attptr += sizeof(int32);
+
+ /*
+ * If a data buffer was passed in, then copy the data from the buffer
+ * to the tuple. Some callers (eg, inv_wrold()) may not pass in a
+ * buffer, since they have to copy part of the old tuple data and part
+ * of the user's new data into the new tuple.
+ */
+
+ if (dbuf != (char *) NULL)
+ memmove(attptr, dbuf, nwrite);
+
+ /* keep track of boundary of current tuple */
+ obj_desc->lowbyte = obj_desc->offset;
+ obj_desc->highbyte = obj_desc->offset + nwrite - 1;
+
+ /* new tuple is filled -- return it */
+ return (ntup);
}
static void
-inv_indextup(LargeObjectDesc *obj_desc, HeapTuple htup)
+inv_indextup(LargeObjectDesc * obj_desc, HeapTuple htup)
{
- InsertIndexResult res;
- Datum v[1];
- char n[1];
+ InsertIndexResult res;
+ Datum v[1];
+ char n[1];
- n[0] = ' ';
- v[0] = Int32GetDatum(obj_desc->highbyte);
- res = index_insert(obj_desc->index_r, &v[0], &n[0],
- &(htup->t_ctid), obj_desc->heap_r);
+ n[0] = ' ';
+ v[0] = Int32GetDatum(obj_desc->highbyte);
+ res = index_insert(obj_desc->index_r, &v[0], &n[0],
+ &(htup->t_ctid), obj_desc->heap_r);
- if (res)
- pfree(res);
+ if (res)
+ pfree(res);
}
/*
static void
DumpPage(Page page, int blkno)
{
- ItemId lp;
- HeapTuple tup;
- int flags, i, nline;
- ItemPointerData pointerData;
+ ItemId lp;
+ HeapTuple tup;
+ int flags, i, nline;
+ ItemPointerData pointerData;
+
+ printf("\t[subblock=%d]:lower=%d:upper=%d:special=%d\n", 0,
+ ((PageHeader)page)->pd_lower, ((PageHeader)page)->pd_upper,
+ ((PageHeader)page)->pd_special);
- printf("\t[subblock=%d]:lower=%d:upper=%d:special=%d\n", 0,
- ((PageHeader)page)->pd_lower, ((PageHeader)page)->pd_upper,
- ((PageHeader)page)->pd_special);
+ printf("\t:MaxOffsetNumber=%d\n",
+ (int16) PageGetMaxOffsetNumber(page));
- printf("\t:MaxOffsetNumber=%d\n",
- (int16) PageGetMaxOffsetNumber(page));
-
- nline = (int16) PageGetMaxOffsetNumber(page);
+ nline = (int16) PageGetMaxOffsetNumber(page);
{
- int i;
- char *cp;
+ int i;
+ char *cp;
- i = PageGetSpecialSize(page);
- cp = PageGetSpecialPointer(page);
+ i = PageGetSpecialSize(page);
+ cp = PageGetSpecialPointer(page);
- printf("\t:SpecialData=");
+ printf("\t:SpecialData=");
- while (i > 0) {
- printf(" 0x%02x", *cp);
- cp += 1;
- i -= 1;
- }
- printf("\n");
+ while (i > 0) {
+ printf(" 0x%02x", *cp);
+ cp += 1;
+ i -= 1;
+ }
+ printf("\n");
}
- for (i = 0; i < nline; i++) {
- lp = ((PageHeader)page)->pd_linp + i;
- flags = (*lp).lp_flags;
- ItemPointerSet(&pointerData, blkno, 1 + i);
- printf("%s:off=%d:flags=0x%x:len=%d",
- ItemPointerFormExternal(&pointerData), (*lp).lp_off,
- flags, (*lp).lp_len);
+ for (i = 0; i < nline; i++) {
+ lp = ((PageHeader)page)->pd_linp + i;
+ flags = (*lp).lp_flags;
+ ItemPointerSet(&pointerData, blkno, 1 + i);
+ printf("%s:off=%d:flags=0x%x:len=%d",
+ ItemPointerFormExternal(&pointerData), (*lp).lp_off,
+ flags, (*lp).lp_len);
- if (flags & LP_USED) {
- HeapTupleData htdata;
+ if (flags & LP_USED) {
+ HeapTupleData htdata;
- printf(":USED");
+ printf(":USED");
- memmove((char *) &htdata,
- (char *) &((char *)page)[(*lp).lp_off],
- sizeof(htdata));
+ memmove((char *) &htdata,
+ (char *) &((char *)page)[(*lp).lp_off],
+ sizeof(htdata));
- tup = &htdata;
+ tup = &htdata;
- printf("\n\t:ctid=%s:oid=%d",
- ItemPointerFormExternal(&tup->t_ctid),
- tup->t_oid);
- printf(":natts=%d:thoff=%d:vtype=`%c' (0x%02x):",
- tup->t_natts,
- tup->t_hoff, tup->t_vtype, tup->t_vtype);
+ printf("\n\t:ctid=%s:oid=%d",
+ ItemPointerFormExternal(&tup->t_ctid),
+ tup->t_oid);
+ printf(":natts=%d:thoff=%d:vtype=`%c' (0x%02x):",
+ tup->t_natts,
+ tup->t_hoff, tup->t_vtype, tup->t_vtype);
- printf("\n\t:tmin=%d:cmin=%u:",
- tup->t_tmin, tup->t_cmin);
+ printf("\n\t:tmin=%d:cmin=%u:",
+ tup->t_tmin, tup->t_cmin);
- printf("xmin=%u:", tup->t_xmin);
+ printf("xmin=%u:", tup->t_xmin);
- printf("\n\t:tmax=%d:cmax=%u:",
- tup->t_tmax, tup->t_cmax);
+ printf("\n\t:tmax=%d:cmax=%u:",
+ tup->t_tmax, tup->t_cmax);
- printf("xmax=%u:", tup->t_xmax);
+ printf("xmax=%u:", tup->t_xmax);
- printf("\n\t:chain=%s:\n",
- ItemPointerFormExternal(&tup->t_chain));
- } else
- putchar('\n');
- }
+ printf("\n\t:chain=%s:\n",
+ ItemPointerFormExternal(&tup->t_chain));
+ } else
+ putchar('\n');
+ }
}
static char*
ItemPointerFormExternal(ItemPointer pointer)
{
- static char itemPointerString[32];
-
- if (!ItemPointerIsValid(pointer)) {
- memmove(itemPointerString, "<-,-,->", sizeof "<-,-,->");
- } else {
- sprintf(itemPointerString, "<%u,%u>",
- ItemPointerGetBlockNumber(pointer),
- ItemPointerGetOffsetNumber(pointer));
- }
+ static char itemPointerString[32];
+
+ if (!ItemPointerIsValid(pointer)) {
+ memmove(itemPointerString, "<-,-,->", sizeof "<-,-,->");
+ } else {
+ sprintf(itemPointerString, "<%u,%u>",
+ ItemPointerGetBlockNumber(pointer),
+ ItemPointerGetOffsetNumber(pointer));
+ }
- return (itemPointerString);
+ return (itemPointerString);
}
*/
static int
_inv_getsize(Relation hreln, TupleDesc hdesc, Relation ireln)
{
- IndexScanDesc iscan;
- RetrieveIndexResult res;
- Buffer buf;
- HeapTuple htup;
- Datum d;
- long size;
- bool isNull;
+ IndexScanDesc iscan;
+ RetrieveIndexResult res;
+ Buffer buf;
+ HeapTuple htup;
+ Datum d;
+ long size;
+ bool isNull;
- /* scan backwards from end */
- iscan = index_beginscan(ireln, (bool) 1, 0, (ScanKey) NULL);
+ /* scan backwards from end */
+ iscan = index_beginscan(ireln, (bool) 1, 0, (ScanKey) NULL);
- buf = InvalidBuffer;
+ buf = InvalidBuffer;
- do {
- res = index_getnext(iscan, BackwardScanDirection);
+ do
+ {
+ res = index_getnext(iscan, BackwardScanDirection);
- /*
- * If there are no more index tuples, then the relation is empty,
- * so the file's size is zero.
- */
+ /*
+ * If there are no more index tuples, then the relation is empty,
+ * so the file's size is zero.
+ */
- if (res == (RetrieveIndexResult) NULL) {
- index_endscan(iscan);
- return (0);
- }
+ if (res == (RetrieveIndexResult) NULL)
+ {
+ index_endscan(iscan);
+ return (0);
+ }
- /*
- * For time travel, we need to use the actual time qual here,
- * rather that NowTimeQual. We currently have no way to pass
- * a time qual in.
- */
+ /*
+ * For time travel, we need to use the actual time qual here,
+ * rather that NowTimeQual. We currently have no way to pass a
+ * time qual in.
+ */
- if (buf != InvalidBuffer)
- ReleaseBuffer(buf);
+ if (buf != InvalidBuffer)
+ ReleaseBuffer(buf);
- htup = heap_fetch(hreln, NowTimeQual, &(res->heap_iptr), &buf);
+ htup = heap_fetch(hreln, NowTimeQual, &(res->heap_iptr), &buf);
- } while (!HeapTupleIsValid(htup));
+ } while (!HeapTupleIsValid(htup));
- /* don't need the index scan anymore */
- index_endscan(iscan);
+ /* don't need the index scan anymore */
+ index_endscan(iscan);
- /* get olastbyte attribute */
- d = (Datum) heap_getattr(htup, buf, 1, hdesc, &isNull);
- size = DatumGetInt32(d) + 1;
+ /* get olastbyte attribute */
+ d = (Datum) heap_getattr(htup, buf, 1, hdesc, &isNull);
+ size = DatumGetInt32(d) + 1;
- /* wei hates it if you forget to do this */
- ReleaseBuffer(buf);
+ /* wei hates it if you forget to do this */
+ ReleaseBuffer(buf);
- return (size);
+ return (size);
}
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 0f34f500596..555303fa14e 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -1,22 +1,22 @@
/*-------------------------------------------------------------------------
*
* lmgr.c--
- * POSTGRES lock manager code
+ * POSTGRES lock manager code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.5 1997/08/19 21:33:15 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.6 1997/09/07 04:48:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-/* #define LOCKDEBUGALL 1 */
+/* #define LOCKDEBUGALL 1 */
/* #define LOCKDEBUG 1 */
#ifdef LOCKDEBUGALL
-#define LOCKDEBUG 1
-#endif /* LOCKDEBUGALL */
+#define LOCKDEBUG 1
+#endif /* LOCKDEBUGALL */
#include <string.h>
@@ -46,239 +46,246 @@
#include "nodes/memnodes.h"
#include "storage/bufmgr.h"
-#include "access/transam.h" /* for AmiTransactionId */
+#include "access/transam.h" /* for AmiTransactionId */
-static void LRelIdAssign(LRelId *lRelId, Oid dbId, Oid relId);
+static void LRelIdAssign(LRelId * lRelId, Oid dbId, Oid relId);
/* ----------------
- *
+ *
* ----------------
*/
-#define MaxRetries 4 /* XXX about 1/4 minute--a hack */
+#define MaxRetries 4 /* XXX about 1/4 minute--a hack */
#define IntentReadRelationLock 0x0100
-#define ReadRelationLock 0x0200
-#define IntentWriteRelationLock 0x0400
-#define WriteRelationLock 0x0800
-#define IntentReadPageLock 0x1000
-#define ReadTupleLock 0x2000
+#define ReadRelationLock 0x0200
+#define IntentWriteRelationLock 0x0400
+#define WriteRelationLock 0x0800
+#define IntentReadPageLock 0x1000
+#define ReadTupleLock 0x2000
-#define TupleLevelLockCountMask 0x000f
+#define TupleLevelLockCountMask 0x000f
-#define TupleLevelLockLimit 10
+#define TupleLevelLockLimit 10
-extern Oid MyDatabaseId;
+extern Oid MyDatabaseId;
static LRelId VariableRelationLRelId = {
- RelOid_pg_variable,
- InvalidOid
+ RelOid_pg_variable,
+ InvalidOid
};
/* ----------------
- * RelationGetLRelId
+ * RelationGetLRelId
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_10 \
elog(NOTICE, "RelationGetLRelId(%s) invalid lockInfo", \
- RelationGetRelationName(relation));
+ RelationGetRelationName(relation));
#else
#define LOCKDEBUG_10
-#endif /* LOCKDEBUG */
-
+#endif /* LOCKDEBUG */
+
/*
* RelationGetLRelId --
- * Returns "lock" relation identifier for a relation.
+ * Returns "lock" relation identifier for a relation.
*/
LRelId
RelationGetLRelId(Relation relation)
{
- LockInfo linfo;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- linfo = (LockInfo) relation->lockInfo;
-
- /* ----------------
- * initialize lock info if necessary
- * ----------------
- */
- if (! LockInfoIsValid(linfo)) {
- LOCKDEBUG_10;
- RelationInitLockInfo(relation);
+ LockInfo linfo;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
linfo = (LockInfo) relation->lockInfo;
- }
-
- /* ----------------
- * XXX hack to prevent problems during
- * VARIABLE relation initialization
- * ----------------
- */
- if (strcmp(RelationGetRelationName(relation)->data,
- VariableRelationName) == 0) {
- return (VariableRelationLRelId);
- }
-
- return (linfo->lRelId);
+
+ /* ----------------
+ * initialize lock info if necessary
+ * ----------------
+ */
+ if (!LockInfoIsValid(linfo))
+ {
+ LOCKDEBUG_10;
+ RelationInitLockInfo(relation);
+ linfo = (LockInfo) relation->lockInfo;
+ }
+
+ /* ----------------
+ * XXX hack to prevent problems during
+ * VARIABLE relation initialization
+ * ----------------
+ */
+ if (strcmp(RelationGetRelationName(relation)->data,
+ VariableRelationName) == 0)
+ {
+ return (VariableRelationLRelId);
+ }
+
+ return (linfo->lRelId);
}
/*
* LRelIdGetDatabaseId --
- * Returns database identifier for a "lock" relation identifier.
+ * Returns database identifier for a "lock" relation identifier.
*/
/* ----------------
- * LRelIdGetDatabaseId
+ * LRelIdGetDatabaseId
*
* Note: The argument may not be correct, if it is not used soon
- * after it is created.
+ * after it is created.
* ----------------
*/
#ifdef NOT_USED
Oid
LRelIdGetDatabaseId(LRelId lRelId)
{
- return (lRelId.dbId);
+ return (lRelId.dbId);
}
+
#endif
/*
* LRelIdGetRelationId --
- * Returns relation identifier for a "lock" relation identifier.
+ * Returns relation identifier for a "lock" relation identifier.
*/
-Oid
+Oid
LRelIdGetRelationId(LRelId lRelId)
{
- return (lRelId.relId);
+ return (lRelId.relId);
}
/*
* DatabaseIdIsMyDatabaseId --
- * True iff database object identifier is valid in my present database.
+ * True iff database object identifier is valid in my present database.
*/
#ifdef NOT_USED
bool
DatabaseIdIsMyDatabaseId(Oid databaseId)
{
- return (bool)
- (!OidIsValid(databaseId) || databaseId == MyDatabaseId);
+ return (bool)
+ (!OidIsValid(databaseId) || databaseId == MyDatabaseId);
}
+
#endif
/*
* LRelIdContainsMyDatabaseId --
- * True iff "lock" relation identifier is valid in my present database.
+ * True iff "lock" relation identifier is valid in my present database.
*/
#ifdef NOT_USED
bool
LRelIdContainsMyDatabaseId(LRelId lRelId)
{
- return (bool)
- (!OidIsValid(lRelId.dbId) || lRelId.dbId == MyDatabaseId);
+ return (bool)
+ (!OidIsValid(lRelId.dbId) || lRelId.dbId == MyDatabaseId);
}
+
#endif
/*
* RelationInitLockInfo --
- * Initializes the lock information in a relation descriptor.
+ * Initializes the lock information in a relation descriptor.
*/
/* ----------------
- * RelationInitLockInfo
+ * RelationInitLockInfo
*
- * XXX processingVariable is a hack to prevent problems during
- * VARIABLE relation initialization.
+ * XXX processingVariable is a hack to prevent problems during
+ * VARIABLE relation initialization.
* ----------------
*/
void
RelationInitLockInfo(Relation relation)
{
- LockInfo info;
- char *relname;
- Oid relationid;
- bool processingVariable;
- extern Oid MyDatabaseId; /* XXX use include */
- extern GlobalMemory CacheCxt;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- Assert(OidIsValid(RelationGetRelationId(relation)));
-
- /* ----------------
- * get information from relation descriptor
- * ----------------
- */
- info = (LockInfo) relation->lockInfo;
- relname = (char *) RelationGetRelationName(relation);
- relationid = RelationGetRelationId(relation);
- processingVariable = (strcmp(relname, VariableRelationName) == 0);
-
- /* ----------------
- * create a new lockinfo if not already done
- * ----------------
- */
- if (! PointerIsValid(info))
+ LockInfo info;
+ char *relname;
+ Oid relationid;
+ bool processingVariable;
+ extern Oid MyDatabaseId; /* XXX use include */
+ extern GlobalMemory CacheCxt;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ Assert(OidIsValid(RelationGetRelationId(relation)));
+
+ /* ----------------
+ * get information from relation descriptor
+ * ----------------
+ */
+ info = (LockInfo) relation->lockInfo;
+ relname = (char *) RelationGetRelationName(relation);
+ relationid = RelationGetRelationId(relation);
+ processingVariable = (strcmp(relname, VariableRelationName) == 0);
+
+ /* ----------------
+ * create a new lockinfo if not already done
+ * ----------------
+ */
+ if (!PointerIsValid(info))
{
- MemoryContext oldcxt;
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
- info = (LockInfo)palloc(sizeof(LockInfoData));
- MemoryContextSwitchTo(oldcxt);
+ MemoryContext oldcxt;
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ info = (LockInfo) palloc(sizeof(LockInfoData));
+ MemoryContextSwitchTo(oldcxt);
}
- else if (processingVariable) {
- if (IsTransactionState()) {
- TransactionIdStore(GetCurrentTransactionId(),
- &info->transactionIdData);
+ else if (processingVariable)
+ {
+ if (IsTransactionState())
+ {
+ TransactionIdStore(GetCurrentTransactionId(),
+ &info->transactionIdData);
+ }
+ info->flags = 0x0;
+ return; /* prevent an infinite loop--still true? */
}
- info->flags = 0x0;
- return; /* prevent an infinite loop--still true? */
- }
- else if (info->initialized)
+ else if (info->initialized)
{
- /* ------------
- * If we've already initialized we're done.
- * ------------
- */
- return;
+ /* ------------
+ * If we've already initialized we're done.
+ * ------------
+ */
+ return;
}
-
- /* ----------------
- * initialize lockinfo.dbId and .relId appropriately
- * ----------------
- */
- if (IsSharedSystemRelationName(relname))
- LRelIdAssign(&info->lRelId, InvalidOid, relationid);
- else
- LRelIdAssign(&info->lRelId, MyDatabaseId, relationid);
-
- /* ----------------
- * store the transaction id in the lockInfo field
- * ----------------
- */
- if (processingVariable)
- TransactionIdStore(AmiTransactionId,
- &info->transactionIdData);
- else if (IsTransactionState())
- TransactionIdStore(GetCurrentTransactionId(),
- &info->transactionIdData);
- else
- StoreInvalidTransactionId(&(info->transactionIdData));
-
- /* ----------------
- * initialize rest of lockinfo
- * ----------------
- */
- info->flags = 0x0;
- info->initialized = (bool)true;
- relation->lockInfo = (Pointer) info;
+
+ /* ----------------
+ * initialize lockinfo.dbId and .relId appropriately
+ * ----------------
+ */
+ if (IsSharedSystemRelationName(relname))
+ LRelIdAssign(&info->lRelId, InvalidOid, relationid);
+ else
+ LRelIdAssign(&info->lRelId, MyDatabaseId, relationid);
+
+ /* ----------------
+ * store the transaction id in the lockInfo field
+ * ----------------
+ */
+ if (processingVariable)
+ TransactionIdStore(AmiTransactionId,
+ &info->transactionIdData);
+ else if (IsTransactionState())
+ TransactionIdStore(GetCurrentTransactionId(),
+ &info->transactionIdData);
+ else
+ StoreInvalidTransactionId(&(info->transactionIdData));
+
+ /* ----------------
+ * initialize rest of lockinfo
+ * ----------------
+ */
+ info->flags = 0x0;
+ info->initialized = (bool) true;
+ relation->lockInfo = (Pointer) info;
}
/* ----------------
- * RelationDiscardLockInfo
+ * RelationDiscardLockInfo
* ----------------
*/
#ifdef LOCKDEBUG
@@ -286,456 +293,464 @@ RelationInitLockInfo(Relation relation)
elog(DEBUG, "DiscardLockInfo: NULL relation->lockInfo")
#else
#define LOCKDEBUG_20
-#endif /* LOCKDEBUG */
-
+#endif /* LOCKDEBUG */
+
/*
* RelationDiscardLockInfo --
- * Discards the lock information in a relation descriptor.
+ * Discards the lock information in a relation descriptor.
*/
#ifdef NOT_USED
void
RelationDiscardLockInfo(Relation relation)
{
- if (! LockInfoIsValid(relation->lockInfo)) {
- LOCKDEBUG_20;
- return;
- }
-
- pfree(relation->lockInfo);
- relation->lockInfo = NULL;
+ if (!LockInfoIsValid(relation->lockInfo))
+ {
+ LOCKDEBUG_20;
+ return;
+ }
+
+ pfree(relation->lockInfo);
+ relation->lockInfo = NULL;
}
+
#endif
/*
* RelationSetLockForDescriptorOpen --
- * Sets read locks for a relation descriptor.
+ * Sets read locks for a relation descriptor.
*/
#ifdef LOCKDEBUGALL
#define LOCKDEBUGALL_30 \
elog(DEBUG, "RelationSetLockForDescriptorOpen(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
#else
#define LOCKDEBUGALL_30
-#endif /* LOCKDEBUGALL*/
-
+#endif /* LOCKDEBUGALL */
+
void
RelationSetLockForDescriptorOpen(Relation relation)
{
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- LOCKDEBUGALL_30;
-
- /* ----------------
- * read lock catalog tuples which compose the relation descriptor
- * XXX race condition? XXX For now, do nothing.
- * ----------------
- */
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ LOCKDEBUGALL_30;
+
+ /* ----------------
+ * read lock catalog tuples which compose the relation descriptor
+ * XXX race condition? XXX For now, do nothing.
+ * ----------------
+ */
}
/* ----------------
- * RelationSetLockForRead
+ * RelationSetLockForRead
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_40 \
elog(DEBUG, "RelationSetLockForRead(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
#else
#define LOCKDEBUG_40
-#endif /* LOCKDEBUG*/
-
+#endif /* LOCKDEBUG */
+
/*
* RelationSetLockForRead --
- * Sets relation level read lock.
+ * Sets relation level read lock.
*/
void
RelationSetLockForRead(Relation relation)
{
- LockInfo linfo;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- LOCKDEBUG_40;
-
- /* ----------------
- * If we don't have lock info on the reln just go ahead and
- * lock it without trying to short circuit the lock manager.
- * ----------------
- */
- if (!LockInfoIsValid(relation->lockInfo))
+ LockInfo linfo;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ LOCKDEBUG_40;
+
+ /* ----------------
+ * If we don't have lock info on the reln just go ahead and
+ * lock it without trying to short circuit the lock manager.
+ * ----------------
+ */
+ if (!LockInfoIsValid(relation->lockInfo))
{
- RelationInitLockInfo(relation);
- linfo = (LockInfo) relation->lockInfo;
- linfo->flags |= ReadRelationLock;
- MultiLockReln(linfo, READ_LOCK);
- return;
+ RelationInitLockInfo(relation);
+ linfo = (LockInfo) relation->lockInfo;
+ linfo->flags |= ReadRelationLock;
+ MultiLockReln(linfo, READ_LOCK);
+ return;
}
- else
- linfo = (LockInfo) relation->lockInfo;
-
- MultiLockReln(linfo, READ_LOCK);
+ else
+ linfo = (LockInfo) relation->lockInfo;
+
+ MultiLockReln(linfo, READ_LOCK);
}
/* ----------------
- * RelationUnsetLockForRead
+ * RelationUnsetLockForRead
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_50 \
elog(DEBUG, "RelationUnsetLockForRead(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
#else
#define LOCKDEBUG_50
-#endif /* LOCKDEBUG*/
-
+#endif /* LOCKDEBUG */
+
/*
* RelationUnsetLockForRead --
- * Unsets relation level read lock.
+ * Unsets relation level read lock.
*/
void
RelationUnsetLockForRead(Relation relation)
{
- LockInfo linfo;
-
- /* ----------------
- * sanity check
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- linfo = (LockInfo) relation->lockInfo;
-
- /* ----------------
- * If we don't have lock info on the reln just go ahead and
- * release it.
- * ----------------
- */
- if (!LockInfoIsValid(linfo))
+ LockInfo linfo;
+
+ /* ----------------
+ * sanity check
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ linfo = (LockInfo) relation->lockInfo;
+
+ /* ----------------
+ * If we don't have lock info on the reln just go ahead and
+ * release it.
+ * ----------------
+ */
+ if (!LockInfoIsValid(linfo))
{
- elog(WARN,
- "Releasing a lock on %s with invalid lock information",
- RelationGetRelationName(relation));
+ elog(WARN,
+ "Releasing a lock on %s with invalid lock information",
+ RelationGetRelationName(relation));
}
-
- MultiReleaseReln(linfo, READ_LOCK);
+
+ MultiReleaseReln(linfo, READ_LOCK);
}
/* ----------------
- * RelationSetLockForWrite(relation)
+ * RelationSetLockForWrite(relation)
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_60 \
elog(DEBUG, "RelationSetLockForWrite(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId)
#else
#define LOCKDEBUG_60
-#endif /* LOCKDEBUG*/
-
+#endif /* LOCKDEBUG */
+
/*
* RelationSetLockForWrite --
- * Sets relation level write lock.
+ * Sets relation level write lock.
*/
void
RelationSetLockForWrite(Relation relation)
{
- LockInfo linfo;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- LOCKDEBUG_60;
-
- /* ----------------
- * If we don't have lock info on the reln just go ahead and
- * lock it without trying to short circuit the lock manager.
- * ----------------
- */
- if (!LockInfoIsValid(relation->lockInfo))
+ LockInfo linfo;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ LOCKDEBUG_60;
+
+ /* ----------------
+ * If we don't have lock info on the reln just go ahead and
+ * lock it without trying to short circuit the lock manager.
+ * ----------------
+ */
+ if (!LockInfoIsValid(relation->lockInfo))
{
- RelationInitLockInfo(relation);
- linfo = (LockInfo) relation->lockInfo;
- linfo->flags |= WriteRelationLock;
- MultiLockReln(linfo, WRITE_LOCK);
- return;
+ RelationInitLockInfo(relation);
+ linfo = (LockInfo) relation->lockInfo;
+ linfo->flags |= WriteRelationLock;
+ MultiLockReln(linfo, WRITE_LOCK);
+ return;
}
- else
- linfo = (LockInfo) relation->lockInfo;
-
- MultiLockReln(linfo, WRITE_LOCK);
+ else
+ linfo = (LockInfo) relation->lockInfo;
+
+ MultiLockReln(linfo, WRITE_LOCK);
}
/* ----------------
- * RelationUnsetLockForWrite
+ * RelationUnsetLockForWrite
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_70 \
elog(DEBUG, "RelationUnsetLockForWrite(%s[%d,%d]) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId);
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId);
#else
#define LOCKDEBUG_70
-#endif /* LOCKDEBUG */
-
+#endif /* LOCKDEBUG */
+
/*
* RelationUnsetLockForWrite --
- * Unsets relation level write lock.
+ * Unsets relation level write lock.
*/
void
RelationUnsetLockForWrite(Relation relation)
{
- LockInfo linfo;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled()) {
- return;
- }
-
- linfo = (LockInfo) relation->lockInfo;
-
- if (!LockInfoIsValid(linfo))
+ LockInfo linfo;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ {
+ return;
+ }
+
+ linfo = (LockInfo) relation->lockInfo;
+
+ if (!LockInfoIsValid(linfo))
{
- elog(WARN,
- "Releasing a lock on %s with invalid lock information",
- RelationGetRelationName(relation));
+ elog(WARN,
+ "Releasing a lock on %s with invalid lock information",
+ RelationGetRelationName(relation));
}
-
- MultiReleaseReln(linfo, WRITE_LOCK);
+
+ MultiReleaseReln(linfo, WRITE_LOCK);
}
/* ----------------
- * RelationSetLockForTupleRead
+ * RelationSetLockForTupleRead
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_80 \
elog(DEBUG, "RelationSetLockForTupleRead(%s[%d,%d], 0x%x) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, \
- itemPointer)
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, \
+ itemPointer)
#define LOCKDEBUG_81 \
- elog(DEBUG, "RelationSetLockForTupleRead() escalating");
+ elog(DEBUG, "RelationSetLockForTupleRead() escalating");
#else
#define LOCKDEBUG_80
#define LOCKDEBUG_81
-#endif /* LOCKDEBUG */
-
+#endif /* LOCKDEBUG */
+
/*
* RelationSetLockForTupleRead --
- * Sets tuple level read lock.
+ * Sets tuple level read lock.
*/
#ifdef NOT_USED
void
RelationSetLockForTupleRead(Relation relation, ItemPointer itemPointer)
{
- LockInfo linfo;
- TransactionId curXact;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- LOCKDEBUG_80;
-
- /* ---------------------
- * If our lock info is invalid don't bother trying to short circuit
- * the lock manager.
- * ---------------------
- */
- if (!LockInfoIsValid(relation->lockInfo))
+ LockInfo linfo;
+ TransactionId curXact;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ LOCKDEBUG_80;
+
+ /* ---------------------
+ * If our lock info is invalid don't bother trying to short circuit
+ * the lock manager.
+ * ---------------------
+ */
+ if (!LockInfoIsValid(relation->lockInfo))
{
- RelationInitLockInfo(relation);
- linfo = (LockInfo) relation->lockInfo;
- linfo->flags |=
- IntentReadRelationLock |
- IntentReadPageLock |
+ RelationInitLockInfo(relation);
+ linfo = (LockInfo) relation->lockInfo;
+ linfo->flags |=
+ IntentReadRelationLock |
+ IntentReadPageLock |
ReadTupleLock;
- MultiLockTuple(linfo, itemPointer, READ_LOCK);
- return;
+ MultiLockTuple(linfo, itemPointer, READ_LOCK);
+ return;
}
- else
- linfo = (LockInfo) relation->lockInfo;
-
- /* ----------------
- * no need to set a lower granularity lock
- * ----------------
- */
- curXact = GetCurrentTransactionId();
- if ((linfo->flags & ReadRelationLock) &&
- TransactionIdEquals(curXact, linfo->transactionIdData))
+ else
+ linfo = (LockInfo) relation->lockInfo;
+
+ /* ----------------
+ * no need to set a lower granularity lock
+ * ----------------
+ */
+ curXact = GetCurrentTransactionId();
+ if ((linfo->flags & ReadRelationLock) &&
+ TransactionIdEquals(curXact, linfo->transactionIdData))
{
- return;
+ return;
}
-
- /* ----------------
- * If we don't already have a tuple lock this transaction
- * ----------------
- */
- if (!( (linfo->flags & ReadTupleLock) &&
- TransactionIdEquals(curXact, linfo->transactionIdData) )) {
-
- linfo->flags |=
- IntentReadRelationLock |
- IntentReadPageLock |
- ReadTupleLock;
-
- /* clear count */
- linfo->flags &= ~TupleLevelLockCountMask;
-
- } else {
- if (TupleLevelLockLimit == (TupleLevelLockCountMask &
- linfo->flags)) {
- LOCKDEBUG_81;
-
- /* escalate */
- MultiLockReln(linfo, READ_LOCK);
-
- /* clear count */
- linfo->flags &= ~TupleLevelLockCountMask;
- return;
+
+ /* ----------------
+ * If we don't already have a tuple lock this transaction
+ * ----------------
+ */
+ if (!((linfo->flags & ReadTupleLock) &&
+ TransactionIdEquals(curXact, linfo->transactionIdData)))
+ {
+
+ linfo->flags |=
+ IntentReadRelationLock |
+ IntentReadPageLock |
+ ReadTupleLock;
+
+ /* clear count */
+ linfo->flags &= ~TupleLevelLockCountMask;
+
+ }
+ else
+ {
+ if (TupleLevelLockLimit == (TupleLevelLockCountMask &
+ linfo->flags))
+ {
+ LOCKDEBUG_81;
+
+ /* escalate */
+ MultiLockReln(linfo, READ_LOCK);
+
+ /* clear count */
+ linfo->flags &= ~TupleLevelLockCountMask;
+ return;
+ }
+
+ /* increment count */
+ linfo->flags =
+ (linfo->flags & ~TupleLevelLockCountMask) |
+ (1 + (TupleLevelLockCountMask & linfo->flags));
}
-
- /* increment count */
- linfo->flags =
- (linfo->flags & ~TupleLevelLockCountMask) |
- (1 + (TupleLevelLockCountMask & linfo->flags));
- }
-
- TransactionIdStore(curXact, &linfo->transactionIdData);
-
- /* ----------------
- * Lock the tuple.
- * ----------------
- */
- MultiLockTuple(linfo, itemPointer, READ_LOCK);
+
+ TransactionIdStore(curXact, &linfo->transactionIdData);
+
+ /* ----------------
+ * Lock the tuple.
+ * ----------------
+ */
+ MultiLockTuple(linfo, itemPointer, READ_LOCK);
}
+
#endif
/* ----------------
- * RelationSetLockForReadPage
+ * RelationSetLockForReadPage
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_90 \
elog(DEBUG, "RelationSetLockForReadPage(%s[%d,%d], @%d) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page);
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page);
#else
#define LOCKDEBUG_90
-#endif /* LOCKDEBUG*/
-
+#endif /* LOCKDEBUG */
+
/* ----------------
- * RelationSetLockForWritePage
+ * RelationSetLockForWritePage
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_100 \
elog(DEBUG, "RelationSetLockForWritePage(%s[%d,%d], @%d) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page);
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page);
#else
#define LOCKDEBUG_100
-#endif /* LOCKDEBUG */
-
+#endif /* LOCKDEBUG */
+
/*
* RelationSetLockForWritePage --
- * Sets write lock on a page.
+ * Sets write lock on a page.
*/
-void
+void
RelationSetLockForWritePage(Relation relation,
- ItemPointer itemPointer)
+ ItemPointer itemPointer)
{
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- /* ---------------
- * Make sure linfo is initialized
- * ---------------
- */
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- /* ----------------
- * attempt to set lock
- * ----------------
- */
- MultiLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK);
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ /* ---------------
+ * Make sure linfo is initialized
+ * ---------------
+ */
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ /* ----------------
+ * attempt to set lock
+ * ----------------
+ */
+ MultiLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK);
}
/* ----------------
- * RelationUnsetLockForReadPage
+ * RelationUnsetLockForReadPage
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_110 \
elog(DEBUG, "RelationUnsetLockForReadPage(%s[%d,%d], @%d) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page)
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page)
#else
#define LOCKDEBUG_110
-#endif /* LOCKDEBUG */
-
+#endif /* LOCKDEBUG */
+
/* ----------------
- * RelationUnsetLockForWritePage
+ * RelationUnsetLockForWritePage
* ----------------
*/
#ifdef LOCKDEBUG
#define LOCKDEBUG_120 \
elog(DEBUG, "RelationUnsetLockForWritePage(%s[%d,%d], @%d) called", \
- RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page)
+ RelationGetRelationName(relation), lRelId.dbId, lRelId.relId, page)
#else
#define LOCKDEBUG_120
-#endif /* LOCKDEBUG */
-
+#endif /* LOCKDEBUG */
+
/*
- * Set a single level write page lock. Assumes that you already
+ * Set a single level write page lock. Assumes that you already
* have a write intent lock on the relation.
*/
void
RelationSetSingleWLockPage(Relation relation,
- ItemPointer itemPointer)
+ ItemPointer itemPointer)
{
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- SingleLockPage((LockInfo)relation->lockInfo, itemPointer, WRITE_LOCK, !UNLOCK);
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, !UNLOCK);
}
/*
@@ -743,23 +758,23 @@ RelationSetSingleWLockPage(Relation relation,
*/
void
RelationUnsetSingleWLockPage(Relation relation,
- ItemPointer itemPointer)
+ ItemPointer itemPointer)
{
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- elog(WARN,
- "Releasing a lock on %s with invalid lock information",
- RelationGetRelationName(relation));
-
- SingleLockPage((LockInfo)relation->lockInfo, itemPointer, WRITE_LOCK, UNLOCK);
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ elog(WARN,
+ "Releasing a lock on %s with invalid lock information",
+ RelationGetRelationName(relation));
+
+ SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, UNLOCK);
}
/*
@@ -768,45 +783,45 @@ RelationUnsetSingleWLockPage(Relation relation,
*/
void
RelationSetSingleRLockPage(Relation relation,
- ItemPointer itemPointer)
+ ItemPointer itemPointer)
{
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- SingleLockPage((LockInfo)relation->lockInfo, itemPointer, READ_LOCK, !UNLOCK);
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, !UNLOCK);
}
-/*
+/*
* Unset a single level read page lock.
*/
void
RelationUnsetSingleRLockPage(Relation relation,
- ItemPointer itemPointer)
+ ItemPointer itemPointer)
{
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- elog(WARN,
- "Releasing a lock on %s with invalid lock information",
- RelationGetRelationName(relation));
-
- SingleLockPage((LockInfo)relation->lockInfo, itemPointer, READ_LOCK, UNLOCK);
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ elog(WARN,
+ "Releasing a lock on %s with invalid lock information",
+ RelationGetRelationName(relation));
+
+ SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, UNLOCK);
}
/*
@@ -821,18 +836,18 @@ RelationUnsetSingleRLockPage(Relation relation,
void
RelationSetRIntentLock(Relation relation)
{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- SingleLockReln((LockInfo)relation->lockInfo, READ_LOCK+INTENT, !UNLOCK);
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, !UNLOCK);
}
/*
@@ -841,18 +856,18 @@ RelationSetRIntentLock(Relation relation)
void
RelationUnsetRIntentLock(Relation relation)
{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- SingleLockReln((LockInfo)relation->lockInfo, READ_LOCK+INTENT, UNLOCK);
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, UNLOCK);
}
/*
@@ -862,18 +877,18 @@ RelationUnsetRIntentLock(Relation relation)
void
RelationSetWIntentLock(Relation relation)
{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- SingleLockReln((LockInfo)relation->lockInfo, WRITE_LOCK+INTENT, !UNLOCK);
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, !UNLOCK);
}
/*
@@ -882,69 +897,71 @@ RelationSetWIntentLock(Relation relation)
void
RelationUnsetWIntentLock(Relation relation)
{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- SingleLockReln((LockInfo)relation->lockInfo, WRITE_LOCK+INTENT, UNLOCK);
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, UNLOCK);
}
/*
* Extend locks are used primarily in tertiary storage devices such as
- * a WORM disk jukebox. Sometimes need exclusive access to extend a
+ * a WORM disk jukebox. Sometimes need exclusive access to extend a
* file by a block.
*/
#ifdef NOT_USED
void
RelationSetLockForExtend(Relation relation)
{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- MultiLockReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ MultiLockReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
}
+
#endif
#ifdef NOT_USED
void
RelationUnsetLockForExtend(Relation relation)
{
- /* -----------------
- * Sanity check
- * -----------------
- */
- Assert(RelationIsValid(relation));
- if (LockingDisabled())
- return;
-
- if (!LockInfoIsValid(relation->lockInfo))
- RelationInitLockInfo(relation);
-
- MultiReleaseReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
+ /* -----------------
+ * Sanity check
+ * -----------------
+ */
+ Assert(RelationIsValid(relation));
+ if (LockingDisabled())
+ return;
+
+ if (!LockInfoIsValid(relation->lockInfo))
+ RelationInitLockInfo(relation);
+
+ MultiReleaseReln((LockInfo) relation->lockInfo, EXTEND_LOCK);
}
+
#endif
-/*
+/*
* Create an LRelid --- Why not just pass in a pointer to the storage?
*/
static void
-LRelIdAssign(LRelId *lRelId, Oid dbId, Oid relId)
-{
- lRelId->dbId = dbId;
- lRelId->relId = relId;
+LRelIdAssign(LRelId * lRelId, Oid dbId, Oid relId)
+{
+ lRelId->dbId = dbId;
+ lRelId->relId = relId;
}
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 15ede2e0ed9..7e592945f1b 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -1,37 +1,37 @@
/*-------------------------------------------------------------------------
*
* lock.c--
- * simple lock acquisition
+ * simple lock acquisition
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.11 1997/08/19 21:33:19 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.12 1997/09/07 04:48:58 momjian Exp $
*
* NOTES
- * Outside modules can create a lock table and acquire/release
- * locks. A lock table is a shared memory hash table. When
- * a process tries to acquire a lock of a type that conflicts
- * with existing locks, it is put to sleep using the routines
- * in storage/lmgr/proc.c.
+ * Outside modules can create a lock table and acquire/release
+ * locks. A lock table is a shared memory hash table. When
+ * a process tries to acquire a lock of a type that conflicts
+ * with existing locks, it is put to sleep using the routines
+ * in storage/lmgr/proc.c.
*
- * Interface:
+ * Interface:
*
- * LockAcquire(), LockRelease(), LockTabInit().
+ * LockAcquire(), LockRelease(), LockTabInit().
*
- * LockReplace() is called only within this module and by the
- * lkchain module. It releases a lock without looking
- * the lock up in the lock table.
+ * LockReplace() is called only within this module and by the
+ * lkchain module. It releases a lock without looking
+ * the lock up in the lock table.
*
- * NOTE: This module is used to define new lock tables. The
- * multi-level lock table (multi.c) used by the heap
- * access methods calls these routines. See multi.c for
- * examples showing how to use this interface.
+ * NOTE: This module is used to define new lock tables. The
+ * multi-level lock table (multi.c) used by the heap
+ * access methods calls these routines. See multi.c for
+ * examples showing how to use this interface.
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
@@ -48,8 +48,9 @@
#include "access/xact.h"
#include "access/transam.h"
-static int WaitOnLock(LOCKTAB *ltable, LockTableId tableId, LOCK *lock,
- LOCKT lockt);
+static int
+WaitOnLock(LOCKTAB * ltable, LockTableId tableId, LOCK * lock,
+ LOCKT lockt);
/*#define LOCK_MGR_DEBUG*/
@@ -60,84 +61,85 @@ static int WaitOnLock(LOCKTAB *ltable, LockTableId tableId, LOCK *lock,
#define LOCK_DUMP_AUX(where,lock,type)
#define XID_PRINT(where,xidentP)
-#else /* LOCK_MGR_DEBUG */
-
-int lockDebug = 0;
-unsigned int lock_debug_oid_min = BootstrapObjectIdData;
-static char *lock_types[] = {
- "NONE",
- "WRITE",
- "READ",
- "WRITE INTENT",
- "READ INTENT",
- "EXTEND"
+#else /* LOCK_MGR_DEBUG */
+
+int lockDebug = 0;
+unsigned int lock_debug_oid_min = BootstrapObjectIdData;
+static char *lock_types[] = {
+ "NONE",
+ "WRITE",
+ "READ",
+ "WRITE INTENT",
+ "READ INTENT",
+ "EXTEND"
};
#define LOCK_PRINT(where,tag,type)\
- if ((lockDebug >= 1) && (tag->relId >= lock_debug_oid_min)) \
- elog(DEBUG, \
- "%s: pid (%d) rel (%d) dbid (%d) tid (%d,%d) type (%s)",where, \
- getpid(),\
- tag->relId, tag->dbId, \
- ((tag->tupleId.ip_blkid.bi_hi<<16)+\
- tag->tupleId.ip_blkid.bi_lo),\
- tag->tupleId.ip_posid, \
- lock_types[type])
+ if ((lockDebug >= 1) && (tag->relId >= lock_debug_oid_min)) \
+ elog(DEBUG, \
+ "%s: pid (%d) rel (%d) dbid (%d) tid (%d,%d) type (%s)",where, \
+ getpid(),\
+ tag->relId, tag->dbId, \
+ ((tag->tupleId.ip_blkid.bi_hi<<16)+\
+ tag->tupleId.ip_blkid.bi_lo),\
+ tag->tupleId.ip_posid, \
+ lock_types[type])
#define LOCK_DUMP(where,lock,type)\
- if ((lockDebug >= 1) && (lock->tag.relId >= lock_debug_oid_min)) \
- LOCK_DUMP_AUX(where,lock,type)
+ if ((lockDebug >= 1) && (lock->tag.relId >= lock_debug_oid_min)) \
+ LOCK_DUMP_AUX(where,lock,type)
#define LOCK_DUMP_AUX(where,lock,type)\
- elog(DEBUG, \
- "%s: pid (%d) rel (%d) dbid (%d) tid (%d,%d) nHolding (%d) "\
- "holders (%d,%d,%d,%d,%d) type (%s)",where, \
- getpid(),\
- lock->tag.relId, lock->tag.dbId, \
- ((lock->tag.tupleId.ip_blkid.bi_hi<<16)+\
- lock->tag.tupleId.ip_blkid.bi_lo),\
- lock->tag.tupleId.ip_posid, \
- lock->nHolding,\
- lock->holders[1],\
- lock->holders[2],\
- lock->holders[3],\
- lock->holders[4],\
- lock->holders[5],\
- lock_types[type])
+ elog(DEBUG, \
+ "%s: pid (%d) rel (%d) dbid (%d) tid (%d,%d) nHolding (%d) "\
+ "holders (%d,%d,%d,%d,%d) type (%s)",where, \
+ getpid(),\
+ lock->tag.relId, lock->tag.dbId, \
+ ((lock->tag.tupleId.ip_blkid.bi_hi<<16)+\
+ lock->tag.tupleId.ip_blkid.bi_lo),\
+ lock->tag.tupleId.ip_posid, \
+ lock->nHolding,\
+ lock->holders[1],\
+ lock->holders[2],\
+ lock->holders[3],\
+ lock->holders[4],\
+ lock->holders[5],\
+ lock_types[type])
#define XID_PRINT(where,xidentP)\
- if ((lockDebug >= 2) && \
- (((LOCK *)MAKE_PTR(xidentP->tag.lock))->tag.relId \
- >= lock_debug_oid_min)) \
- elog(DEBUG,\
- "%s: pid (%d) xid (%d) pid (%d) lock (%x) nHolding (%d) "\
- "holders (%d,%d,%d,%d,%d)",\
- where,\
- getpid(),\
- xidentP->tag.xid,\
- xidentP->tag.pid,\
- xidentP->tag.lock,\
- xidentP->nHolding,\
- xidentP->holders[1],\
- xidentP->holders[2],\
- xidentP->holders[3],\
- xidentP->holders[4],\
- xidentP->holders[5])
-
-#endif /* LOCK_MGR_DEBUG */
-
-SPINLOCK LockMgrLock; /* in Shmem or created in CreateSpinlocks() */
+ if ((lockDebug >= 2) && \
+ (((LOCK *)MAKE_PTR(xidentP->tag.lock))->tag.relId \
+ >= lock_debug_oid_min)) \
+ elog(DEBUG,\
+ "%s: pid (%d) xid (%d) pid (%d) lock (%x) nHolding (%d) "\
+ "holders (%d,%d,%d,%d,%d)",\
+ where,\
+ getpid(),\
+ xidentP->tag.xid,\
+ xidentP->tag.pid,\
+ xidentP->tag.lock,\
+ xidentP->nHolding,\
+ xidentP->holders[1],\
+ xidentP->holders[2],\
+ xidentP->holders[3],\
+ xidentP->holders[4],\
+ xidentP->holders[5])
+
+#endif /* LOCK_MGR_DEBUG */
+
+SPINLOCK LockMgrLock; /* in Shmem or created in
+ * CreateSpinlocks() */
/* This is to simplify/speed up some bit arithmetic */
-static MASK BITS_OFF[MAX_LOCKTYPES];
-static MASK BITS_ON[MAX_LOCKTYPES];
+static MASK BITS_OFF[MAX_LOCKTYPES];
+static MASK BITS_ON[MAX_LOCKTYPES];
/* -----------------
* XXX Want to move this to this file
* -----------------
*/
-static bool LockingIsDisabled;
+static bool LockingIsDisabled;
/* -------------------
* map from tableId to the lock table structure
@@ -149,28 +151,28 @@ static LOCKTAB *AllTables[MAX_TABLES];
* no zero-th table
* -------------------
*/
-static int NumTables = 1;
+static int NumTables = 1;
/* -------------------
* InitLocks -- Init the lock module. Create a private data
- * structure for constructing conflict masks.
+ * structure for constructing conflict masks.
* -------------------
*/
void
InitLocks()
{
- int i;
- int bit;
-
- bit = 1;
- /* -------------------
- * remember 0th locktype is invalid
- * -------------------
- */
- for (i=0;i<MAX_LOCKTYPES;i++,bit <<= 1)
+ int i;
+ int bit;
+
+ bit = 1;
+ /* -------------------
+ * remember 0th locktype is invalid
+ * -------------------
+ */
+ for (i = 0; i < MAX_LOCKTYPES; i++, bit <<= 1)
{
- BITS_ON[i] = bit;
- BITS_OFF[i] = ~bit;
+ BITS_ON[i] = bit;
+ BITS_OFF[i] = ~bit;
}
}
@@ -181,30 +183,30 @@ InitLocks()
void
LockDisable(int status)
{
- LockingIsDisabled = status;
+ LockingIsDisabled = status;
}
/*
* LockTypeInit -- initialize the lock table's lock type
- * structures
+ * structures
*
* Notes: just copying. Should only be called once.
*/
static void
-LockTypeInit(LOCKTAB *ltable,
- MASK *conflictsP,
- int *prioP,
- int ntypes)
+LockTypeInit(LOCKTAB * ltable,
+ MASK * conflictsP,
+ int *prioP,
+ int ntypes)
{
- int i;
-
- ltable->ctl->nLockTypes = ntypes;
- ntypes++;
- for (i=0;i<ntypes;i++,prioP++,conflictsP++)
+ int i;
+
+ ltable->ctl->nLockTypes = ntypes;
+ ntypes++;
+ for (i = 0; i < ntypes; i++, prioP++, conflictsP++)
{
- ltable->ctl->conflictTab[i] = *conflictsP;
- ltable->ctl->prio[i] = *prioP;
+ ltable->ctl->conflictTab[i] = *conflictsP;
+ ltable->ctl->prio[i] = *prioP;
}
}
@@ -212,873 +214,900 @@ LockTypeInit(LOCKTAB *ltable,
* LockTabInit -- initialize a lock table structure
*
* Notes:
- * (a) a lock table has four separate entries in the binding
- * table. This is because every shared hash table and spinlock
- * has its name stored in the binding table at its creation. It
- * is wasteful, in this case, but not much space is involved.
+ * (a) a lock table has four separate entries in the binding
+ * table. This is because every shared hash table and spinlock
+ * has its name stored in the binding table at its creation. It
+ * is wasteful, in this case, but not much space is involved.
*
*/
LockTableId
LockTabInit(char *tabName,
- MASK *conflictsP,
- int *prioP,
- int ntypes)
+ MASK * conflictsP,
+ int *prioP,
+ int ntypes)
{
- LOCKTAB *ltable;
- char *shmemName;
- HASHCTL info;
- int hash_flags;
- bool found;
- int status = TRUE;
-
- if (ntypes > MAX_LOCKTYPES)
+ LOCKTAB *ltable;
+ char *shmemName;
+ HASHCTL info;
+ int hash_flags;
+ bool found;
+ int status = TRUE;
+
+ if (ntypes > MAX_LOCKTYPES)
{
- elog(NOTICE,"LockTabInit: too many lock types %d greater than %d",
- ntypes,MAX_LOCKTYPES);
- return(INVALID_TABLEID);
+ elog(NOTICE, "LockTabInit: too many lock types %d greater than %d",
+ ntypes, MAX_LOCKTYPES);
+ return (INVALID_TABLEID);
}
-
- if (NumTables > MAX_TABLES)
+
+ if (NumTables > MAX_TABLES)
{
- elog(NOTICE,
- "LockTabInit: system limit of MAX_TABLES (%d) lock tables",
- MAX_TABLES);
- return(INVALID_TABLEID);
+ elog(NOTICE,
+ "LockTabInit: system limit of MAX_TABLES (%d) lock tables",
+ MAX_TABLES);
+ return (INVALID_TABLEID);
}
-
- /* allocate a string for the binding table lookup */
- shmemName = (char *) palloc((unsigned)(strlen(tabName)+32));
- if (! shmemName)
+
+ /* allocate a string for the binding table lookup */
+ shmemName = (char *) palloc((unsigned) (strlen(tabName) + 32));
+ if (!shmemName)
{
- elog(NOTICE,"LockTabInit: couldn't malloc string %s \n",tabName);
- return(INVALID_TABLEID);
+ elog(NOTICE, "LockTabInit: couldn't malloc string %s \n", tabName);
+ return (INVALID_TABLEID);
}
-
- /* each lock table has a non-shared header */
- ltable = (LOCKTAB *) palloc((unsigned) sizeof(LOCKTAB));
- if (! ltable)
+
+ /* each lock table has a non-shared header */
+ ltable = (LOCKTAB *) palloc((unsigned) sizeof(LOCKTAB));
+ if (!ltable)
{
- elog(NOTICE,"LockTabInit: couldn't malloc lock table %s\n",tabName);
- pfree (shmemName);
- return(INVALID_TABLEID);
+ elog(NOTICE, "LockTabInit: couldn't malloc lock table %s\n", tabName);
+ pfree(shmemName);
+ return (INVALID_TABLEID);
}
-
- /* ------------------------
- * find/acquire the spinlock for the table
- * ------------------------
- */
- SpinAcquire(LockMgrLock);
-
-
- /* -----------------------
- * allocate a control structure from shared memory or attach to it
- * if it already exists.
- * -----------------------
- */
- sprintf(shmemName,"%s (ctl)",tabName);
- ltable->ctl = (LOCKCTL *)
- ShmemInitStruct(shmemName,(unsigned)sizeof(LOCKCTL),&found);
-
- if (! ltable->ctl)
+
+ /* ------------------------
+ * find/acquire the spinlock for the table
+ * ------------------------
+ */
+ SpinAcquire(LockMgrLock);
+
+
+ /* -----------------------
+ * allocate a control structure from shared memory or attach to it
+ * if it already exists.
+ * -----------------------
+ */
+ sprintf(shmemName, "%s (ctl)", tabName);
+ ltable->ctl = (LOCKCTL *)
+ ShmemInitStruct(shmemName, (unsigned) sizeof(LOCKCTL), &found);
+
+ if (!ltable->ctl)
{
- elog(FATAL,"LockTabInit: couldn't initialize %s",tabName);
- status = FALSE;
+ elog(FATAL, "LockTabInit: couldn't initialize %s", tabName);
+ status = FALSE;
}
-
- /* ----------------
- * we're first - initialize
- * ----------------
- */
- if (! found)
+
+ /* ----------------
+ * we're first - initialize
+ * ----------------
+ */
+ if (!found)
{
- memset(ltable->ctl, 0, sizeof(LOCKCTL));
- ltable->ctl->masterLock = LockMgrLock;
- ltable->ctl->tableId = NumTables;
+ memset(ltable->ctl, 0, sizeof(LOCKCTL));
+ ltable->ctl->masterLock = LockMgrLock;
+ ltable->ctl->tableId = NumTables;
}
-
- /* --------------------
- * other modules refer to the lock table by a tableId
- * --------------------
- */
- AllTables[NumTables] = ltable;
- NumTables++;
- Assert(NumTables <= MAX_TABLES);
-
- /* ----------------------
- * allocate a hash table for the lock tags. This is used
- * to find the different locks.
- * ----------------------
- */
- info.keysize = sizeof(LOCKTAG);
- info.datasize = sizeof(LOCK);
- info.hash = tag_hash;
- hash_flags = (HASH_ELEM | HASH_FUNCTION);
-
- sprintf(shmemName,"%s (lock hash)",tabName);
- ltable->lockHash = (HTAB *) ShmemInitHash(shmemName,
- INIT_TABLE_SIZE,MAX_TABLE_SIZE,
- &info,hash_flags);
-
- Assert( ltable->lockHash->hash == tag_hash);
- if (! ltable->lockHash)
+
+ /* --------------------
+ * other modules refer to the lock table by a tableId
+ * --------------------
+ */
+ AllTables[NumTables] = ltable;
+ NumTables++;
+ Assert(NumTables <= MAX_TABLES);
+
+ /* ----------------------
+ * allocate a hash table for the lock tags. This is used
+ * to find the different locks.
+ * ----------------------
+ */
+ info.keysize = sizeof(LOCKTAG);
+ info.datasize = sizeof(LOCK);
+ info.hash = tag_hash;
+ hash_flags = (HASH_ELEM | HASH_FUNCTION);
+
+ sprintf(shmemName, "%s (lock hash)", tabName);
+ ltable->lockHash = (HTAB *) ShmemInitHash(shmemName,
+ INIT_TABLE_SIZE, MAX_TABLE_SIZE,
+ &info, hash_flags);
+
+ Assert(ltable->lockHash->hash == tag_hash);
+ if (!ltable->lockHash)
{
- elog(FATAL,"LockTabInit: couldn't initialize %s",tabName);
- status = FALSE;
+ elog(FATAL, "LockTabInit: couldn't initialize %s", tabName);
+ status = FALSE;
}
-
- /* -------------------------
- * allocate an xid table. When different transactions hold
- * the same lock, additional information must be saved (locks per tx).
- * -------------------------
- */
- info.keysize = XID_TAGSIZE;
- info.datasize = sizeof(XIDLookupEnt);
- info.hash = tag_hash;
- hash_flags = (HASH_ELEM | HASH_FUNCTION);
-
- sprintf(shmemName,"%s (xid hash)",tabName);
- ltable->xidHash = (HTAB *) ShmemInitHash(shmemName,
- INIT_TABLE_SIZE,MAX_TABLE_SIZE,
- &info,hash_flags);
-
- if (! ltable->xidHash)
+
+ /* -------------------------
+ * allocate an xid table. When different transactions hold
+ * the same lock, additional information must be saved (locks per tx).
+ * -------------------------
+ */
+ info.keysize = XID_TAGSIZE;
+ info.datasize = sizeof(XIDLookupEnt);
+ info.hash = tag_hash;
+ hash_flags = (HASH_ELEM | HASH_FUNCTION);
+
+ sprintf(shmemName, "%s (xid hash)", tabName);
+ ltable->xidHash = (HTAB *) ShmemInitHash(shmemName,
+ INIT_TABLE_SIZE, MAX_TABLE_SIZE,
+ &info, hash_flags);
+
+ if (!ltable->xidHash)
{
- elog(FATAL,"LockTabInit: couldn't initialize %s",tabName);
- status = FALSE;
+ elog(FATAL, "LockTabInit: couldn't initialize %s", tabName);
+ status = FALSE;
}
-
- /* init ctl data structures */
- LockTypeInit(ltable, conflictsP, prioP, ntypes);
-
- SpinRelease(LockMgrLock);
-
- pfree (shmemName);
-
- if (status)
- return(ltable->ctl->tableId);
- else
- return(INVALID_TABLEID);
+
+ /* init ctl data structures */
+ LockTypeInit(ltable, conflictsP, prioP, ntypes);
+
+ SpinRelease(LockMgrLock);
+
+ pfree(shmemName);
+
+ if (status)
+ return (ltable->ctl->tableId);
+ else
+ return (INVALID_TABLEID);
}
/*
* LockTabRename -- allocate another tableId to the same
- * lock table.
+ * lock table.
*
* NOTES: Both the lock module and the lock chain (lchain.c)
- * module use table id's to distinguish between different
- * kinds of locks. Short term and long term locks look
- * the same to the lock table, but are handled differently
- * by the lock chain manager. This function allows the
- * client to use different tableIds when acquiring/releasing
- * short term and long term locks.
+ * module use table id's to distinguish between different
+ * kinds of locks. Short term and long term locks look
+ * the same to the lock table, but are handled differently
+ * by the lock chain manager. This function allows the
+ * client to use different tableIds when acquiring/releasing
+ * short term and long term locks.
*/
#ifdef NOT_USED
LockTableId
LockTabRename(LockTableId tableId)
{
- LockTableId newTableId;
-
- if (NumTables >= MAX_TABLES)
+ LockTableId newTableId;
+
+ if (NumTables >= MAX_TABLES)
{
- return(INVALID_TABLEID);
+ return (INVALID_TABLEID);
}
- if (AllTables[tableId] == INVALID_TABLEID)
+ if (AllTables[tableId] == INVALID_TABLEID)
{
- return(INVALID_TABLEID);
+ return (INVALID_TABLEID);
}
-
- /* other modules refer to the lock table by a tableId */
- newTableId = NumTables;
- NumTables++;
-
- AllTables[newTableId] = AllTables[tableId];
- return(newTableId);
+
+ /* other modules refer to the lock table by a tableId */
+ newTableId = NumTables;
+ NumTables++;
+
+ AllTables[newTableId] = AllTables[tableId];
+ return (newTableId);
}
+
#endif
/*
* LockAcquire -- Check for lock conflicts, sleep if conflict found,
- * set lock if/when no conflicts.
+ * set lock if/when no conflicts.
*
* Returns: TRUE if parameters are correct, FALSE otherwise.
*
* Side Effects: The lock is always acquired. No way to abort
- * a lock acquisition other than aborting the transaction.
- * Lock is recorded in the lkchain.
+ * a lock acquisition other than aborting the transaction.
+ * Lock is recorded in the lkchain.
#ifdef USER_LOCKS
- * Note on User Locks:
- * User locks are handled totally on the application side as
- * long term cooperative locks which extend beyond the normal
- * transaction boundaries. Their purpose is to indicate to an
- * application that someone is `working' on an item. So it is
- * possible to put an user lock on a tuple's oid, retrieve the
- * tuple, work on it for an hour and then update it and remove
- * the lock. While the lock is active other clients can still
- * read and write the tuple but they can be aware that it has
- * been locked at the application level by someone.
- * User locks use lock tags made of an uint16 and an uint32, for
- * example 0 and a tuple oid, or any other arbitrary pair of
- * numbers following a convention established by the application.
- * In this sense tags don't refer to tuples or database entities.
- * User locks and normal locks are completely orthogonal and
- * they don't interfere with each other, so it is possible
- * to acquire a normal lock on an user-locked tuple or user-lock
- * a tuple for which a normal write lock already exists.
- * User locks are always non blocking, therefore they are never
- * acquired if already held by another process. They must be
- * released explicitly by the application but they are released
- * automatically when a backend terminates.
- * They are indicated by a dummy tableId 0 which doesn't have
- * any table allocated but uses the normal lock table, and are
- * distinguished from normal locks for the following differences:
+ * Note on User Locks:
+ * User locks are handled totally on the application side as
+ * long term cooperative locks which extend beyond the normal
+ * transaction boundaries. Their purpose is to indicate to an
+ * application that someone is `working' on an item. So it is
+ * possible to put an user lock on a tuple's oid, retrieve the
+ * tuple, work on it for an hour and then update it and remove
+ * the lock. While the lock is active other clients can still
+ * read and write the tuple but they can be aware that it has
+ * been locked at the application level by someone.
+ * User locks use lock tags made of an uint16 and an uint32, for
+ * example 0 and a tuple oid, or any other arbitrary pair of
+ * numbers following a convention established by the application.
+ * In this sense tags don't refer to tuples or database entities.
+ * User locks and normal locks are completely orthogonal and
+ * they don't interfere with each other, so it is possible
+ * to acquire a normal lock on an user-locked tuple or user-lock
+ * a tuple for which a normal write lock already exists.
+ * User locks are always non blocking, therefore they are never
+ * acquired if already held by another process. They must be
+ * released explicitly by the application but they are released
+ * automatically when a backend terminates.
+ * They are indicated by a dummy tableId 0 which doesn't have
+ * any table allocated but uses the normal lock table, and are
+ * distinguished from normal locks for the following differences:
*
- * normal lock user lock
+ * normal lock user lock
*
- * tableId 1 0
- * tag.relId rel oid 0
- * tag.ItemPointerData.ip_blkid block id lock id2
- * tag.ItemPointerData.ip_posid tuple offset lock id1
- * xid.pid 0 backend pid
- * xid.xid current xid 0
- * persistence transaction user or backend
+ * tableId 1 0
+ * tag.relId rel oid 0
+ * tag.ItemPointerData.ip_blkid block id lock id2
+ * tag.ItemPointerData.ip_posid tuple offset lock id1
+ * xid.pid 0 backend pid
+ * xid.xid current xid 0
+ * persistence transaction user or backend
*
- * The lockt parameter can have the same values for normal locks
- * although probably only WRITE_LOCK can have some practical use.
+ * The lockt parameter can have the same values for normal locks
+ * although probably only WRITE_LOCK can have some practical use.
*
- * DZ - 4 Oct 1996
+ * DZ - 4 Oct 1996
#endif
*/
bool
-LockAcquire(LockTableId tableId, LOCKTAG *lockName, LOCKT lockt)
+LockAcquire(LockTableId tableId, LOCKTAG * lockName, LOCKT lockt)
{
- XIDLookupEnt *result,item;
- HTAB *xidTable;
- bool found;
- LOCK *lock = NULL;
- SPINLOCK masterLock;
- LOCKTAB *ltable;
- int status;
- TransactionId myXid;
-
+ XIDLookupEnt *result,
+ item;
+ HTAB *xidTable;
+ bool found;
+ LOCK *lock = NULL;
+ SPINLOCK masterLock;
+ LOCKTAB *ltable;
+ int status;
+ TransactionId myXid;
+
#ifdef USER_LOCKS
- int is_user_lock;
+ int is_user_lock;
- is_user_lock = (tableId == 0);
- if (is_user_lock) {
- tableId = 1;
+ is_user_lock = (tableId == 0);
+ if (is_user_lock)
+ {
+ tableId = 1;
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,"LockAcquire: user lock tag [%u,%u] %d",
- lockName->tupleId.ip_posid,
- ((lockName->tupleId.ip_blkid.bi_hi<<16)+
- lockName->tupleId.ip_blkid.bi_lo),
- lockt);
+ elog(NOTICE, "LockAcquire: user lock tag [%u,%u] %d",
+ lockName->tupleId.ip_posid,
+ ((lockName->tupleId.ip_blkid.bi_hi << 16) +
+ lockName->tupleId.ip_blkid.bi_lo),
+ lockt);
#endif
- }
+ }
#endif
- Assert (tableId < NumTables);
- ltable = AllTables[tableId];
- if (!ltable)
+ Assert(tableId < NumTables);
+ ltable = AllTables[tableId];
+ if (!ltable)
{
- elog(NOTICE,"LockAcquire: bad lock table %d",tableId);
- return (FALSE);
+ elog(NOTICE, "LockAcquire: bad lock table %d", tableId);
+ return (FALSE);
}
-
- if (LockingIsDisabled)
+
+ if (LockingIsDisabled)
{
- return(TRUE);
+ return (TRUE);
}
-
- LOCK_PRINT("Acquire",lockName,lockt);
- masterLock = ltable->ctl->masterLock;
-
- SpinAcquire(masterLock);
-
- Assert( ltable->lockHash->hash == tag_hash);
- lock = (LOCK *)hash_search(ltable->lockHash,(Pointer)lockName,HASH_ENTER,&found);
-
- if (! lock)
+
+ LOCK_PRINT("Acquire", lockName, lockt);
+ masterLock = ltable->ctl->masterLock;
+
+ SpinAcquire(masterLock);
+
+ Assert(ltable->lockHash->hash == tag_hash);
+ lock = (LOCK *) hash_search(ltable->lockHash, (Pointer) lockName, HASH_ENTER, &found);
+
+ if (!lock)
{
- SpinRelease(masterLock);
- elog(FATAL,"LockAcquire: lock table %d is corrupted",tableId);
- return(FALSE);
+ SpinRelease(masterLock);
+ elog(FATAL, "LockAcquire: lock table %d is corrupted", tableId);
+ return (FALSE);
}
-
- /* --------------------
- * if there was nothing else there, complete initialization
- * --------------------
- */
- if (! found)
+
+ /* --------------------
+ * if there was nothing else there, complete initialization
+ * --------------------
+ */
+ if (!found)
{
- lock->mask = 0;
- ProcQueueInit(&(lock->waitProcs));
- memset((char *)lock->holders, 0, sizeof(int)*MAX_LOCKTYPES);
- memset((char *)lock->activeHolders, 0, sizeof(int)*MAX_LOCKTYPES);
- lock->nHolding = 0;
- lock->nActive = 0;
-
- Assert(BlockIdEquals(&(lock->tag.tupleId.ip_blkid),
- &(lockName->tupleId.ip_blkid)));
-
+ lock->mask = 0;
+ ProcQueueInit(&(lock->waitProcs));
+ memset((char *) lock->holders, 0, sizeof(int) * MAX_LOCKTYPES);
+ memset((char *) lock->activeHolders, 0, sizeof(int) * MAX_LOCKTYPES);
+ lock->nHolding = 0;
+ lock->nActive = 0;
+
+ Assert(BlockIdEquals(&(lock->tag.tupleId.ip_blkid),
+ &(lockName->tupleId.ip_blkid)));
+
}
-
- /* ------------------
- * add an element to the lock queue so that we can clear the
- * locks at end of transaction.
- * ------------------
- */
- xidTable = ltable->xidHash;
- myXid = GetCurrentTransactionId();
-
- /* ------------------
- * Zero out all of the tag bytes (this clears the padding bytes for long
- * word alignment and ensures hashing consistency).
- * ------------------
- */
- memset(&item, 0, XID_TAGSIZE);
- TransactionIdStore(myXid, &item.tag.xid);
- item.tag.lock = MAKE_OFFSET(lock);
+
+ /* ------------------
+ * add an element to the lock queue so that we can clear the
+ * locks at end of transaction.
+ * ------------------
+ */
+ xidTable = ltable->xidHash;
+ myXid = GetCurrentTransactionId();
+
+ /* ------------------
+ * Zero out all of the tag bytes (this clears the padding bytes for long
+ * word alignment and ensures hashing consistency).
+ * ------------------
+ */
+ memset(&item, 0, XID_TAGSIZE);
+ TransactionIdStore(myXid, &item.tag.xid);
+ item.tag.lock = MAKE_OFFSET(lock);
#if 0
- item.tag.pid = MyPid;
+ item.tag.pid = MyPid;
#endif
-
+
#ifdef USER_LOCKS
- if (is_user_lock) {
- item.tag.pid = getpid();
- item.tag.xid = myXid = 0;
+ if (is_user_lock)
+ {
+ item.tag.pid = getpid();
+ item.tag.xid = myXid = 0;
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,"LockAcquire: user lock xid [%d,%d,%d]",
- item.tag.lock, item.tag.pid, item.tag.xid);
+ elog(NOTICE, "LockAcquire: user lock xid [%d,%d,%d]",
+ item.tag.lock, item.tag.pid, item.tag.xid);
#endif
- }
+ }
#endif
- result = (XIDLookupEnt *)hash_search(xidTable, (Pointer)&item, HASH_ENTER, &found);
- if (!result)
+ result = (XIDLookupEnt *) hash_search(xidTable, (Pointer) & item, HASH_ENTER, &found);
+ if (!result)
{
- elog(NOTICE,"LockAcquire: xid table corrupted");
- return(STATUS_ERROR);
+ elog(NOTICE, "LockAcquire: xid table corrupted");
+ return (STATUS_ERROR);
}
- if (!found)
+ if (!found)
{
- XID_PRINT("LockAcquire: queueing XidEnt", result);
- ProcAddLock(&result->queue);
- result->nHolding = 0;
- memset((char *)result->holders, 0, sizeof(int)*MAX_LOCKTYPES);
+ XID_PRINT("LockAcquire: queueing XidEnt", result);
+ ProcAddLock(&result->queue);
+ result->nHolding = 0;
+ memset((char *) result->holders, 0, sizeof(int) * MAX_LOCKTYPES);
}
-
- /* ----------------
- * lock->nholding tells us how many processes have _tried_ to
- * acquire this lock, Regardless of whether they succeeded or
- * failed in doing so.
- * ----------------
- */
- lock->nHolding++;
- lock->holders[lockt]++;
-
- /* --------------------
- * If I'm the only one holding a lock, then there
- * cannot be a conflict. Need to subtract one from the
- * lock's count since we just bumped the count up by 1
- * above.
- * --------------------
- */
- if (result->nHolding == lock->nActive)
+
+ /* ----------------
+ * lock->nholding tells us how many processes have _tried_ to
+ * acquire this lock, Regardless of whether they succeeded or
+ * failed in doing so.
+ * ----------------
+ */
+ lock->nHolding++;
+ lock->holders[lockt]++;
+
+ /* --------------------
+ * If I'm the only one holding a lock, then there
+ * cannot be a conflict. Need to subtract one from the
+ * lock's count since we just bumped the count up by 1
+ * above.
+ * --------------------
+ */
+ if (result->nHolding == lock->nActive)
{
- result->holders[lockt]++;
- result->nHolding++;
- GrantLock(lock, lockt);
- SpinRelease(masterLock);
- return(TRUE);
+ result->holders[lockt]++;
+ result->nHolding++;
+ GrantLock(lock, lockt);
+ SpinRelease(masterLock);
+ return (TRUE);
}
-
- Assert(result->nHolding <= lock->nActive);
-
- status = LockResolveConflicts(ltable, lock, lockt, myXid);
-
- if (status == STATUS_OK)
+
+ Assert(result->nHolding <= lock->nActive);
+
+ status = LockResolveConflicts(ltable, lock, lockt, myXid);
+
+ if (status == STATUS_OK)
{
- GrantLock(lock, lockt);
+ GrantLock(lock, lockt);
}
- else if (status == STATUS_FOUND)
+ else if (status == STATUS_FOUND)
{
#ifdef USER_LOCKS
- /*
- * User locks are non blocking. If we can't acquire a lock
- * remove the xid entry and return FALSE without waiting.
- */
- if (is_user_lock) {
- if (!result->nHolding) {
- SHMQueueDelete(&result->queue);
- hash_search(xidTable, (Pointer)&item, HASH_REMOVE, &found);
- }
- lock->nHolding--;
- lock->holders[lockt]--;
- SpinRelease(masterLock);
+
+ /*
+ * User locks are non blocking. If we can't acquire a lock remove
+ * the xid entry and return FALSE without waiting.
+ */
+ if (is_user_lock)
+ {
+ if (!result->nHolding)
+ {
+ SHMQueueDelete(&result->queue);
+ hash_search(xidTable, (Pointer) & item, HASH_REMOVE, &found);
+ }
+ lock->nHolding--;
+ lock->holders[lockt]--;
+ SpinRelease(masterLock);
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,"LockAcquire: user lock failed");
+ elog(NOTICE, "LockAcquire: user lock failed");
#endif
- return(FALSE);
- }
+ return (FALSE);
+ }
#endif
- status = WaitOnLock(ltable, tableId, lock, lockt);
- XID_PRINT("Someone granted me the lock", result);
+ status = WaitOnLock(ltable, tableId, lock, lockt);
+ XID_PRINT("Someone granted me the lock", result);
}
-
- SpinRelease(masterLock);
-
- return(status == STATUS_OK);
+
+ SpinRelease(masterLock);
+
+ return (status == STATUS_OK);
}
/* ----------------------------
* LockResolveConflicts -- test for lock conflicts
*
* NOTES:
- * Here's what makes this complicated: one transaction's
+ * Here's what makes this complicated: one transaction's
* locks don't conflict with one another. When many processes
* hold locks, each has to subtract off the other's locks when
* determining whether or not any new lock acquired conflicts with
* the old ones.
*
- * For example, if I am already holding a WRITE_INTENT lock,
- * there will not be a conflict with my own READ_LOCK. If I
- * don't consider the intent lock when checking for conflicts,
- * I find no conflict.
+ * For example, if I am already holding a WRITE_INTENT lock,
+ * there will not be a conflict with my own READ_LOCK. If I
+ * don't consider the intent lock when checking for conflicts,
+ * I find no conflict.
* ----------------------------
*/
int
-LockResolveConflicts(LOCKTAB *ltable,
- LOCK *lock,
- LOCKT lockt,
- TransactionId xid)
+LockResolveConflicts(LOCKTAB * ltable,
+ LOCK * lock,
+ LOCKT lockt,
+ TransactionId xid)
{
- XIDLookupEnt *result,item;
- int *myHolders;
- int nLockTypes;
- HTAB *xidTable;
- bool found;
- int bitmask;
- int i,tmpMask;
-
- nLockTypes = ltable->ctl->nLockTypes;
- xidTable = ltable->xidHash;
-
- /* ---------------------
- * read my own statistics from the xid table. If there
- * isn't an entry, then we'll just add one.
- *
- * Zero out the tag, this clears the padding bytes for long
- * word alignment and ensures hashing consistency.
- * ------------------
- */
- memset(&item, 0, XID_TAGSIZE);
- TransactionIdStore(xid, &item.tag.xid);
- item.tag.lock = MAKE_OFFSET(lock);
+ XIDLookupEnt *result,
+ item;
+ int *myHolders;
+ int nLockTypes;
+ HTAB *xidTable;
+ bool found;
+ int bitmask;
+ int i,
+ tmpMask;
+
+ nLockTypes = ltable->ctl->nLockTypes;
+ xidTable = ltable->xidHash;
+
+ /* ---------------------
+ * read my own statistics from the xid table. If there
+ * isn't an entry, then we'll just add one.
+ *
+ * Zero out the tag, this clears the padding bytes for long
+ * word alignment and ensures hashing consistency.
+ * ------------------
+ */
+ memset(&item, 0, XID_TAGSIZE);
+ TransactionIdStore(xid, &item.tag.xid);
+ item.tag.lock = MAKE_OFFSET(lock);
#if 0
- item.tag.pid = pid;
+ item.tag.pid = pid;
#endif
-
- if (! (result = (XIDLookupEnt *)
- hash_search(xidTable, (Pointer)&item, HASH_ENTER, &found)))
+
+ if (!(result = (XIDLookupEnt *)
+ hash_search(xidTable, (Pointer) & item, HASH_ENTER, &found)))
{
- elog(NOTICE,"LockResolveConflicts: xid table corrupted");
- return(STATUS_ERROR);
+ elog(NOTICE, "LockResolveConflicts: xid table corrupted");
+ return (STATUS_ERROR);
}
- myHolders = result->holders;
-
- if (! found)
+ myHolders = result->holders;
+
+ if (!found)
{
- /* ---------------
- * we're not holding any type of lock yet. Clear
- * the lock stats.
- * ---------------
- */
- memset(result->holders, 0, nLockTypes * sizeof(*(lock->holders)));
- result->nHolding = 0;
+ /* ---------------
+ * we're not holding any type of lock yet. Clear
+ * the lock stats.
+ * ---------------
+ */
+ memset(result->holders, 0, nLockTypes * sizeof(*(lock->holders)));
+ result->nHolding = 0;
}
-
- /* ----------------------------
- * first check for global conflicts: If no locks conflict
- * with mine, then I get the lock.
- *
- * Checking for conflict: lock->mask represents the types of
- * currently held locks. conflictTable[lockt] has a bit
- * set for each type of lock that conflicts with mine. Bitwise
- * compare tells if there is a conflict.
- * ----------------------------
- */
- if (! (ltable->ctl->conflictTab[lockt] & lock->mask))
+
+ /* ----------------------------
+ * first check for global conflicts: If no locks conflict
+ * with mine, then I get the lock.
+ *
+ * Checking for conflict: lock->mask represents the types of
+ * currently held locks. conflictTable[lockt] has a bit
+ * set for each type of lock that conflicts with mine. Bitwise
+ * compare tells if there is a conflict.
+ * ----------------------------
+ */
+ if (!(ltable->ctl->conflictTab[lockt] & lock->mask))
{
-
- result->holders[lockt]++;
- result->nHolding++;
-
- XID_PRINT("Conflict Resolved: updated xid entry stats", result);
-
- return(STATUS_OK);
+
+ result->holders[lockt]++;
+ result->nHolding++;
+
+ XID_PRINT("Conflict Resolved: updated xid entry stats", result);
+
+ return (STATUS_OK);
}
-
- /* ------------------------
- * Rats. Something conflicts. But it could still be my own
- * lock. We have to construct a conflict mask
- * that does not reflect our own locks.
- * ------------------------
- */
- bitmask = 0;
- tmpMask = 2;
- for (i=1;i<=nLockTypes;i++, tmpMask <<= 1)
+
+ /* ------------------------
+ * Rats. Something conflicts. But it could still be my own
+ * lock. We have to construct a conflict mask
+ * that does not reflect our own locks.
+ * ------------------------
+ */
+ bitmask = 0;
+ tmpMask = 2;
+ for (i = 1; i <= nLockTypes; i++, tmpMask <<= 1)
{
- if (lock->activeHolders[i] - myHolders[i])
+ if (lock->activeHolders[i] - myHolders[i])
{
- bitmask |= tmpMask;
+ bitmask |= tmpMask;
}
}
-
- /* ------------------------
- * now check again for conflicts. 'bitmask' describes the types
- * of locks held by other processes. If one of these
- * conflicts with the kind of lock that I want, there is a
- * conflict and I have to sleep.
- * ------------------------
- */
- if (! (ltable->ctl->conflictTab[lockt] & bitmask))
+
+ /* ------------------------
+ * now check again for conflicts. 'bitmask' describes the types
+ * of locks held by other processes. If one of these
+ * conflicts with the kind of lock that I want, there is a
+ * conflict and I have to sleep.
+ * ------------------------
+ */
+ if (!(ltable->ctl->conflictTab[lockt] & bitmask))
{
-
- /* no conflict. Get the lock and go on */
-
- result->holders[lockt]++;
- result->nHolding++;
-
- XID_PRINT("Conflict Resolved: updated xid entry stats", result);
-
- return(STATUS_OK);
-
+
+ /* no conflict. Get the lock and go on */
+
+ result->holders[lockt]++;
+ result->nHolding++;
+
+ XID_PRINT("Conflict Resolved: updated xid entry stats", result);
+
+ return (STATUS_OK);
+
}
-
- return(STATUS_FOUND);
+
+ return (STATUS_FOUND);
}
static int
-WaitOnLock(LOCKTAB *ltable, LockTableId tableId, LOCK *lock, LOCKT lockt)
+WaitOnLock(LOCKTAB * ltable, LockTableId tableId, LOCK * lock, LOCKT lockt)
{
- PROC_QUEUE *waitQueue = &(lock->waitProcs);
-
- int prio = ltable->ctl->prio[lockt];
-
- /* the waitqueue is ordered by priority. I insert myself
- * according to the priority of the lock I am acquiring.
- *
- * SYNC NOTE: I am assuming that the lock table spinlock
- * is sufficient synchronization for this queue. That
- * will not be true if/when people can be deleted from
- * the queue by a SIGINT or something.
- */
- LOCK_DUMP_AUX("WaitOnLock: sleeping on lock", lock, lockt);
- if (ProcSleep(waitQueue,
- ltable->ctl->masterLock,
- lockt,
- prio,
- lock) != NO_ERROR)
+ PROC_QUEUE *waitQueue = &(lock->waitProcs);
+
+ int prio = ltable->ctl->prio[lockt];
+
+ /*
+ * the waitqueue is ordered by priority. I insert myself according to
+ * the priority of the lock I am acquiring.
+ *
+ * SYNC NOTE: I am assuming that the lock table spinlock is sufficient
+ * synchronization for this queue. That will not be true if/when
+ * people can be deleted from the queue by a SIGINT or something.
+ */
+ LOCK_DUMP_AUX("WaitOnLock: sleeping on lock", lock, lockt);
+ if (ProcSleep(waitQueue,
+ ltable->ctl->masterLock,
+ lockt,
+ prio,
+ lock) != NO_ERROR)
{
- /* -------------------
- * This could have happend as a result of a deadlock, see HandleDeadLock()
- * Decrement the lock nHolding and holders fields as we are no longer
- * waiting on this lock.
- * -------------------
- */
- lock->nHolding--;
- lock->holders[lockt]--;
- LOCK_DUMP_AUX("WaitOnLock: aborting on lock", lock, lockt);
- SpinRelease(ltable->ctl->masterLock);
- elog(WARN,"WaitOnLock: error on wakeup - Aborting this transaction");
+ /* -------------------
+ * This could have happend as a result of a deadlock, see HandleDeadLock()
+ * Decrement the lock nHolding and holders fields as we are no longer
+ * waiting on this lock.
+ * -------------------
+ */
+ lock->nHolding--;
+ lock->holders[lockt]--;
+ LOCK_DUMP_AUX("WaitOnLock: aborting on lock", lock, lockt);
+ SpinRelease(ltable->ctl->masterLock);
+ elog(WARN, "WaitOnLock: error on wakeup - Aborting this transaction");
}
-
- LOCK_DUMP_AUX("WaitOnLock: wakeup on lock", lock, lockt);
- return(STATUS_OK);
+
+ LOCK_DUMP_AUX("WaitOnLock: wakeup on lock", lock, lockt);
+ return (STATUS_OK);
}
/*
* LockRelease -- look up 'lockName' in lock table 'tableId' and
- * release it.
+ * release it.
*
* Side Effects: if the lock no longer conflicts with the highest
- * priority waiting process, that process is granted the lock
- * and awoken. (We have to grant the lock here to avoid a
- * race between the waking process and any new process to
- * come along and request the lock).
+ * priority waiting process, that process is granted the lock
+ * and awoken. (We have to grant the lock here to avoid a
+ * race between the waking process and any new process to
+ * come along and request the lock).
*/
bool
-LockRelease(LockTableId tableId, LOCKTAG *lockName, LOCKT lockt)
+LockRelease(LockTableId tableId, LOCKTAG * lockName, LOCKT lockt)
{
- LOCK *lock = NULL;
- SPINLOCK masterLock;
- bool found;
- LOCKTAB *ltable;
- XIDLookupEnt *result,item;
- HTAB *xidTable;
- bool wakeupNeeded = true;
-
+ LOCK *lock = NULL;
+ SPINLOCK masterLock;
+ bool found;
+ LOCKTAB *ltable;
+ XIDLookupEnt *result,
+ item;
+ HTAB *xidTable;
+ bool wakeupNeeded = true;
+
#ifdef USER_LOCKS
- int is_user_lock;
+ int is_user_lock;
- is_user_lock = (tableId == 0);
- if (is_user_lock) {
- tableId = 1;
+ is_user_lock = (tableId == 0);
+ if (is_user_lock)
+ {
+ tableId = 1;
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,"LockRelease: user lock tag [%u,%u] %d",
- lockName->tupleId.ip_posid,
- ((lockName->tupleId.ip_blkid.bi_hi<<16)+
- lockName->tupleId.ip_blkid.bi_lo),
- lockt);
+ elog(NOTICE, "LockRelease: user lock tag [%u,%u] %d",
+ lockName->tupleId.ip_posid,
+ ((lockName->tupleId.ip_blkid.bi_hi << 16) +
+ lockName->tupleId.ip_blkid.bi_lo),
+ lockt);
#endif
- }
+ }
#endif
- Assert (tableId < NumTables);
- ltable = AllTables[tableId];
- if (!ltable) {
- elog(NOTICE, "ltable is null in LockRelease");
- return (FALSE);
- }
-
- if (LockingIsDisabled)
+ Assert(tableId < NumTables);
+ ltable = AllTables[tableId];
+ if (!ltable)
+ {
+ elog(NOTICE, "ltable is null in LockRelease");
+ return (FALSE);
+ }
+
+ if (LockingIsDisabled)
{
- return(TRUE);
+ return (TRUE);
}
-
- LOCK_PRINT("Release",lockName,lockt);
-
- masterLock = ltable->ctl->masterLock;
- xidTable = ltable->xidHash;
-
- SpinAcquire(masterLock);
-
- Assert( ltable->lockHash->hash == tag_hash);
- lock = (LOCK *)
- hash_search(ltable->lockHash,(Pointer)lockName,HASH_FIND_SAVE,&found);
-
+
+ LOCK_PRINT("Release", lockName, lockt);
+
+ masterLock = ltable->ctl->masterLock;
+ xidTable = ltable->xidHash;
+
+ SpinAcquire(masterLock);
+
+ Assert(ltable->lockHash->hash == tag_hash);
+ lock = (LOCK *)
+ hash_search(ltable->lockHash, (Pointer) lockName, HASH_FIND_SAVE, &found);
+
#ifdef USER_LOCKS
- /*
- * If the entry is not found hash_search returns TRUE
- * instead of NULL, so we must check it explicitly.
- */
- if ((is_user_lock) && (lock == (LOCK *)TRUE)) {
- SpinRelease(masterLock);
- elog(NOTICE,"LockRelease: there are no locks with this tag");
- return(FALSE);
- }
+
+ /*
+ * If the entry is not found hash_search returns TRUE instead of NULL,
+ * so we must check it explicitly.
+ */
+ if ((is_user_lock) && (lock == (LOCK *) TRUE))
+ {
+ SpinRelease(masterLock);
+ elog(NOTICE, "LockRelease: there are no locks with this tag");
+ return (FALSE);
+ }
#endif
- /* let the caller print its own error message, too.
- * Do not elog(WARN).
- */
- if (! lock)
+ /*
+ * let the caller print its own error message, too. Do not elog(WARN).
+ */
+ if (!lock)
{
- SpinRelease(masterLock);
- elog(NOTICE,"LockRelease: locktable corrupted");
- return(FALSE);
+ SpinRelease(masterLock);
+ elog(NOTICE, "LockRelease: locktable corrupted");
+ return (FALSE);
}
-
- if (! found)
+
+ if (!found)
{
- SpinRelease(masterLock);
- elog(NOTICE,"LockRelease: locktable lookup failed, no lock");
- return(FALSE);
+ SpinRelease(masterLock);
+ elog(NOTICE, "LockRelease: locktable lookup failed, no lock");
+ return (FALSE);
}
-
- Assert(lock->nHolding > 0);
-
+
+ Assert(lock->nHolding > 0);
+
#ifdef USER_LOCKS
- /*
- * If this is an user lock it can be removed only after
- * checking that it was acquired by the current process,
- * so this code is skipped and executed later.
- */
- if (!is_user_lock) {
-#endif
- /*
- * fix the general lock stats
- */
- lock->nHolding--;
- lock->holders[lockt]--;
- lock->nActive--;
- lock->activeHolders[lockt]--;
-
- Assert(lock->nActive >= 0);
-
- if (! lock->nHolding)
+
+ /*
+ * If this is an user lock it can be removed only after checking that
+ * it was acquired by the current process, so this code is skipped and
+ * executed later.
+ */
+ if (!is_user_lock)
{
- /* ------------------
- * if there's no one waiting in the queue,
- * we just released the last lock.
- * Delete it from the lock table.
- * ------------------
- */
- Assert( ltable->lockHash->hash == tag_hash);
- lock = (LOCK *) hash_search(ltable->lockHash,
- (Pointer) &(lock->tag),
- HASH_REMOVE_SAVED,
- &found);
- Assert(lock && found);
- wakeupNeeded = false;
- }
+#endif
+
+ /*
+ * fix the general lock stats
+ */
+ lock->nHolding--;
+ lock->holders[lockt]--;
+ lock->nActive--;
+ lock->activeHolders[lockt]--;
+
+ Assert(lock->nActive >= 0);
+
+ if (!lock->nHolding)
+ {
+ /* ------------------
+ * if there's no one waiting in the queue,
+ * we just released the last lock.
+ * Delete it from the lock table.
+ * ------------------
+ */
+ Assert(ltable->lockHash->hash == tag_hash);
+ lock = (LOCK *) hash_search(ltable->lockHash,
+ (Pointer) & (lock->tag),
+ HASH_REMOVE_SAVED,
+ &found);
+ Assert(lock && found);
+ wakeupNeeded = false;
+ }
#ifdef USER_LOCKS
- }
+ }
#endif
-
- /* ------------------
- * Zero out all of the tag bytes (this clears the padding bytes for long
- * word alignment and ensures hashing consistency).
- * ------------------
- */
- memset(&item, 0, XID_TAGSIZE);
-
- TransactionIdStore(GetCurrentTransactionId(), &item.tag.xid);
- item.tag.lock = MAKE_OFFSET(lock);
+
+ /* ------------------
+ * Zero out all of the tag bytes (this clears the padding bytes for long
+ * word alignment and ensures hashing consistency).
+ * ------------------
+ */
+ memset(&item, 0, XID_TAGSIZE);
+
+ TransactionIdStore(GetCurrentTransactionId(), &item.tag.xid);
+ item.tag.lock = MAKE_OFFSET(lock);
#if 0
- item.tag.pid = MyPid;
+ item.tag.pid = MyPid;
#endif
-
+
#ifdef USER_LOCKS
- if (is_user_lock) {
- item.tag.pid = getpid();
- item.tag.xid = 0;
+ if (is_user_lock)
+ {
+ item.tag.pid = getpid();
+ item.tag.xid = 0;
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,"LockRelease: user lock xid [%d,%d,%d]",
- item.tag.lock, item.tag.pid, item.tag.xid);
+ elog(NOTICE, "LockRelease: user lock xid [%d,%d,%d]",
+ item.tag.lock, item.tag.pid, item.tag.xid);
#endif
- }
+ }
#endif
- if (! ( result = (XIDLookupEnt *) hash_search(xidTable,
- (Pointer)&item,
- HASH_FIND_SAVE,
- &found) )
- || !found)
+ if (!(result = (XIDLookupEnt *) hash_search(xidTable,
+ (Pointer) & item,
+ HASH_FIND_SAVE,
+ &found))
+ || !found)
{
- SpinRelease(masterLock);
+ SpinRelease(masterLock);
#ifdef USER_LOCKS
- if ((is_user_lock) && (result)) {
- elog(NOTICE,"LockRelease: you don't have a lock on this tag");
- } else {
- elog(NOTICE,"LockRelease: find xid, table corrupted");
- }
+ if ((is_user_lock) && (result))
+ {
+ elog(NOTICE, "LockRelease: you don't have a lock on this tag");
+ }
+ else
+ {
+ elog(NOTICE, "LockRelease: find xid, table corrupted");
+ }
#else
- elog(NOTICE,"LockReplace: xid table corrupted");
+ elog(NOTICE, "LockReplace: xid table corrupted");
#endif
- return(FALSE);
+ return (FALSE);
}
- /*
- * now check to see if I have any private locks. If I do,
- * decrement the counts associated with them.
- */
- result->holders[lockt]--;
- result->nHolding--;
-
- XID_PRINT("LockRelease updated xid stats", result);
-
- /*
- * If this was my last hold on this lock, delete my entry
- * in the XID table.
- */
- if (! result->nHolding)
+
+ /*
+ * now check to see if I have any private locks. If I do, decrement
+ * the counts associated with them.
+ */
+ result->holders[lockt]--;
+ result->nHolding--;
+
+ XID_PRINT("LockRelease updated xid stats", result);
+
+ /*
+ * If this was my last hold on this lock, delete my entry in the XID
+ * table.
+ */
+ if (!result->nHolding)
{
#ifdef USER_LOCKS
- if (result->queue.prev == INVALID_OFFSET) {
- elog(NOTICE,"LockRelease: xid.prev == INVALID_OFFSET");
- }
- if (result->queue.next == INVALID_OFFSET) {
- elog(NOTICE,"LockRelease: xid.next == INVALID_OFFSET");
- }
+ if (result->queue.prev == INVALID_OFFSET)
+ {
+ elog(NOTICE, "LockRelease: xid.prev == INVALID_OFFSET");
+ }
+ if (result->queue.next == INVALID_OFFSET)
+ {
+ elog(NOTICE, "LockRelease: xid.next == INVALID_OFFSET");
+ }
#endif
- if (result->queue.next != INVALID_OFFSET)
- SHMQueueDelete(&result->queue);
- if (! (result = (XIDLookupEnt *)
- hash_search(xidTable, (Pointer)&item, HASH_REMOVE_SAVED, &found)) ||
- ! found)
+ if (result->queue.next != INVALID_OFFSET)
+ SHMQueueDelete(&result->queue);
+ if (!(result = (XIDLookupEnt *)
+ hash_search(xidTable, (Pointer) & item, HASH_REMOVE_SAVED, &found)) ||
+ !found)
{
- SpinRelease(masterLock);
+ SpinRelease(masterLock);
#ifdef USER_LOCKS
- elog(NOTICE,"LockRelease: remove xid, table corrupted");
+ elog(NOTICE, "LockRelease: remove xid, table corrupted");
#else
- elog(NOTICE,"LockReplace: xid table corrupted");
+ elog(NOTICE, "LockReplace: xid table corrupted");
#endif
- return(FALSE);
+ return (FALSE);
}
}
-
+
#ifdef USER_LOCKS
- /*
- * If this is an user lock remove it now, after the
- * corresponding xid entry has been found and deleted.
- */
- if (is_user_lock) {
- /*
- * fix the general lock stats
- */
- lock->nHolding--;
- lock->holders[lockt]--;
- lock->nActive--;
- lock->activeHolders[lockt]--;
-
- Assert(lock->nActive >= 0);
-
- if (! lock->nHolding)
+
+ /*
+ * If this is an user lock remove it now, after the corresponding xid
+ * entry has been found and deleted.
+ */
+ if (is_user_lock)
{
- /* ------------------
- * if there's no one waiting in the queue,
- * we just released the last lock.
- * Delete it from the lock table.
- * ------------------
- */
- Assert( ltable->lockHash->hash == tag_hash);
- lock = (LOCK *) hash_search(ltable->lockHash,
- (Pointer) &(lock->tag),
- HASH_REMOVE,
- &found);
- Assert(lock && found);
- wakeupNeeded = false;
+
+ /*
+ * fix the general lock stats
+ */
+ lock->nHolding--;
+ lock->holders[lockt]--;
+ lock->nActive--;
+ lock->activeHolders[lockt]--;
+
+ Assert(lock->nActive >= 0);
+
+ if (!lock->nHolding)
+ {
+ /* ------------------
+ * if there's no one waiting in the queue,
+ * we just released the last lock.
+ * Delete it from the lock table.
+ * ------------------
+ */
+ Assert(ltable->lockHash->hash == tag_hash);
+ lock = (LOCK *) hash_search(ltable->lockHash,
+ (Pointer) & (lock->tag),
+ HASH_REMOVE,
+ &found);
+ Assert(lock && found);
+ wakeupNeeded = false;
+ }
}
- }
#endif
- /* --------------------------
- * If there are still active locks of the type I just released, no one
- * should be woken up. Whoever is asleep will still conflict
- * with the remaining locks.
- * --------------------------
- */
- if (! (lock->activeHolders[lockt]))
+ /* --------------------------
+ * If there are still active locks of the type I just released, no one
+ * should be woken up. Whoever is asleep will still conflict
+ * with the remaining locks.
+ * --------------------------
+ */
+ if (!(lock->activeHolders[lockt]))
{
- /* change the conflict mask. No more of this lock type. */
- lock->mask &= BITS_OFF[lockt];
+ /* change the conflict mask. No more of this lock type. */
+ lock->mask &= BITS_OFF[lockt];
}
-
- if (wakeupNeeded)
+
+ if (wakeupNeeded)
{
- /* --------------------------
- * Wake the first waiting process and grant him the lock if it
- * doesn't conflict. The woken process must record the lock
- * himself.
- * --------------------------
- */
- ProcLockWakeup(&(lock->waitProcs), (char *) ltable, (char *) lock);
+ /* --------------------------
+ * Wake the first waiting process and grant him the lock if it
+ * doesn't conflict. The woken process must record the lock
+ * himself.
+ * --------------------------
+ */
+ ProcLockWakeup(&(lock->waitProcs), (char *) ltable, (char *) lock);
}
-
- SpinRelease(masterLock);
- return(TRUE);
+
+ SpinRelease(masterLock);
+ return (TRUE);
}
/*
* GrantLock -- udpate the lock data structure to show
- * the new lock holder.
+ * the new lock holder.
*/
void
-GrantLock(LOCK *lock, LOCKT lockt)
+GrantLock(LOCK * lock, LOCKT lockt)
{
- lock->nActive++;
- lock->activeHolders[lockt]++;
- lock->mask |= BITS_ON[lockt];
+ lock->nActive++;
+ lock->activeHolders[lockt]++;
+ lock->mask |= BITS_ON[lockt];
}
#ifdef USER_LOCKS
@@ -1086,265 +1115,281 @@ GrantLock(LOCK *lock, LOCKT lockt)
* LockReleaseAll -- Release all locks in a process lock queue.
*
* Note: This code is a little complicated by the presence in the
- * same queue of user locks which can't be removed from the
- * normal lock queue at the end of a transaction. They must
- * however be removed when the backend exits.
- * A dummy tableId 0 is used to indicate that we are releasing
- * the user locks, from the code added to ProcKill().
+ * same queue of user locks which can't be removed from the
+ * normal lock queue at the end of a transaction. They must
+ * however be removed when the backend exits.
+ * A dummy tableId 0 is used to indicate that we are releasing
+ * the user locks, from the code added to ProcKill().
*/
#endif
bool
-LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue)
+LockReleaseAll(LockTableId tableId, SHM_QUEUE * lockQueue)
{
- PROC_QUEUE *waitQueue;
- int done;
- XIDLookupEnt *xidLook = NULL;
- XIDLookupEnt *tmp = NULL;
- SHMEM_OFFSET end = MAKE_OFFSET(lockQueue);
- SPINLOCK masterLock;
- LOCKTAB *ltable;
- int i,nLockTypes;
- LOCK *lock;
- bool found;
-
+ PROC_QUEUE *waitQueue;
+ int done;
+ XIDLookupEnt *xidLook = NULL;
+ XIDLookupEnt *tmp = NULL;
+ SHMEM_OFFSET end = MAKE_OFFSET(lockQueue);
+ SPINLOCK masterLock;
+ LOCKTAB *ltable;
+ int i,
+ nLockTypes;
+ LOCK *lock;
+ bool found;
+
#ifdef USER_LOCKS
- int is_user_lock_table, my_pid, count, nskip;
+ int is_user_lock_table,
+ my_pid,
+ count,
+ nskip;
- is_user_lock_table = (tableId == 0);
- my_pid = getpid();
+ is_user_lock_table = (tableId == 0);
+ my_pid = getpid();
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,"LockReleaseAll: tableId=%d, pid=%d", tableId, my_pid);
+ elog(NOTICE, "LockReleaseAll: tableId=%d, pid=%d", tableId, my_pid);
#endif
- if (is_user_lock_table) {
- tableId = 1;
- }
+ if (is_user_lock_table)
+ {
+ tableId = 1;
+ }
#endif
- Assert (tableId < NumTables);
- ltable = AllTables[tableId];
- if (!ltable)
- return (FALSE);
-
- nLockTypes = ltable->ctl->nLockTypes;
- masterLock = ltable->ctl->masterLock;
-
- if (SHMQueueEmpty(lockQueue))
- return TRUE;
-
+ Assert(tableId < NumTables);
+ ltable = AllTables[tableId];
+ if (!ltable)
+ return (FALSE);
+
+ nLockTypes = ltable->ctl->nLockTypes;
+ masterLock = ltable->ctl->masterLock;
+
+ if (SHMQueueEmpty(lockQueue))
+ return TRUE;
+
#ifdef USER_LOCKS
- SpinAcquire(masterLock);
+ SpinAcquire(masterLock);
#endif
- SHMQueueFirst(lockQueue,(Pointer*)&xidLook,&xidLook->queue);
-
- XID_PRINT("LockReleaseAll", xidLook);
-
+ SHMQueueFirst(lockQueue, (Pointer *) & xidLook, &xidLook->queue);
+
+ XID_PRINT("LockReleaseAll", xidLook);
+
#ifndef USER_LOCKS
- SpinAcquire(masterLock);
+ SpinAcquire(masterLock);
#else
- count = nskip = 0;
+ count = nskip = 0;
#endif
- for (;;)
+ for (;;)
{
- /* ---------------------------
- * XXX Here we assume the shared memory queue is circular and
- * that we know its internal structure. Should have some sort of
- * macros to allow one to walk it. mer 20 July 1991
- * ---------------------------
- */
- done = (xidLook->queue.next == end);
- lock = (LOCK *) MAKE_PTR(xidLook->tag.lock);
-
- LOCK_PRINT("ReleaseAll",(&lock->tag),0);
-
+ /* ---------------------------
+ * XXX Here we assume the shared memory queue is circular and
+ * that we know its internal structure. Should have some sort of
+ * macros to allow one to walk it. mer 20 July 1991
+ * ---------------------------
+ */
+ done = (xidLook->queue.next == end);
+ lock = (LOCK *) MAKE_PTR(xidLook->tag.lock);
+
+ LOCK_PRINT("ReleaseAll", (&lock->tag), 0);
+
#ifdef USER_LOCKS
- /*
- * Sometimes the queue appears to be messed up.
- */
- if (count++ > 2000) {
- elog(NOTICE,"LockReleaseAll: xid loop detected, giving up");
- nskip = 0;
- break;
- }
- if (is_user_lock_table) {
- if ((xidLook->tag.pid == 0) || (xidLook->tag.xid != 0)) {
-#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,"LockReleaseAll: skip normal lock [%d,%d,%d]",
- xidLook->tag.lock,xidLook->tag.pid,xidLook->tag.xid);
-#endif
- nskip++;
- goto next_item;
+
+ /*
+ * Sometimes the queue appears to be messed up.
+ */
+ if (count++ > 2000)
+ {
+ elog(NOTICE, "LockReleaseAll: xid loop detected, giving up");
+ nskip = 0;
+ break;
}
- if (xidLook->tag.pid != my_pid) {
- /* This should never happen */
+ if (is_user_lock_table)
+ {
+ if ((xidLook->tag.pid == 0) || (xidLook->tag.xid != 0))
+ {
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,
- "LockReleaseAll: skip other pid [%u,%u] [%d,%d,%d]",
- lock->tag.tupleId.ip_posid,
- ((lock->tag.tupleId.ip_blkid.bi_hi<<16)+
- lock->tag.tupleId.ip_blkid.bi_lo),
- xidLook->tag.lock,xidLook->tag.pid,xidLook->tag.xid);
+ elog(NOTICE, "LockReleaseAll: skip normal lock [%d,%d,%d]",
+ xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid);
#endif
- nskip++;
- goto next_item;
- }
+ nskip++;
+ goto next_item;
+ }
+ if (xidLook->tag.pid != my_pid)
+ {
+ /* This should never happen */
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,
- "LockReleaseAll: release user lock [%u,%u] [%d,%d,%d]",
- lock->tag.tupleId.ip_posid,
- ((lock->tag.tupleId.ip_blkid.bi_hi<<16)+
- lock->tag.tupleId.ip_blkid.bi_lo),
- xidLook->tag.lock,xidLook->tag.pid,xidLook->tag.xid);
+ elog(NOTICE,
+ "LockReleaseAll: skip other pid [%u,%u] [%d,%d,%d]",
+ lock->tag.tupleId.ip_posid,
+ ((lock->tag.tupleId.ip_blkid.bi_hi << 16) +
+ lock->tag.tupleId.ip_blkid.bi_lo),
+ xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid);
#endif
- } else {
- if ((xidLook->tag.pid != 0) || (xidLook->tag.xid == 0)) {
+ nskip++;
+ goto next_item;
+ }
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,
- "LockReleaseAll: skip user lock [%u,%u] [%d,%d,%d]",
- lock->tag.tupleId.ip_posid,
- ((lock->tag.tupleId.ip_blkid.bi_hi<<16)+
- lock->tag.tupleId.ip_blkid.bi_lo),
- xidLook->tag.lock,xidLook->tag.pid,xidLook->tag.xid);
+ elog(NOTICE,
+ "LockReleaseAll: release user lock [%u,%u] [%d,%d,%d]",
+ lock->tag.tupleId.ip_posid,
+ ((lock->tag.tupleId.ip_blkid.bi_hi << 16) +
+ lock->tag.tupleId.ip_blkid.bi_lo),
+ xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid);
#endif
- nskip++;
- goto next_item;
}
+ else
+ {
+ if ((xidLook->tag.pid != 0) || (xidLook->tag.xid == 0))
+ {
#ifdef USER_LOCKS_DEBUG
- elog(NOTICE,"LockReleaseAll: release normal lock [%d,%d,%d]",
- xidLook->tag.lock,xidLook->tag.pid,xidLook->tag.xid);
+ elog(NOTICE,
+ "LockReleaseAll: skip user lock [%u,%u] [%d,%d,%d]",
+ lock->tag.tupleId.ip_posid,
+ ((lock->tag.tupleId.ip_blkid.bi_hi << 16) +
+ lock->tag.tupleId.ip_blkid.bi_lo),
+ xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid);
#endif
- }
+ nskip++;
+ goto next_item;
+ }
+#ifdef USER_LOCKS_DEBUG
+ elog(NOTICE, "LockReleaseAll: release normal lock [%d,%d,%d]",
+ xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid);
+#endif
+ }
#endif
- /* ------------------
- * fix the general lock stats
- * ------------------
- */
- if (lock->nHolding != xidLook->nHolding)
+ /* ------------------
+ * fix the general lock stats
+ * ------------------
+ */
+ if (lock->nHolding != xidLook->nHolding)
{
- lock->nHolding -= xidLook->nHolding;
- lock->nActive -= xidLook->nHolding;
- Assert(lock->nActive >= 0);
- for (i=1; i<=nLockTypes; i++)
+ lock->nHolding -= xidLook->nHolding;
+ lock->nActive -= xidLook->nHolding;
+ Assert(lock->nActive >= 0);
+ for (i = 1; i <= nLockTypes; i++)
{
- lock->holders[i] -= xidLook->holders[i];
- lock->activeHolders[i] -= xidLook->holders[i];
- if (! lock->activeHolders[i])
- lock->mask &= BITS_OFF[i];
+ lock->holders[i] -= xidLook->holders[i];
+ lock->activeHolders[i] -= xidLook->holders[i];
+ if (!lock->activeHolders[i])
+ lock->mask &= BITS_OFF[i];
}
}
- else
+ else
{
- /* --------------
- * set nHolding to zero so that we can garbage collect the lock
- * down below...
- * --------------
- */
- lock->nHolding = 0;
+ /* --------------
+ * set nHolding to zero so that we can garbage collect the lock
+ * down below...
+ * --------------
+ */
+ lock->nHolding = 0;
}
- /* ----------------
- * always remove the xidLookup entry, we're done with it now
- * ----------------
- */
+ /* ----------------
+ * always remove the xidLookup entry, we're done with it now
+ * ----------------
+ */
#ifdef USER_LOCKS
- SHMQueueDelete(&xidLook->queue);
+ SHMQueueDelete(&xidLook->queue);
#endif
- if ((! hash_search(ltable->xidHash, (Pointer)xidLook, HASH_REMOVE, &found))
- || !found)
+ if ((!hash_search(ltable->xidHash, (Pointer) xidLook, HASH_REMOVE, &found))
+ || !found)
{
- SpinRelease(masterLock);
+ SpinRelease(masterLock);
#ifdef USER_LOCKS
- elog(NOTICE,"LockReleaseAll: xid table corrupted");
+ elog(NOTICE, "LockReleaseAll: xid table corrupted");
#else
- elog(NOTICE,"LockReplace: xid table corrupted");
+ elog(NOTICE, "LockReplace: xid table corrupted");
#endif
- return(FALSE);
+ return (FALSE);
}
-
- if (! lock->nHolding)
+
+ if (!lock->nHolding)
{
- /* --------------------
- * if there's no one waiting in the queue, we've just released
- * the last lock.
- * --------------------
- */
-
- Assert( ltable->lockHash->hash == tag_hash);
- lock = (LOCK *)
- hash_search(ltable->lockHash,(Pointer)&(lock->tag),HASH_REMOVE, &found);
- if ((! lock) || (!found))
+ /* --------------------
+ * if there's no one waiting in the queue, we've just released
+ * the last lock.
+ * --------------------
+ */
+
+ Assert(ltable->lockHash->hash == tag_hash);
+ lock = (LOCK *)
+ hash_search(ltable->lockHash, (Pointer) & (lock->tag), HASH_REMOVE, &found);
+ if ((!lock) || (!found))
{
- SpinRelease(masterLock);
+ SpinRelease(masterLock);
#ifdef USER_LOCKS
- elog(NOTICE,"LockReleaseAll: cannot remove lock from HTAB");
+ elog(NOTICE, "LockReleaseAll: cannot remove lock from HTAB");
#else
- elog(NOTICE,"LockReplace: cannot remove lock from HTAB");
+ elog(NOTICE, "LockReplace: cannot remove lock from HTAB");
#endif
- return(FALSE);
+ return (FALSE);
}
}
- else
+ else
{
- /* --------------------
- * Wake the first waiting process and grant him the lock if it
- * doesn't conflict. The woken process must record the lock
- * him/herself.
- * --------------------
- */
- waitQueue = &(lock->waitProcs);
- ProcLockWakeup(waitQueue, (char *) ltable, (char *) lock);
+ /* --------------------
+ * Wake the first waiting process and grant him the lock if it
+ * doesn't conflict. The woken process must record the lock
+ * him/herself.
+ * --------------------
+ */
+ waitQueue = &(lock->waitProcs);
+ ProcLockWakeup(waitQueue, (char *) ltable, (char *) lock);
}
-
+
#ifdef USER_LOCKS
- next_item:
+next_item:
#endif
- if (done)
- break;
- SHMQueueFirst(&xidLook->queue,(Pointer*)&tmp,&tmp->queue);
- xidLook = tmp;
+ if (done)
+ break;
+ SHMQueueFirst(&xidLook->queue, (Pointer *) & tmp, &tmp->queue);
+ xidLook = tmp;
}
- SpinRelease(masterLock);
+ SpinRelease(masterLock);
#ifdef USER_LOCKS
- /*
- * Reinitialize the queue only if nothing has been left in.
- */
- if (nskip == 0)
+
+ /*
+ * Reinitialize the queue only if nothing has been left in.
+ */
+ if (nskip == 0)
#endif
- SHMQueueInit(lockQueue);
- return TRUE;
+ SHMQueueInit(lockQueue);
+ return TRUE;
}
int
LockShmemSize()
{
- int size = 0;
- int nLockBuckets, nLockSegs;
- int nXidBuckets, nXidSegs;
-
- nLockBuckets = 1 << (int)my_log2((NLOCKENTS - 1) / DEF_FFACTOR + 1);
- nLockSegs = 1 << (int)my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
-
- nXidBuckets = 1 << (int)my_log2((NLOCKS_PER_XACT-1) / DEF_FFACTOR + 1);
- nXidSegs = 1 << (int)my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
-
- size += MAXALIGN(NBACKENDS * sizeof(PROC)); /* each MyProc */
- size += MAXALIGN(NBACKENDS * sizeof(LOCKCTL)); /* each ltable->ctl */
- size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
-
- size += MAXALIGN(my_log2(NLOCKENTS) * sizeof(void *));
- size += MAXALIGN(sizeof(HHDR));
- size += nLockSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
- size += NLOCKENTS * /* XXX not multiple of BUCKET_ALLOC_INCR? */
- (MAXALIGN(sizeof(BUCKET_INDEX)) +
- MAXALIGN(sizeof(LOCK))); /* contains hash key */
-
- size += MAXALIGN(my_log2(NBACKENDS) * sizeof(void *));
- size += MAXALIGN(sizeof(HHDR));
- size += nXidSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
- size += NBACKENDS * /* XXX not multiple of BUCKET_ALLOC_INCR? */
- (MAXALIGN(sizeof(BUCKET_INDEX)) +
- MAXALIGN(sizeof(XIDLookupEnt))); /* contains hash key */
-
- return size;
+ int size = 0;
+ int nLockBuckets,
+ nLockSegs;
+ int nXidBuckets,
+ nXidSegs;
+
+ nLockBuckets = 1 << (int) my_log2((NLOCKENTS - 1) / DEF_FFACTOR + 1);
+ nLockSegs = 1 << (int) my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
+
+ nXidBuckets = 1 << (int) my_log2((NLOCKS_PER_XACT - 1) / DEF_FFACTOR + 1);
+ nXidSegs = 1 << (int) my_log2((nLockBuckets - 1) / DEF_SEGSIZE + 1);
+
+ size += MAXALIGN(NBACKENDS * sizeof(PROC)); /* each MyProc */
+ size += MAXALIGN(NBACKENDS * sizeof(LOCKCTL)); /* each ltable->ctl */
+ size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
+
+ size += MAXALIGN(my_log2(NLOCKENTS) * sizeof(void *));
+ size += MAXALIGN(sizeof(HHDR));
+ size += nLockSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
+ size += NLOCKENTS * /* XXX not multiple of BUCKET_ALLOC_INCR? */
+ (MAXALIGN(sizeof(BUCKET_INDEX)) +
+ MAXALIGN(sizeof(LOCK))); /* contains hash key */
+
+ size += MAXALIGN(my_log2(NBACKENDS) * sizeof(void *));
+ size += MAXALIGN(sizeof(HHDR));
+ size += nXidSegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
+ size += NBACKENDS * /* XXX not multiple of BUCKET_ALLOC_INCR? */
+ (MAXALIGN(sizeof(BUCKET_INDEX)) +
+ MAXALIGN(sizeof(XIDLookupEnt))); /* contains hash key */
+
+ return size;
}
/* -----------------
@@ -1354,7 +1399,7 @@ LockShmemSize()
bool
LockingDisabled()
{
- return LockingIsDisabled;
+ return LockingIsDisabled;
}
#ifdef DEADLOCK_DEBUG
@@ -1364,67 +1409,71 @@ LockingDisabled()
void
DumpLocks()
{
- SHMEM_OFFSET location;
- PROC *proc;
- SHM_QUEUE *lockQueue;
- int done;
- XIDLookupEnt *xidLook = NULL;
- XIDLookupEnt *tmp = NULL;
- SHMEM_OFFSET end;
- SPINLOCK masterLock;
- int nLockTypes;
- LOCK *lock;
- int pid, count;
- int tableId = 1;
- LOCKTAB *ltable;
-
- pid = getpid();
- ShmemPIDLookup(pid,&location);
- if (location == INVALID_OFFSET)
- return;
- proc = (PROC *) MAKE_PTR(location);
- if (proc != MyProc)
- return;
- lockQueue = &proc->lockQueue;
-
- Assert (tableId < NumTables);
- ltable = AllTables[tableId];
- if (!ltable)
- return;
-
- nLockTypes = ltable->ctl->nLockTypes;
- masterLock = ltable->ctl->masterLock;
-
- if (SHMQueueEmpty(lockQueue))
- return;
-
- SHMQueueFirst(lockQueue,(Pointer*)&xidLook,&xidLook->queue);
- end = MAKE_OFFSET(lockQueue);
-
- LOCK_DUMP("DumpLocks", MyProc->waitLock, 0);
- XID_PRINT("DumpLocks", xidLook);
-
- for (count=0;;) {
- /* ---------------------------
- * XXX Here we assume the shared memory queue is circular and
- * that we know its internal structure. Should have some sort of
- * macros to allow one to walk it. mer 20 July 1991
- * ---------------------------
- */
- done = (xidLook->queue.next == end);
- lock = (LOCK *) MAKE_PTR(xidLook->tag.lock);
-
- LOCK_DUMP("DumpLocks",lock,0);
-
- if (count++ > 2000) {
- elog(NOTICE,"DumpLocks: xid loop detected, giving up");
- break;
+ SHMEM_OFFSET location;
+ PROC *proc;
+ SHM_QUEUE *lockQueue;
+ int done;
+ XIDLookupEnt *xidLook = NULL;
+ XIDLookupEnt *tmp = NULL;
+ SHMEM_OFFSET end;
+ SPINLOCK masterLock;
+ int nLockTypes;
+ LOCK *lock;
+ int pid,
+ count;
+ int tableId = 1;
+ LOCKTAB *ltable;
+
+ pid = getpid();
+ ShmemPIDLookup(pid, &location);
+ if (location == INVALID_OFFSET)
+ return;
+ proc = (PROC *) MAKE_PTR(location);
+ if (proc != MyProc)
+ return;
+ lockQueue = &proc->lockQueue;
+
+ Assert(tableId < NumTables);
+ ltable = AllTables[tableId];
+ if (!ltable)
+ return;
+
+ nLockTypes = ltable->ctl->nLockTypes;
+ masterLock = ltable->ctl->masterLock;
+
+ if (SHMQueueEmpty(lockQueue))
+ return;
+
+ SHMQueueFirst(lockQueue, (Pointer *) & xidLook, &xidLook->queue);
+ end = MAKE_OFFSET(lockQueue);
+
+ LOCK_DUMP("DumpLocks", MyProc->waitLock, 0);
+ XID_PRINT("DumpLocks", xidLook);
+
+ for (count = 0;;)
+ {
+ /* ---------------------------
+ * XXX Here we assume the shared memory queue is circular and
+ * that we know its internal structure. Should have some sort of
+ * macros to allow one to walk it. mer 20 July 1991
+ * ---------------------------
+ */
+ done = (xidLook->queue.next == end);
+ lock = (LOCK *) MAKE_PTR(xidLook->tag.lock);
+
+ LOCK_DUMP("DumpLocks", lock, 0);
+
+ if (count++ > 2000)
+ {
+ elog(NOTICE, "DumpLocks: xid loop detected, giving up");
+ break;
+ }
+
+ if (done)
+ break;
+ SHMQueueFirst(&xidLook->queue, (Pointer *) & tmp, &tmp->queue);
+ xidLook = tmp;
}
-
- if (done)
- break;
- SHMQueueFirst(&xidLook->queue,(Pointer*)&tmp,&tmp->queue);
- xidLook = tmp;
- }
}
+
#endif
diff --git a/src/backend/storage/lmgr/multi.c b/src/backend/storage/lmgr/multi.c
index 9cd3a36b48c..d5466fce04c 100644
--- a/src/backend/storage/lmgr/multi.c
+++ b/src/backend/storage/lmgr/multi.c
@@ -1,22 +1,22 @@
/*-------------------------------------------------------------------------
*
* multi.c--
- * multi level lock table manager
+ * multi level lock table manager
*
- * Standard multi-level lock manager as per the Gray paper
- * (at least, that is what it is supposed to be). We implement
- * three levels -- RELN, PAGE, TUPLE. Tuple is actually TID
- * a physical record pointer. It isn't an object id.
+ * Standard multi-level lock manager as per the Gray paper
+ * (at least, that is what it is supposed to be). We implement
+ * three levels -- RELN, PAGE, TUPLE. Tuple is actually TID
+ * a physical record pointer. It isn't an object id.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Attic/multi.c,v 1.4 1997/08/19 21:33:25 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Attic/multi.c,v 1.5 1997/09/07 04:49:02 momjian Exp $
*
* NOTES:
- * (1) The lock.c module assumes that the caller here is doing
- * two phase locking.
+ * (1) The lock.c module assumes that the caller here is doing
+ * two phase locking.
*
*-------------------------------------------------------------------------
*/
@@ -27,53 +27,59 @@
#include "storage/multilev.h"
#include "utils/rel.h"
-#include "miscadmin.h" /* MyDatabaseId */
+#include "miscadmin.h" /* MyDatabaseId */
-static bool MultiAcquire(LockTableId tableId, LOCKTAG *tag, LOCKT lockt,
+static bool
+MultiAcquire(LockTableId tableId, LOCKTAG * tag, LOCKT lockt,
LOCK_LEVEL level);
-static bool MultiRelease(LockTableId tableId, LOCKTAG *tag, LOCKT lockt,
+static bool
+MultiRelease(LockTableId tableId, LOCKTAG * tag, LOCKT lockt,
LOCK_LEVEL level);
/*
* INTENT indicates to higher level that a lower level lock has been
- * set. For example, a write lock on a tuple conflicts with a write
- * lock on a relation. This conflict is detected as a WRITE_INTENT/
+ * set. For example, a write lock on a tuple conflicts with a write
+ * lock on a relation. This conflict is detected as a WRITE_INTENT/
* WRITE conflict between the tuple's intent lock and the relation's
* write lock.
*/
-static int MultiConflicts[] = {
- (int)NULL,
- /* All reads and writes at any level conflict with a write lock */
- (1 << WRITE_LOCK)|(1 << WRITE_INTENT)|(1 << READ_LOCK)|(1 << READ_INTENT),
- /* read locks conflict with write locks at curr and lower levels */
- (1 << WRITE_LOCK)| (1 << WRITE_INTENT),
- /* write intent locks */
- (1 << READ_LOCK) | (1 << WRITE_LOCK),
- /* read intent locks*/
- (1 << WRITE_LOCK),
- /* extend locks for archive storage manager conflict only w/extend locks */
- (1 << EXTEND_LOCK)
+static int MultiConflicts[] = {
+ (int) NULL,
+ /* All reads and writes at any level conflict with a write lock */
+ (1 << WRITE_LOCK) | (1 << WRITE_INTENT) | (1 << READ_LOCK) | (1 << READ_INTENT),
+ /* read locks conflict with write locks at curr and lower levels */
+ (1 << WRITE_LOCK) | (1 << WRITE_INTENT),
+ /* write intent locks */
+ (1 << READ_LOCK) | (1 << WRITE_LOCK),
+ /* read intent locks */
+ (1 << WRITE_LOCK),
+
+ /*
+ * extend locks for archive storage manager conflict only w/extend
+ * locks
+ */
+ (1 << EXTEND_LOCK)
};
/*
* write locks have higher priority than read locks and extend locks. May
* want to treat INTENT locks differently.
*/
-static int MultiPrios[] = {
- (int)NULL,
- 2,
- 1,
- 2,
- 1,
- 1
+static int MultiPrios[] = {
+ (int) NULL,
+ 2,
+ 1,
+ 2,
+ 1,
+ 1
};
-/*
+/*
* Lock table identifier for this lock table. The multi-level
* lock table is ONE lock table, not three.
*/
-LockTableId MultiTableId = (LockTableId)NULL;
-LockTableId ShortTermTableId = (LockTableId)NULL;
+LockTableId MultiTableId = (LockTableId) NULL;
+LockTableId ShortTermTableId = (LockTableId) NULL;
/*
* Create the lock table described by MultiConflicts and Multiprio.
@@ -81,30 +87,31 @@ LockTableId ShortTermTableId = (LockTableId)NULL;
LockTableId
InitMultiLevelLockm()
{
- int tableId;
-
- /* -----------------------
- * If we're already initialized just return the table id.
- * -----------------------
- */
- if (MultiTableId)
+ int tableId;
+
+ /* -----------------------
+ * If we're already initialized just return the table id.
+ * -----------------------
+ */
+ if (MultiTableId)
+ return MultiTableId;
+
+ tableId = LockTabInit("LockTable", MultiConflicts, MultiPrios, 5);
+ MultiTableId = tableId;
+ if (!(MultiTableId))
+ {
+ elog(WARN, "InitMultiLockm: couldnt initialize lock table");
+ }
+ /* -----------------------
+ * No short term lock table for now. -Jeff 15 July 1991
+ *
+ * ShortTermTableId = LockTabRename(tableId);
+ * if (! (ShortTermTableId)) {
+ * elog(WARN,"InitMultiLockm: couldnt rename lock table");
+ * }
+ * -----------------------
+ */
return MultiTableId;
-
- tableId = LockTabInit("LockTable", MultiConflicts, MultiPrios, 5);
- MultiTableId = tableId;
- if (! (MultiTableId)) {
- elog(WARN,"InitMultiLockm: couldnt initialize lock table");
- }
- /* -----------------------
- * No short term lock table for now. -Jeff 15 July 1991
- *
- * ShortTermTableId = LockTabRename(tableId);
- * if (! (ShortTermTableId)) {
- * elog(WARN,"InitMultiLockm: couldnt rename lock table");
- * }
- * -----------------------
- */
- return MultiTableId;
}
/*
@@ -115,16 +122,16 @@ InitMultiLevelLockm()
bool
MultiLockReln(LockInfo linfo, LOCKT lockt)
{
- LOCKTAG tag;
-
- /* LOCKTAG has two bytes of padding, unfortunately. The
- * hash function will return miss if the padding bytes aren't
- * zero'd.
- */
- memset(&tag,0,sizeof(tag));
- tag.relId = linfo->lRelId.relId;
- tag.dbId = linfo->lRelId.dbId;
- return(MultiAcquire(MultiTableId, &tag, lockt, RELN_LEVEL));
+ LOCKTAG tag;
+
+ /*
+ * LOCKTAG has two bytes of padding, unfortunately. The hash function
+ * will return miss if the padding bytes aren't zero'd.
+ */
+ memset(&tag, 0, sizeof(tag));
+ tag.relId = linfo->lRelId.relId;
+ tag.dbId = linfo->lRelId.dbId;
+ return (MultiAcquire(MultiTableId, &tag, lockt, RELN_LEVEL));
}
/*
@@ -133,25 +140,25 @@ MultiLockReln(LockInfo linfo, LOCKT lockt)
* Returns: TRUE if lock is set, FALSE otherwise.
*
* Side Effects: causes intention level locks to be set
- * at the page and relation level.
+ * at the page and relation level.
*/
bool
MultiLockTuple(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt)
{
- LOCKTAG tag;
-
- /* LOCKTAG has two bytes of padding, unfortunately. The
- * hash function will return miss if the padding bytes aren't
- * zero'd.
- */
- memset(&tag,0,sizeof(tag));
-
- tag.relId = linfo->lRelId.relId;
- tag.dbId = linfo->lRelId.dbId;
-
- /* not locking any valid Tuple, just the page */
- tag.tupleId = *tidPtr;
- return(MultiAcquire(MultiTableId, &tag, lockt, TUPLE_LEVEL));
+ LOCKTAG tag;
+
+ /*
+ * LOCKTAG has two bytes of padding, unfortunately. The hash function
+ * will return miss if the padding bytes aren't zero'd.
+ */
+ memset(&tag, 0, sizeof(tag));
+
+ tag.relId = linfo->lRelId.relId;
+ tag.dbId = linfo->lRelId.dbId;
+
+ /* not locking any valid Tuple, just the page */
+ tag.tupleId = *tidPtr;
+ return (MultiAcquire(MultiTableId, &tag, lockt, TUPLE_LEVEL));
}
/*
@@ -160,28 +167,28 @@ MultiLockTuple(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt)
bool
MultiLockPage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt)
{
- LOCKTAG tag;
-
- /* LOCKTAG has two bytes of padding, unfortunately. The
- * hash function will return miss if the padding bytes aren't
- * zero'd.
- */
- memset(&tag,0,sizeof(tag));
-
-
- /* ----------------------------
- * Now we want to set the page offset to be invalid
- * and lock the block. There is some confusion here as to what
- * a page is. In Postgres a page is an 8k block, however this
- * block may be partitioned into many subpages which are sometimes
- * also called pages. The term is overloaded, so don't be fooled
- * when we say lock the page we mean the 8k block. -Jeff 16 July 1991
- * ----------------------------
- */
- tag.relId = linfo->lRelId.relId;
- tag.dbId = linfo->lRelId.dbId;
- BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid));
- return(MultiAcquire(MultiTableId, &tag, lockt, PAGE_LEVEL));
+ LOCKTAG tag;
+
+ /*
+ * LOCKTAG has two bytes of padding, unfortunately. The hash function
+ * will return miss if the padding bytes aren't zero'd.
+ */
+ memset(&tag, 0, sizeof(tag));
+
+
+ /* ----------------------------
+ * Now we want to set the page offset to be invalid
+ * and lock the block. There is some confusion here as to what
+ * a page is. In Postgres a page is an 8k block, however this
+ * block may be partitioned into many subpages which are sometimes
+ * also called pages. The term is overloaded, so don't be fooled
+ * when we say lock the page we mean the 8k block. -Jeff 16 July 1991
+ * ----------------------------
+ */
+ tag.relId = linfo->lRelId.relId;
+ tag.dbId = linfo->lRelId.dbId;
+ BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid));
+ return (MultiAcquire(MultiTableId, &tag, lockt, PAGE_LEVEL));
}
/*
@@ -190,102 +197,110 @@ MultiLockPage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt)
* Returns: TRUE if lock is set, FALSE if not
* Side Effects:
*/
-static bool
+static bool
MultiAcquire(LockTableId tableId,
- LOCKTAG *tag,
- LOCKT lockt,
- LOCK_LEVEL level)
+ LOCKTAG * tag,
+ LOCKT lockt,
+ LOCK_LEVEL level)
{
- LOCKT locks[N_LEVELS];
- int i,status;
- LOCKTAG xxTag, *tmpTag = &xxTag;
- int retStatus = TRUE;
-
- /*
- * Three levels implemented. If we set a low level (e.g. Tuple)
- * lock, we must set INTENT locks on the higher levels. The
- * intent lock detects conflicts between the low level lock
- * and an existing high level lock. For example, setting a
- * write lock on a tuple in a relation is disallowed if there
- * is an existing read lock on the entire relation. The
- * write lock would set a WRITE + INTENT lock on the relation
- * and that lock would conflict with the read.
- */
- switch (level) {
- case RELN_LEVEL:
- locks[0] = lockt;
- locks[1] = NO_LOCK;
- locks[2] = NO_LOCK;
- break;
- case PAGE_LEVEL:
- locks[0] = lockt + INTENT;
- locks[1] = lockt;
- locks[2] = NO_LOCK;
- break;
- case TUPLE_LEVEL:
- locks[0] = lockt + INTENT;
- locks[1] = lockt + INTENT;
- locks[2] = lockt;
- break;
- default:
- elog(WARN,"MultiAcquire: bad lock level");
- return(FALSE);
- }
-
- /*
- * construct a new tag as we go. Always loop through all levels,
- * but if we arent' seting a low level lock, locks[i] is set to
- * NO_LOCK for the lower levels. Always start from the highest
- * level and go to the lowest level.
- */
- memset(tmpTag,0,sizeof(*tmpTag));
- tmpTag->relId = tag->relId;
- tmpTag->dbId = tag->dbId;
-
- for (i=0;i<N_LEVELS;i++) {
- if (locks[i] != NO_LOCK) {
- switch (i) {
- case RELN_LEVEL:
- /* -------------
- * Set the block # and offset to invalid
- * -------------
- */
- BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber);
- tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
- break;
- case PAGE_LEVEL:
- /* -------------
- * Copy the block #, set the offset to invalid
- * -------------
- */
- BlockIdCopy(&(tmpTag->tupleId.ip_blkid),
- &(tag->tupleId.ip_blkid));
- tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
+ LOCKT locks[N_LEVELS];
+ int i,
+ status;
+ LOCKTAG xxTag,
+ *tmpTag = &xxTag;
+ int retStatus = TRUE;
+
+ /*
+ * Three levels implemented. If we set a low level (e.g. Tuple) lock,
+ * we must set INTENT locks on the higher levels. The intent lock
+ * detects conflicts between the low level lock and an existing high
+ * level lock. For example, setting a write lock on a tuple in a
+ * relation is disallowed if there is an existing read lock on the
+ * entire relation. The write lock would set a WRITE + INTENT lock on
+ * the relation and that lock would conflict with the read.
+ */
+ switch (level)
+ {
+ case RELN_LEVEL:
+ locks[0] = lockt;
+ locks[1] = NO_LOCK;
+ locks[2] = NO_LOCK;
break;
- case TUPLE_LEVEL:
- /* --------------
- * Copy the entire tuple id.
- * --------------
- */
- ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
+ case PAGE_LEVEL:
+ locks[0] = lockt + INTENT;
+ locks[1] = lockt;
+ locks[2] = NO_LOCK;
break;
- }
-
- status = LockAcquire(tableId, tmpTag, locks[i]);
- if (! status) {
- /* failed for some reason. Before returning we have
- * to release all of the locks we just acquired.
- * MultiRelease(xx,xx,xx, i) means release starting from
- * the last level lock we successfully acquired
- */
- retStatus = FALSE;
- MultiRelease(tableId, tag, lockt, i);
- /* now leave the loop. Don't try for any more locks */
+ case TUPLE_LEVEL:
+ locks[0] = lockt + INTENT;
+ locks[1] = lockt + INTENT;
+ locks[2] = lockt;
break;
- }
+ default:
+ elog(WARN, "MultiAcquire: bad lock level");
+ return (FALSE);
}
- }
- return(retStatus);
+
+ /*
+ * construct a new tag as we go. Always loop through all levels, but
+ * if we arent' seting a low level lock, locks[i] is set to NO_LOCK
+ * for the lower levels. Always start from the highest level and go
+ * to the lowest level.
+ */
+ memset(tmpTag, 0, sizeof(*tmpTag));
+ tmpTag->relId = tag->relId;
+ tmpTag->dbId = tag->dbId;
+
+ for (i = 0; i < N_LEVELS; i++)
+ {
+ if (locks[i] != NO_LOCK)
+ {
+ switch (i)
+ {
+ case RELN_LEVEL:
+ /* -------------
+ * Set the block # and offset to invalid
+ * -------------
+ */
+ BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber);
+ tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
+ break;
+ case PAGE_LEVEL:
+ /* -------------
+ * Copy the block #, set the offset to invalid
+ * -------------
+ */
+ BlockIdCopy(&(tmpTag->tupleId.ip_blkid),
+ &(tag->tupleId.ip_blkid));
+ tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
+ break;
+ case TUPLE_LEVEL:
+ /* --------------
+ * Copy the entire tuple id.
+ * --------------
+ */
+ ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
+ break;
+ }
+
+ status = LockAcquire(tableId, tmpTag, locks[i]);
+ if (!status)
+ {
+
+ /*
+ * failed for some reason. Before returning we have to
+ * release all of the locks we just acquired.
+ * MultiRelease(xx,xx,xx, i) means release starting from
+ * the last level lock we successfully acquired
+ */
+ retStatus = FALSE;
+ MultiRelease(tableId, tag, lockt, i);
+ /* now leave the loop. Don't try for any more locks */
+ break;
+ }
+ }
+ }
+ return (retStatus);
}
/* ------------------
@@ -294,24 +309,25 @@ MultiAcquire(LockTableId tableId,
*/
#ifdef NOT_USED
bool
-MultiReleasePage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt)
+MultiReleasePage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt)
{
- LOCKTAG tag;
-
- /* ------------------
- * LOCKTAG has two bytes of padding, unfortunately. The
- * hash function will return miss if the padding bytes aren't
- * zero'd.
- * ------------------
- */
- memset(&tag, 0,sizeof(LOCKTAG));
-
- tag.relId = linfo->lRelId.relId;
- tag.dbId = linfo->lRelId.dbId;
- BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid));
-
- return (MultiRelease(MultiTableId, &tag, lockt, PAGE_LEVEL));
+ LOCKTAG tag;
+
+ /* ------------------
+ * LOCKTAG has two bytes of padding, unfortunately. The
+ * hash function will return miss if the padding bytes aren't
+ * zero'd.
+ * ------------------
+ */
+ memset(&tag, 0, sizeof(LOCKTAG));
+
+ tag.relId = linfo->lRelId.relId;
+ tag.dbId = linfo->lRelId.dbId;
+ BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid));
+
+ return (MultiRelease(MultiTableId, &tag, lockt, PAGE_LEVEL));
}
+
#endif
/* ------------------
@@ -319,21 +335,21 @@ MultiReleasePage(LockInfo linfo, ItemPointer tidPtr, LOCKT lockt)
* ------------------
*/
bool
-MultiReleaseReln(LockInfo linfo, LOCKT lockt)
+MultiReleaseReln(LockInfo linfo, LOCKT lockt)
{
- LOCKTAG tag;
-
- /* ------------------
- * LOCKTAG has two bytes of padding, unfortunately. The
- * hash function will return miss if the padding bytes aren't
- * zero'd.
- * ------------------
- */
- memset(&tag, 0, sizeof(LOCKTAG));
- tag.relId = linfo->lRelId.relId;
- tag.dbId = linfo->lRelId.dbId;
-
- return (MultiRelease(MultiTableId, &tag, lockt, RELN_LEVEL));
+ LOCKTAG tag;
+
+ /* ------------------
+ * LOCKTAG has two bytes of padding, unfortunately. The
+ * hash function will return miss if the padding bytes aren't
+ * zero'd.
+ * ------------------
+ */
+ memset(&tag, 0, sizeof(LOCKTAG));
+ tag.relId = linfo->lRelId.relId;
+ tag.dbId = linfo->lRelId.dbId;
+
+ return (MultiRelease(MultiTableId, &tag, lockt, RELN_LEVEL));
}
/*
@@ -341,81 +357,88 @@ MultiReleaseReln(LockInfo linfo, LOCKT lockt)
*
* Returns: TRUE if successful, FALSE otherwise.
*/
-static bool
+static bool
MultiRelease(LockTableId tableId,
- LOCKTAG *tag,
- LOCKT lockt,
- LOCK_LEVEL level)
+ LOCKTAG * tag,
+ LOCKT lockt,
+ LOCK_LEVEL level)
{
- LOCKT locks[N_LEVELS];
- int i,status;
- LOCKTAG xxTag, *tmpTag = &xxTag;
-
- /*
- * same level scheme as MultiAcquire().
- */
- switch (level) {
- case RELN_LEVEL:
- locks[0] = lockt;
- locks[1] = NO_LOCK;
- locks[2] = NO_LOCK;
- break;
- case PAGE_LEVEL:
- locks[0] = lockt + INTENT;
- locks[1] = lockt;
- locks[2] = NO_LOCK;
- break;
- case TUPLE_LEVEL:
- locks[0] = lockt + INTENT;
- locks[1] = lockt + INTENT;
- locks[2] = lockt;
- break;
- default:
- elog(WARN,"MultiRelease: bad lockt");
- }
-
- /*
- * again, construct the tag on the fly. This time, however,
- * we release the locks in the REVERSE order -- from lowest
- * level to highest level.
- *
- * Must zero out the tag to set padding byes to zero and ensure
- * hashing consistency.
- */
- memset(tmpTag, 0, sizeof(*tmpTag));
- tmpTag->relId = tag->relId;
- tmpTag->dbId = tag->dbId;
-
- for (i=(N_LEVELS-1); i>=0; i--) {
- if (locks[i] != NO_LOCK) {
- switch (i) {
- case RELN_LEVEL:
- /* -------------
- * Set the block # and offset to invalid
- * -------------
- */
- BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber);
- tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
+ LOCKT locks[N_LEVELS];
+ int i,
+ status;
+ LOCKTAG xxTag,
+ *tmpTag = &xxTag;
+
+ /*
+ * same level scheme as MultiAcquire().
+ */
+ switch (level)
+ {
+ case RELN_LEVEL:
+ locks[0] = lockt;
+ locks[1] = NO_LOCK;
+ locks[2] = NO_LOCK;
break;
- case PAGE_LEVEL:
- /* -------------
- * Copy the block #, set the offset to invalid
- * -------------
- */
- BlockIdCopy(&(tmpTag->tupleId.ip_blkid),
- &(tag->tupleId.ip_blkid));
- tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
+ case PAGE_LEVEL:
+ locks[0] = lockt + INTENT;
+ locks[1] = lockt;
+ locks[2] = NO_LOCK;
break;
- case TUPLE_LEVEL:
- ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
+ case TUPLE_LEVEL:
+ locks[0] = lockt + INTENT;
+ locks[1] = lockt + INTENT;
+ locks[2] = lockt;
break;
- }
- status = LockRelease(tableId, tmpTag, locks[i]);
- if (! status) {
- elog(WARN,"MultiRelease: couldn't release after error");
- }
+ default:
+ elog(WARN, "MultiRelease: bad lockt");
+ }
+
+ /*
+ * again, construct the tag on the fly. This time, however, we
+ * release the locks in the REVERSE order -- from lowest level to
+ * highest level.
+ *
+ * Must zero out the tag to set padding byes to zero and ensure hashing
+ * consistency.
+ */
+ memset(tmpTag, 0, sizeof(*tmpTag));
+ tmpTag->relId = tag->relId;
+ tmpTag->dbId = tag->dbId;
+
+ for (i = (N_LEVELS - 1); i >= 0; i--)
+ {
+ if (locks[i] != NO_LOCK)
+ {
+ switch (i)
+ {
+ case RELN_LEVEL:
+ /* -------------
+ * Set the block # and offset to invalid
+ * -------------
+ */
+ BlockIdSet(&(tmpTag->tupleId.ip_blkid), InvalidBlockNumber);
+ tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
+ break;
+ case PAGE_LEVEL:
+ /* -------------
+ * Copy the block #, set the offset to invalid
+ * -------------
+ */
+ BlockIdCopy(&(tmpTag->tupleId.ip_blkid),
+ &(tag->tupleId.ip_blkid));
+ tmpTag->tupleId.ip_posid = InvalidOffsetNumber;
+ break;
+ case TUPLE_LEVEL:
+ ItemPointerCopy(&tmpTag->tupleId, &tag->tupleId);
+ break;
+ }
+ status = LockRelease(tableId, tmpTag, locks[i]);
+ if (!status)
+ {
+ elog(WARN, "MultiRelease: couldn't release after error");
+ }
+ }
}
- }
- /* shouldn't reach here */
- return false;
+ /* shouldn't reach here */
+ return false;
}
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 528bfa1e35d..e3872091dfc 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -1,25 +1,25 @@
/*-------------------------------------------------------------------------
*
* proc.c--
- * routines to manage per-process shared memory data structure
+ * routines to manage per-process shared memory data structure
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.18 1997/08/19 21:33:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.19 1997/09/07 04:49:03 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * Each postgres backend gets one of these. We'll use it to
- * clean up after the process should the process suddenly die.
+ * Each postgres backend gets one of these. We'll use it to
+ * clean up after the process should the process suddenly die.
*
*
* Interface (a):
- * ProcSleep(), ProcWakeup(), ProcWakeupNext(),
- * ProcQueueAlloc() -- create a shm queue for sleeping processes
- * ProcQueueInit() -- create a queue without allocing memory
+ * ProcSleep(), ProcWakeup(), ProcWakeupNext(),
+ * ProcQueueAlloc() -- create a shm queue for sleeping processes
+ * ProcQueueInit() -- create a queue without allocing memory
*
* Locking and waiting for buffers can cause the backend to be
* put to sleep. Whoever releases the lock, etc. wakes the
@@ -30,23 +30,23 @@
*
* ProcReleaseLocks -- frees the locks associated with this process,
* ProcKill -- destroys the shared memory state (and locks)
- * associated with the process.
+ * associated with the process.
*
* 5/15/91 -- removed the buffer pool based lock chain in favor
- * of a shared memory lock chain. The write-protection is
- * more expensive if the lock chain is in the buffer pool.
- * The only reason I kept the lock chain in the buffer pool
- * in the first place was to allow the lock table to grow larger
- * than available shared memory and that isn't going to work
- * without a lot of unimplemented support anyway.
+ * of a shared memory lock chain. The write-protection is
+ * more expensive if the lock chain is in the buffer pool.
+ * The only reason I kept the lock chain in the buffer pool
+ * in the first place was to allow the lock table to grow larger
+ * than available shared memory and that isn't going to work
+ * without a lot of unimplemented support anyway.
*
* 4/7/95 -- instead of allocating a set of 1 semaphore per process, we
- * allocate a semaphore from a set of PROC_NSEMS_PER_SET semaphores
- * shared among backends (we keep a few sets of semaphores around).
- * This is so that we can support more backends. (system-wide semaphore
- * sets run out pretty fast.) -ay 4/95
+ * allocate a semaphore from a set of PROC_NSEMS_PER_SET semaphores
+ * shared among backends (we keep a few sets of semaphores around).
+ * This is so that we can support more backends. (system-wide semaphore
+ * sets run out pretty fast.) -ay 4/95
*
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.18 1997/08/19 21:33:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.19 1997/09/07 04:49:03 momjian Exp $
*/
#include <sys/time.h>
#include <unistd.h>
@@ -69,21 +69,21 @@
#include "storage/ipc.h"
/* In Ultrix, sem.h must be included after ipc.h */
#include <sys/sem.h>
-#include "storage/buf.h"
+#include "storage/buf.h"
#include "storage/lock.h"
#include "storage/lmgr.h"
#include "storage/shmem.h"
#include "storage/spin.h"
#include "storage/proc.h"
-static void HandleDeadLock(int sig);
-static PROC *ProcWakeup(PROC *proc, int errType);
+static void HandleDeadLock(int sig);
+static PROC *ProcWakeup(PROC * proc, int errType);
/*
* timeout (in seconds) for resolving possible deadlock
*/
#ifndef DEADLOCK_TIMEOUT
-#define DEADLOCK_TIMEOUT 60
+#define DEADLOCK_TIMEOUT 60
#endif
/* --------------------
@@ -93,51 +93,52 @@ static PROC *ProcWakeup(PROC *proc, int errType);
* memory. -mer 17 July 1991
* --------------------
*/
-SPINLOCK ProcStructLock;
+SPINLOCK ProcStructLock;
/*
* For cleanup routines. Don't cleanup if the initialization
* has not happened.
*/
-static bool ProcInitialized = FALSE;
+static bool ProcInitialized = FALSE;
static PROC_HDR *ProcGlobal = NULL;
-PROC *MyProc = NULL;
+PROC *MyProc = NULL;
+
+static void ProcKill(int exitStatus, int pid);
+static void ProcGetNewSemKeyAndNum(IPCKey * key, int *semNum);
+static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
-static void ProcKill(int exitStatus, int pid);
-static void ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum);
-static void ProcFreeSem(IpcSemaphoreKey semKey, int semNum);
/*
* InitProcGlobal -
- * initializes the global process table. We put it here so that
- * the postmaster can do this initialization. (ProcFreeAllSem needs
- * to read this table on exiting the postmaster. If we have the first
- * backend do this, starting up and killing the postmaster without
- * starting any backends will be a problem.)
+ * initializes the global process table. We put it here so that
+ * the postmaster can do this initialization. (ProcFreeAllSem needs
+ * to read this table on exiting the postmaster. If we have the first
+ * backend do this, starting up and killing the postmaster without
+ * starting any backends will be a problem.)
*/
void
InitProcGlobal(IPCKey key)
{
- bool found = false;
+ bool found = false;
- /* attach to the free list */
- ProcGlobal = (PROC_HDR *)
- ShmemInitStruct("Proc Header",(unsigned)sizeof(PROC_HDR),&found);
+ /* attach to the free list */
+ ProcGlobal = (PROC_HDR *)
+ ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
- /* --------------------
- * We're the first - initialize.
- * --------------------
- */
- if (! found)
+ /* --------------------
+ * We're the first - initialize.
+ * --------------------
+ */
+ if (!found)
{
- int i;
+ int i;
- ProcGlobal->numProcs = 0;
- ProcGlobal->freeProcs = INVALID_OFFSET;
- ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
- for (i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++)
- ProcGlobal->freeSemMap[i] = 0;
+ ProcGlobal->numProcs = 0;
+ ProcGlobal->freeProcs = INVALID_OFFSET;
+ ProcGlobal->currKey = IPCGetProcessSemaphoreInitKey(key);
+ for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+ ProcGlobal->freeSemMap[i] = 0;
}
}
@@ -149,141 +150,149 @@ InitProcGlobal(IPCKey key)
void
InitProcess(IPCKey key)
{
- bool found = false;
- int pid;
- int semstat;
- unsigned long location, myOffset;
-
- /* ------------------
- * Routine called if deadlock timer goes off. See ProcSleep()
- * ------------------
- */
- pqsignal(SIGALRM, HandleDeadLock);
-
- SpinAcquire(ProcStructLock);
-
- /* attach to the free list */
- ProcGlobal = (PROC_HDR *)
- ShmemInitStruct("Proc Header",(unsigned)sizeof(PROC_HDR),&found);
- if (!found) {
- /* this should not happen. InitProcGlobal() is called before this. */
- elog(WARN, "InitProcess: Proc Header uninitialized");
- }
-
- if (MyProc != NULL)
+ bool found = false;
+ int pid;
+ int semstat;
+ unsigned long location,
+ myOffset;
+
+ /* ------------------
+ * Routine called if deadlock timer goes off. See ProcSleep()
+ * ------------------
+ */
+ pqsignal(SIGALRM, HandleDeadLock);
+
+ SpinAcquire(ProcStructLock);
+
+ /* attach to the free list */
+ ProcGlobal = (PROC_HDR *)
+ ShmemInitStruct("Proc Header", (unsigned) sizeof(PROC_HDR), &found);
+ if (!found)
{
- SpinRelease(ProcStructLock);
- elog(WARN,"ProcInit: you already exist");
- return;
+ /* this should not happen. InitProcGlobal() is called before this. */
+ elog(WARN, "InitProcess: Proc Header uninitialized");
}
-
- /* try to get a proc from the free list first */
-
- myOffset = ProcGlobal->freeProcs;
-
- if (myOffset != INVALID_OFFSET)
+
+ if (MyProc != NULL)
{
- MyProc = (PROC *) MAKE_PTR(myOffset);
- ProcGlobal->freeProcs = MyProc->links.next;
+ SpinRelease(ProcStructLock);
+ elog(WARN, "ProcInit: you already exist");
+ return;
}
- else
+
+ /* try to get a proc from the free list first */
+
+ myOffset = ProcGlobal->freeProcs;
+
+ if (myOffset != INVALID_OFFSET)
{
- /* have to allocate one. We can't use the normal binding
- * table mechanism because the proc structure is stored
- * by PID instead of by a global name (need to look it
- * up by PID when we cleanup dead processes).
- */
-
- MyProc = (PROC *) ShmemAlloc((unsigned)sizeof(PROC));
- if (! MyProc)
+ MyProc = (PROC *) MAKE_PTR(myOffset);
+ ProcGlobal->freeProcs = MyProc->links.next;
+ }
+ else
+ {
+
+ /*
+ * have to allocate one. We can't use the normal binding table
+ * mechanism because the proc structure is stored by PID instead
+ * of by a global name (need to look it up by PID when we cleanup
+ * dead processes).
+ */
+
+ MyProc = (PROC *) ShmemAlloc((unsigned) sizeof(PROC));
+ if (!MyProc)
{
- SpinRelease(ProcStructLock);
- elog (FATAL,"cannot create new proc: out of memory");
+ SpinRelease(ProcStructLock);
+ elog(FATAL, "cannot create new proc: out of memory");
}
-
- /* this cannot be initialized until after the buffer pool */
- SHMQueueInit(&(MyProc->lockQueue));
- MyProc->procId = ProcGlobal->numProcs;
- ProcGlobal->numProcs++;
+
+ /* this cannot be initialized until after the buffer pool */
+ SHMQueueInit(&(MyProc->lockQueue));
+ MyProc->procId = ProcGlobal->numProcs;
+ ProcGlobal->numProcs++;
}
-
- /*
- * zero out the spin lock counts and set the sLocks field for
- * ProcStructLock to 1 as we have acquired this spinlock above but
- * didn't record it since we didn't have MyProc until now.
- */
- memset(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
- MyProc->sLocks[ProcStructLock] = 1;
-
-
- if (IsUnderPostmaster) {
- IPCKey semKey;
- int semNum;
- int semId;
- union semun semun;
-
- ProcGetNewSemKeyAndNum(&semKey, &semNum);
-
- semId = IpcSemaphoreCreate(semKey,
- PROC_NSEMS_PER_SET,
- IPCProtection,
- IpcSemaphoreDefaultStartValue,
- 0,
- &semstat);
+
/*
- * we might be reusing a semaphore that belongs to a dead
- * backend. So be careful and reinitialize its value here.
+ * zero out the spin lock counts and set the sLocks field for
+ * ProcStructLock to 1 as we have acquired this spinlock above but
+ * didn't record it since we didn't have MyProc until now.
*/
- semun.val = IpcSemaphoreDefaultStartValue;
- semctl(semId, semNum, SETVAL, semun);
-
- IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
- MyProc->sem.semId = semId;
- MyProc->sem.semNum = semNum;
- MyProc->sem.semKey = semKey;
- } else {
- MyProc->sem.semId = -1;
- }
-
- /* ----------------------
- * Release the lock.
- * ----------------------
- */
- SpinRelease(ProcStructLock);
-
- MyProc->pid = 0;
- MyProc->xid = InvalidTransactionId;
+ memset(MyProc->sLocks, 0, sizeof(MyProc->sLocks));
+ MyProc->sLocks[ProcStructLock] = 1;
+
+
+ if (IsUnderPostmaster)
+ {
+ IPCKey semKey;
+ int semNum;
+ int semId;
+ union semun semun;
+
+ ProcGetNewSemKeyAndNum(&semKey, &semNum);
+
+ semId = IpcSemaphoreCreate(semKey,
+ PROC_NSEMS_PER_SET,
+ IPCProtection,
+ IpcSemaphoreDefaultStartValue,
+ 0,
+ &semstat);
+
+ /*
+ * we might be reusing a semaphore that belongs to a dead backend.
+ * So be careful and reinitialize its value here.
+ */
+ semun.val = IpcSemaphoreDefaultStartValue;
+ semctl(semId, semNum, SETVAL, semun);
+
+ IpcSemaphoreLock(semId, semNum, IpcExclusiveLock);
+ MyProc->sem.semId = semId;
+ MyProc->sem.semNum = semNum;
+ MyProc->sem.semKey = semKey;
+ }
+ else
+ {
+ MyProc->sem.semId = -1;
+ }
+
+ /* ----------------------
+ * Release the lock.
+ * ----------------------
+ */
+ SpinRelease(ProcStructLock);
+
+ MyProc->pid = 0;
+ MyProc->xid = InvalidTransactionId;
#if 0
- MyProc->pid = MyPid;
+ MyProc->pid = MyPid;
#endif
-
- /* ----------------
- * Start keeping spin lock stats from here on. Any botch before
- * this initialization is forever botched
- * ----------------
- */
- memset(MyProc->sLocks, 0, MAX_SPINS*sizeof(*MyProc->sLocks));
-
- /* -------------------------
- * Install ourselves in the binding table. The name to
- * use is determined by the OS-assigned process id. That
- * allows the cleanup process to find us after any untimely
- * exit.
- * -------------------------
- */
- pid = getpid();
- location = MAKE_OFFSET(MyProc);
- if ((! ShmemPIDLookup(pid,&location)) || (location != MAKE_OFFSET(MyProc)))
+
+ /* ----------------
+ * Start keeping spin lock stats from here on. Any botch before
+ * this initialization is forever botched
+ * ----------------
+ */
+ memset(MyProc->sLocks, 0, MAX_SPINS * sizeof(*MyProc->sLocks));
+
+ /* -------------------------
+ * Install ourselves in the binding table. The name to
+ * use is determined by the OS-assigned process id. That
+ * allows the cleanup process to find us after any untimely
+ * exit.
+ * -------------------------
+ */
+ pid = getpid();
+ location = MAKE_OFFSET(MyProc);
+ if ((!ShmemPIDLookup(pid, &location)) || (location != MAKE_OFFSET(MyProc)))
{
- elog(FATAL,"InitProc: ShmemPID table broken");
+ elog(FATAL, "InitProc: ShmemPID table broken");
}
-
- MyProc->errType = NO_ERROR;
- SHMQueueElemInit(&(MyProc->links));
-
- on_exitpg(ProcKill, (caddr_t)pid);
-
- ProcInitialized = TRUE;
+
+ MyProc->errType = NO_ERROR;
+ SHMQueueElemInit(&(MyProc->links));
+
+ on_exitpg(ProcKill, (caddr_t) pid);
+
+ ProcInitialized = TRUE;
}
/*
@@ -293,109 +302,112 @@ InitProcess(IPCKey key)
void
ProcReleaseLocks()
{
- if (!MyProc)
- return;
- LockReleaseAll(1,&MyProc->lockQueue);
+ if (!MyProc)
+ return;
+ LockReleaseAll(1, &MyProc->lockQueue);
}
/*
* ProcRemove -
- * used by the postmaster to clean up the global tables. This also frees
- * up the semaphore used for the lmgr of the process. (We have to do
- * this is the postmaster instead of doing a IpcSemaphoreKill on exiting
- * the process because the semaphore set is shared among backends and
- * we don't want to remove other's semaphores on exit.)
+ * used by the postmaster to clean up the global tables. This also frees
+ * up the semaphore used for the lmgr of the process. (We have to do
+ * this is the postmaster instead of doing a IpcSemaphoreKill on exiting
+ * the process because the semaphore set is shared among backends and
+ * we don't want to remove other's semaphores on exit.)
*/
bool
ProcRemove(int pid)
{
- SHMEM_OFFSET location;
- PROC *proc;
-
- location = INVALID_OFFSET;
-
- location = ShmemPIDDestroy(pid);
- if (location == INVALID_OFFSET)
- return(FALSE);
- proc = (PROC *) MAKE_PTR(location);
-
- SpinAcquire(ProcStructLock);
-
- ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
-
- proc->links.next = ProcGlobal->freeProcs;
- ProcGlobal->freeProcs = MAKE_OFFSET(proc);
-
- SpinRelease(ProcStructLock);
-
- return(TRUE);
+ SHMEM_OFFSET location;
+ PROC *proc;
+
+ location = INVALID_OFFSET;
+
+ location = ShmemPIDDestroy(pid);
+ if (location == INVALID_OFFSET)
+ return (FALSE);
+ proc = (PROC *) MAKE_PTR(location);
+
+ SpinAcquire(ProcStructLock);
+
+ ProcFreeSem(proc->sem.semKey, proc->sem.semNum);
+
+ proc->links.next = ProcGlobal->freeProcs;
+ ProcGlobal->freeProcs = MAKE_OFFSET(proc);
+
+ SpinRelease(ProcStructLock);
+
+ return (TRUE);
}
/*
* ProcKill() -- Destroy the per-proc data structure for
- * this process. Release any of its held spin locks.
+ * this process. Release any of its held spin locks.
*/
static void
ProcKill(int exitStatus, int pid)
{
- PROC *proc;
- SHMEM_OFFSET location;
-
- /* --------------------
- * If this is a FATAL exit the postmaster will have to kill all the
- * existing backends and reinitialize shared memory. So all we don't
- * need to do anything here.
- * --------------------
- */
- if (exitStatus != 0)
- return;
-
- if (! pid)
+ PROC *proc;
+ SHMEM_OFFSET location;
+
+ /* --------------------
+ * If this is a FATAL exit the postmaster will have to kill all the
+ * existing backends and reinitialize shared memory. So all we don't
+ * need to do anything here.
+ * --------------------
+ */
+ if (exitStatus != 0)
+ return;
+
+ if (!pid)
{
- pid = getpid();
+ pid = getpid();
}
-
- ShmemPIDLookup(pid,&location);
- if (location == INVALID_OFFSET)
- return;
-
- proc = (PROC *) MAKE_PTR(location);
-
- if (proc != MyProc) {
- Assert( pid != getpid() );
- } else
- MyProc = NULL;
-
- /* ---------------
- * Assume one lock table.
- * ---------------
- */
- ProcReleaseSpins(proc);
- LockReleaseAll(1,&proc->lockQueue);
-
+
+ ShmemPIDLookup(pid, &location);
+ if (location == INVALID_OFFSET)
+ return;
+
+ proc = (PROC *) MAKE_PTR(location);
+
+ if (proc != MyProc)
+ {
+ Assert(pid != getpid());
+ }
+ else
+ MyProc = NULL;
+
+ /* ---------------
+ * Assume one lock table.
+ * ---------------
+ */
+ ProcReleaseSpins(proc);
+ LockReleaseAll(1, &proc->lockQueue);
+
#ifdef USER_LOCKS
- LockReleaseAll(0,&proc->lockQueue);
+ LockReleaseAll(0, &proc->lockQueue);
#endif
- /* ----------------
- * get off the wait queue
- * ----------------
- */
- LockLockTable();
- if (proc->links.next != INVALID_OFFSET) {
- Assert(proc->waitLock->waitProcs.size > 0);
- SHMQueueDelete(&(proc->links));
- --proc->waitLock->waitProcs.size;
- }
- SHMQueueElemInit(&(proc->links));
- UnlockLockTable();
-
- return;
+ /* ----------------
+ * get off the wait queue
+ * ----------------
+ */
+ LockLockTable();
+ if (proc->links.next != INVALID_OFFSET)
+ {
+ Assert(proc->waitLock->waitProcs.size > 0);
+ SHMQueueDelete(&(proc->links));
+ --proc->waitLock->waitProcs.size;
+ }
+ SHMQueueElemInit(&(proc->links));
+ UnlockLockTable();
+
+ return;
}
/*
* ProcQueue package: routines for putting processes to sleep
- * and waking them up
+ * and waking them up
*/
/*
@@ -405,33 +417,34 @@ ProcKill(int exitStatus, int pid)
* Side Effects: Initializes the queue if we allocated one
*/
#ifdef NOT_USED
-PROC_QUEUE *
+PROC_QUEUE *
ProcQueueAlloc(char *name)
{
- bool found;
- PROC_QUEUE *queue = (PROC_QUEUE *)
- ShmemInitStruct(name,(unsigned)sizeof(PROC_QUEUE),&found);
-
- if (! queue)
+ bool found;
+ PROC_QUEUE *queue = (PROC_QUEUE *)
+ ShmemInitStruct(name, (unsigned) sizeof(PROC_QUEUE), &found);
+
+ if (!queue)
{
- return(NULL);
+ return (NULL);
}
- if (! found)
+ if (!found)
{
- ProcQueueInit(queue);
+ ProcQueueInit(queue);
}
- return(queue);
+ return (queue);
}
+
#endif
/*
* ProcQueueInit -- initialize a shared memory process queue
*/
void
-ProcQueueInit(PROC_QUEUE *queue)
+ProcQueueInit(PROC_QUEUE * queue)
{
- SHMQueueInit(&(queue->links));
- queue->size = 0;
+ SHMQueueInit(&(queue->links));
+ queue->size = 0;
}
@@ -444,124 +457,126 @@ ProcQueueInit(PROC_QUEUE *queue)
* to acquire it, we sleep.
*
* ASSUME: that no one will fiddle with the queue until after
- * we release the spin lock.
+ * we release the spin lock.
*
* NOTES: The process queue is now a priority queue for locking.
*/
int
-ProcSleep(PROC_QUEUE *queue,
- SPINLOCK spinlock,
- int token,
- int prio,
- LOCK *lock)
+ProcSleep(PROC_QUEUE * queue,
+ SPINLOCK spinlock,
+ int token,
+ int prio,
+ LOCK * lock)
{
- int i;
- PROC *proc;
- struct itimerval timeval, dummy;
-
- proc = (PROC *) MAKE_PTR(queue->links.prev);
- for (i=0;i<queue->size;i++)
+ int i;
+ PROC *proc;
+ struct itimerval timeval,
+ dummy;
+
+ proc = (PROC *) MAKE_PTR(queue->links.prev);
+ for (i = 0; i < queue->size; i++)
{
- if (proc->prio < prio)
- proc = (PROC *) MAKE_PTR(proc->links.prev);
- else
- break;
+ if (proc->prio < prio)
+ proc = (PROC *) MAKE_PTR(proc->links.prev);
+ else
+ break;
}
-
- MyProc->prio = prio;
- MyProc->token = token;
- MyProc->waitLock = lock;
-
- /* -------------------
- * currently, we only need this for the ProcWakeup routines
- * -------------------
- */
- TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
-
- /* -------------------
- * assume that these two operations are atomic (because
- * of the spinlock).
- * -------------------
- */
- SHMQueueInsertTL(&(proc->links),&(MyProc->links));
- queue->size++;
-
- SpinRelease(spinlock);
-
- /* --------------
- * Postgres does not have any deadlock detection code and for this
- * reason we must set a timer to wake up the process in the event of
- * a deadlock. For now the timer is set for 1 minute and we assume that
- * any process which sleeps for this amount of time is deadlocked and will
- * receive a SIGALRM signal. The handler should release the processes
- * semaphore and abort the current transaction.
- *
- * Need to zero out struct to set the interval and the micro seconds fields
- * to 0.
- * --------------
- */
- memset(&timeval, 0, sizeof(struct itimerval));
- timeval.it_value.tv_sec = DEADLOCK_TIMEOUT;
-
- if (setitimer(ITIMER_REAL, &timeval, &dummy))
- elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
-
- /* --------------
- * if someone wakes us between SpinRelease and IpcSemaphoreLock,
- * IpcSemaphoreLock will not block. The wakeup is "saved" by
- * the semaphore implementation.
- * --------------
- */
- IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
-
- /* ---------------
- * We were awoken before a timeout - now disable the timer
- * ---------------
- */
- timeval.it_value.tv_sec = 0;
-
-
- if (setitimer(ITIMER_REAL, &timeval, &dummy))
- elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
-
- /* ----------------
- * We were assumed to be in a critical section when we went
- * to sleep.
- * ----------------
- */
- SpinAcquire(spinlock);
-
- return(MyProc->errType);
+
+ MyProc->prio = prio;
+ MyProc->token = token;
+ MyProc->waitLock = lock;
+
+ /* -------------------
+ * currently, we only need this for the ProcWakeup routines
+ * -------------------
+ */
+ TransactionIdStore((TransactionId) GetCurrentTransactionId(), &MyProc->xid);
+
+ /* -------------------
+ * assume that these two operations are atomic (because
+ * of the spinlock).
+ * -------------------
+ */
+ SHMQueueInsertTL(&(proc->links), &(MyProc->links));
+ queue->size++;
+
+ SpinRelease(spinlock);
+
+ /* --------------
+ * Postgres does not have any deadlock detection code and for this
+ * reason we must set a timer to wake up the process in the event of
+ * a deadlock. For now the timer is set for 1 minute and we assume that
+ * any process which sleeps for this amount of time is deadlocked and will
+ * receive a SIGALRM signal. The handler should release the processes
+ * semaphore and abort the current transaction.
+ *
+ * Need to zero out struct to set the interval and the micro seconds fields
+ * to 0.
+ * --------------
+ */
+ memset(&timeval, 0, sizeof(struct itimerval));
+ timeval.it_value.tv_sec = DEADLOCK_TIMEOUT;
+
+ if (setitimer(ITIMER_REAL, &timeval, &dummy))
+ elog(FATAL, "ProcSleep: Unable to set timer for process wakeup");
+
+ /* --------------
+ * if someone wakes us between SpinRelease and IpcSemaphoreLock,
+ * IpcSemaphoreLock will not block. The wakeup is "saved" by
+ * the semaphore implementation.
+ * --------------
+ */
+ IpcSemaphoreLock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
+
+ /* ---------------
+ * We were awoken before a timeout - now disable the timer
+ * ---------------
+ */
+ timeval.it_value.tv_sec = 0;
+
+
+ if (setitimer(ITIMER_REAL, &timeval, &dummy))
+ elog(FATAL, "ProcSleep: Unable to diable timer for process wakeup");
+
+ /* ----------------
+ * We were assumed to be in a critical section when we went
+ * to sleep.
+ * ----------------
+ */
+ SpinAcquire(spinlock);
+
+ return (MyProc->errType);
}
/*
* ProcWakeup -- wake up a process by releasing its private semaphore.
*
- * remove the process from the wait queue and set its links invalid.
- * RETURN: the next process in the wait queue.
+ * remove the process from the wait queue and set its links invalid.
+ * RETURN: the next process in the wait queue.
*/
-static PROC *
-ProcWakeup(PROC *proc, int errType)
+static PROC *
+ProcWakeup(PROC * proc, int errType)
{
- PROC *retProc;
- /* assume that spinlock has been acquired */
-
- if (proc->links.prev == INVALID_OFFSET ||
- proc->links.next == INVALID_OFFSET)
- return((PROC *) NULL);
-
- retProc = (PROC *) MAKE_PTR(proc->links.prev);
-
- /* you have to update waitLock->waitProcs.size yourself */
- SHMQueueDelete(&(proc->links));
- SHMQueueElemInit(&(proc->links));
-
- proc->errType = errType;
-
- IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
-
- return retProc;
+ PROC *retProc;
+
+ /* assume that spinlock has been acquired */
+
+ if (proc->links.prev == INVALID_OFFSET ||
+ proc->links.next == INVALID_OFFSET)
+ return ((PROC *) NULL);
+
+ retProc = (PROC *) MAKE_PTR(proc->links.prev);
+
+ /* you have to update waitLock->waitProcs.size yourself */
+ SHMQueueDelete(&(proc->links));
+ SHMQueueElemInit(&(proc->links));
+
+ proc->errType = errType;
+
+ IpcSemaphoreUnlock(proc->sem.semId, proc->sem.semNum, IpcExclusiveLock);
+
+ return retProc;
}
@@ -572,61 +587,64 @@ ProcWakeup(PROC *proc, int errType)
int
ProcGetId()
{
- return( MyProc->procId );
+ return (MyProc->procId);
}
+
#endif
/*
* ProcLockWakeup -- routine for waking up processes when a lock is
- * released.
+ * released.
*/
int
-ProcLockWakeup(PROC_QUEUE *queue, char *ltable, char *lock)
+ProcLockWakeup(PROC_QUEUE * queue, char *ltable, char *lock)
{
- PROC *proc;
- int count;
-
- if (! queue->size)
- return(STATUS_NOT_FOUND);
-
- proc = (PROC *) MAKE_PTR(queue->links.prev);
- count = 0;
- while ((LockResolveConflicts ((LOCKTAB *) ltable,
- (LOCK *) lock,
- proc->token,
- proc->xid) == STATUS_OK))
+ PROC *proc;
+ int count;
+
+ if (!queue->size)
+ return (STATUS_NOT_FOUND);
+
+ proc = (PROC *) MAKE_PTR(queue->links.prev);
+ count = 0;
+ while ((LockResolveConflicts((LOCKTAB *) ltable,
+ (LOCK *) lock,
+ proc->token,
+ proc->xid) == STATUS_OK))
{
- /* there was a waiting process, grant it the lock before waking it
- * up. This will prevent another process from seizing the lock
- * between the time we release the lock master (spinlock) and
- * the time that the awoken process begins executing again.
- */
- GrantLock((LOCK *) lock, proc->token);
- queue->size--;
-
- /*
- * ProcWakeup removes proc from the lock waiting process queue and
- * returns the next proc in chain. If a writer just dropped
- * its lock and there are several waiting readers, wake them all up.
- */
- proc = ProcWakeup(proc, NO_ERROR);
-
- count++;
- if (!proc || queue->size == 0)
- break;
+
+ /*
+ * there was a waiting process, grant it the lock before waking it
+ * up. This will prevent another process from seizing the lock
+ * between the time we release the lock master (spinlock) and the
+ * time that the awoken process begins executing again.
+ */
+ GrantLock((LOCK *) lock, proc->token);
+ queue->size--;
+
+ /*
+ * ProcWakeup removes proc from the lock waiting process queue and
+ * returns the next proc in chain. If a writer just dropped its
+ * lock and there are several waiting readers, wake them all up.
+ */
+ proc = ProcWakeup(proc, NO_ERROR);
+
+ count++;
+ if (!proc || queue->size == 0)
+ break;
}
-
- if (count)
- return(STATUS_OK);
- else
- /* Something is still blocking us. May have deadlocked. */
- return(STATUS_NOT_FOUND);
+
+ if (count)
+ return (STATUS_OK);
+ else
+ /* Something is still blocking us. May have deadlocked. */
+ return (STATUS_NOT_FOUND);
}
void
-ProcAddLock(SHM_QUEUE *elem)
+ProcAddLock(SHM_QUEUE * elem)
{
- SHMQueueInsertTL(&MyProc->lockQueue,elem);
+ SHMQueueInsertTL(&MyProc->lockQueue, elem);
}
/* --------------------
@@ -634,194 +652,201 @@ ProcAddLock(SHM_QUEUE *elem)
* while waiting for a lock to be released by some other process. After
* the one minute deadline we assume we have a deadlock and must abort
* this transaction. We must also indicate that I'm no longer waiting
- * on a lock so that other processes don't try to wake me up and screw
+ * on a lock so that other processes don't try to wake me up and screw
* up my semaphore.
* --------------------
*/
static void
HandleDeadLock(int sig)
{
- LOCK *lock;
- int size;
-
- LockLockTable();
-
- /* ---------------------
- * Check to see if we've been awoken by anyone in the interim.
- *
- * If we have we can return and resume our transaction -- happy day.
- * Before we are awoken the process releasing the lock grants it to
- * us so we know that we don't have to wait anymore.
- *
- * Damn these names are LONG! -mer
- * ---------------------
- */
- if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
- IpcSemaphoreDefaultStartValue) {
- UnlockLockTable();
- return;
- }
-
- /*
- * you would think this would be unnecessary, but...
- *
- * this also means we've been removed already. in some ports
- * (e.g., sparc and aix) the semop(2) implementation is such that
- * we can actually end up in this handler after someone has removed
- * us from the queue and bopped the semaphore *but the test above
- * fails to detect the semaphore update* (presumably something weird
- * having to do with the order in which the semaphore wakeup signal
- * and SIGALRM get handled).
- */
- if (MyProc->links.prev == INVALID_OFFSET ||
- MyProc->links.next == INVALID_OFFSET) {
- UnlockLockTable();
- return;
- }
-
- lock = MyProc->waitLock;
- size = lock->waitProcs.size; /* so we can look at this in the core */
-
+ LOCK *lock;
+ int size;
+
+ LockLockTable();
+
+ /* ---------------------
+ * Check to see if we've been awoken by anyone in the interim.
+ *
+ * If we have we can return and resume our transaction -- happy day.
+ * Before we are awoken the process releasing the lock grants it to
+ * us so we know that we don't have to wait anymore.
+ *
+ * Damn these names are LONG! -mer
+ * ---------------------
+ */
+ if (IpcSemaphoreGetCount(MyProc->sem.semId, MyProc->sem.semNum) ==
+ IpcSemaphoreDefaultStartValue)
+ {
+ UnlockLockTable();
+ return;
+ }
+
+ /*
+ * you would think this would be unnecessary, but...
+ *
+ * this also means we've been removed already. in some ports (e.g.,
+ * sparc and aix) the semop(2) implementation is such that we can
+ * actually end up in this handler after someone has removed us from
+ * the queue and bopped the semaphore *but the test above fails to
+ * detect the semaphore update* (presumably something weird having to
+ * do with the order in which the semaphore wakeup signal and SIGALRM
+ * get handled).
+ */
+ if (MyProc->links.prev == INVALID_OFFSET ||
+ MyProc->links.next == INVALID_OFFSET)
+ {
+ UnlockLockTable();
+ return;
+ }
+
+ lock = MyProc->waitLock;
+ size = lock->waitProcs.size;/* so we can look at this in the core */
+
#ifdef DEADLOCK_DEBUG
- DumpLocks();
+ DumpLocks();
#endif
- /* ------------------------
- * Get this process off the lock's wait queue
- * ------------------------
- */
- Assert(lock->waitProcs.size > 0);
- --lock->waitProcs.size;
- SHMQueueDelete(&(MyProc->links));
- SHMQueueElemInit(&(MyProc->links));
-
- /* ------------------
- * Unlock my semaphore so that the count is right for next time.
- * I was awoken by a signal, not by someone unlocking my semaphore.
- * ------------------
- */
- IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
-
- /* -------------
- * Set MyProc->errType to STATUS_ERROR so that we abort after
- * returning from this handler.
- * -------------
- */
- MyProc->errType = STATUS_ERROR;
-
- /*
- * if this doesn't follow the IpcSemaphoreUnlock then we get lock
- * table corruption ("LockReplace: xid table corrupted") due to
- * race conditions. i don't claim to understand this...
- */
- UnlockLockTable();
-
- elog(NOTICE, "Timeout -- possible deadlock");
- return;
+ /* ------------------------
+ * Get this process off the lock's wait queue
+ * ------------------------
+ */
+ Assert(lock->waitProcs.size > 0);
+ --lock->waitProcs.size;
+ SHMQueueDelete(&(MyProc->links));
+ SHMQueueElemInit(&(MyProc->links));
+
+ /* ------------------
+ * Unlock my semaphore so that the count is right for next time.
+ * I was awoken by a signal, not by someone unlocking my semaphore.
+ * ------------------
+ */
+ IpcSemaphoreUnlock(MyProc->sem.semId, MyProc->sem.semNum, IpcExclusiveLock);
+
+ /* -------------
+ * Set MyProc->errType to STATUS_ERROR so that we abort after
+ * returning from this handler.
+ * -------------
+ */
+ MyProc->errType = STATUS_ERROR;
+
+ /*
+ * if this doesn't follow the IpcSemaphoreUnlock then we get lock
+ * table corruption ("LockReplace: xid table corrupted") due to race
+ * conditions. i don't claim to understand this...
+ */
+ UnlockLockTable();
+
+ elog(NOTICE, "Timeout -- possible deadlock");
+ return;
}
void
-ProcReleaseSpins(PROC *proc)
+ProcReleaseSpins(PROC * proc)
{
- int i;
-
- if (!proc)
- proc = MyProc;
-
- if (!proc)
- return;
- for (i=0; i < (int)MAX_SPINS; i++)
+ int i;
+
+ if (!proc)
+ proc = MyProc;
+
+ if (!proc)
+ return;
+ for (i = 0; i < (int) MAX_SPINS; i++)
{
- if (proc->sLocks[i])
+ if (proc->sLocks[i])
{
- Assert(proc->sLocks[i] == 1);
- SpinRelease(i);
+ Assert(proc->sLocks[i] == 1);
+ SpinRelease(i);
}
}
}
/*****************************************************************************
- *
+ *
*****************************************************************************/
/*
* ProcGetNewSemKeyAndNum -
- * scan the free semaphore bitmap and allocate a single semaphore from
- * a semaphore set. (If the semaphore set doesn't exist yet,
- * IpcSemaphoreCreate will create it. Otherwise, we use the existing
- * semaphore set.)
+ * scan the free semaphore bitmap and allocate a single semaphore from
+ * a semaphore set. (If the semaphore set doesn't exist yet,
+ * IpcSemaphoreCreate will create it. Otherwise, we use the existing
+ * semaphore set.)
*/
static void
-ProcGetNewSemKeyAndNum(IPCKey *key, int *semNum)
+ProcGetNewSemKeyAndNum(IPCKey * key, int *semNum)
{
- int i;
- int32 *freeSemMap = ProcGlobal->freeSemMap;
- unsigned int fullmask;
-
- /*
- * we hold ProcStructLock when entering this routine. We scan through
- * the bitmap to look for a free semaphore.
- */
- fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
- for(i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++) {
- int mask = 1;
- int j;
-
- if (freeSemMap[i] == fullmask)
- continue; /* none free for this set */
-
- for(j = 0; j < PROC_NSEMS_PER_SET; j++) {
- if ((freeSemMap[i] & mask) == 0) {
- /*
- * a free semaphore found. Mark it as allocated.
- */
- freeSemMap[i] |= mask;
+ int i;
+ int32 *freeSemMap = ProcGlobal->freeSemMap;
+ unsigned int fullmask;
- *key = ProcGlobal->currKey + i;
- *semNum = j;
- return;
- }
- mask <<= 1;
+ /*
+ * we hold ProcStructLock when entering this routine. We scan through
+ * the bitmap to look for a free semaphore.
+ */
+ fullmask = ~0 >> (32 - PROC_NSEMS_PER_SET);
+ for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+ {
+ int mask = 1;
+ int j;
+
+ if (freeSemMap[i] == fullmask)
+ continue; /* none free for this set */
+
+ for (j = 0; j < PROC_NSEMS_PER_SET; j++)
+ {
+ if ((freeSemMap[i] & mask) == 0)
+ {
+
+ /*
+ * a free semaphore found. Mark it as allocated.
+ */
+ freeSemMap[i] |= mask;
+
+ *key = ProcGlobal->currKey + i;
+ *semNum = j;
+ return;
+ }
+ mask <<= 1;
+ }
}
- }
- /* if we reach here, all the semaphores are in use. */
- elog(WARN, "InitProc: cannot allocate a free semaphore");
+ /* if we reach here, all the semaphores are in use. */
+ elog(WARN, "InitProc: cannot allocate a free semaphore");
}
/*
* ProcFreeSem -
- * free up our semaphore in the semaphore set. If we're the last one
- * in the set, also remove the semaphore set.
+ * free up our semaphore in the semaphore set. If we're the last one
+ * in the set, also remove the semaphore set.
*/
static void
ProcFreeSem(IpcSemaphoreKey semKey, int semNum)
{
- int mask;
- int i;
- int32 *freeSemMap = ProcGlobal->freeSemMap;
+ int mask;
+ int i;
+ int32 *freeSemMap = ProcGlobal->freeSemMap;
- i = semKey - ProcGlobal->currKey;
- mask = ~(1 << semNum);
- freeSemMap[i] &= mask;
+ i = semKey - ProcGlobal->currKey;
+ mask = ~(1 << semNum);
+ freeSemMap[i] &= mask;
- if (freeSemMap[i]==0)
- IpcSemaphoreKill(semKey);
+ if (freeSemMap[i] == 0)
+ IpcSemaphoreKill(semKey);
}
/*
* ProcFreeAllSemaphores -
- * on exiting the postmaster, we free up all the semaphores allocated
- * to the lmgrs of the backends.
+ * on exiting the postmaster, we free up all the semaphores allocated
+ * to the lmgrs of the backends.
*/
void
ProcFreeAllSemaphores()
{
- int i;
- int32 *freeSemMap = ProcGlobal->freeSemMap;
+ int i;
+ int32 *freeSemMap = ProcGlobal->freeSemMap;
- for(i=0; i < MAX_PROC_SEMS/PROC_NSEMS_PER_SET; i++) {
- if (freeSemMap[i]!=0)
- IpcSemaphoreKill(ProcGlobal->currKey + i);
- }
+ for (i = 0; i < MAX_PROC_SEMS / PROC_NSEMS_PER_SET; i++)
+ {
+ if (freeSemMap[i] != 0)
+ IpcSemaphoreKill(ProcGlobal->currKey + i);
+ }
}
diff --git a/src/backend/storage/lmgr/single.c b/src/backend/storage/lmgr/single.c
index 20feddbed9f..80220368437 100644
--- a/src/backend/storage/lmgr/single.c
+++ b/src/backend/storage/lmgr/single.c
@@ -1,19 +1,19 @@
/*-------------------------------------------------------------------------
*
* single.c--
- * set single locks in the multi-level lock hierarchy
+ * set single locks in the multi-level lock hierarchy
*
- * Sometimes we don't want to set all levels of the multi-level
- * lock hierarchy at once. This allows us to set and release
- * one level at a time. It's useful in index scans when
- * you can set an intent lock at the beginning and thereafter
- * only set page locks. Tends to speed things up.
+ * Sometimes we don't want to set all levels of the multi-level
+ * lock hierarchy at once. This allows us to set and release
+ * one level at a time. It's useful in index scans when
+ * you can set an intent lock at the beginning and thereafter
+ * only set page locks. Tends to speed things up.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Attic/single.c,v 1.2 1996/11/03 05:07:33 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Attic/single.c,v 1.3 1997/09/07 04:49:04 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,7 +21,7 @@
#include "postgres.h"
-#include "storage/lmgr.h" /* where the declarations go */
+#include "storage/lmgr.h" /* where the declarations go */
#include "storage/lock.h"
#include "storage/multilev.h"
#include "utils/rel.h"
@@ -34,28 +34,27 @@
bool
SingleLockReln(LockInfo linfo, LOCKT lockt, int action)
{
- LOCKTAG tag;
-
- /*
- * LOCKTAG has two bytes of padding, unfortunately. The
- * hash function will return miss if the padding bytes aren't
- * zero'd.
- */
- memset(&tag,0,sizeof(tag));
- tag.relId = linfo->lRelId.relId;
- tag.dbId = linfo->lRelId.dbId;
- BlockIdSet(&(tag.tupleId.ip_blkid), InvalidBlockNumber);
- tag.tupleId.ip_posid = InvalidOffsetNumber;
-
- if (action == UNLOCK)
- return(LockRelease(MultiTableId, &tag, lockt));
- else
- return(LockAcquire(MultiTableId, &tag, lockt));
+ LOCKTAG tag;
+
+ /*
+ * LOCKTAG has two bytes of padding, unfortunately. The hash function
+ * will return miss if the padding bytes aren't zero'd.
+ */
+ memset(&tag, 0, sizeof(tag));
+ tag.relId = linfo->lRelId.relId;
+ tag.dbId = linfo->lRelId.dbId;
+ BlockIdSet(&(tag.tupleId.ip_blkid), InvalidBlockNumber);
+ tag.tupleId.ip_posid = InvalidOffsetNumber;
+
+ if (action == UNLOCK)
+ return (LockRelease(MultiTableId, &tag, lockt));
+ else
+ return (LockAcquire(MultiTableId, &tag, lockt));
}
/*
* SingleLockPage -- use multi-level lock table, but lock
- * only at the page level.
+ * only at the page level.
*
* Assumes that an INTENT lock has already been set in the
* multi-level lock table.
@@ -63,27 +62,25 @@ SingleLockReln(LockInfo linfo, LOCKT lockt, int action)
*/
bool
SingleLockPage(LockInfo linfo,
- ItemPointer tidPtr,
- LOCKT lockt,
- int action)
+ ItemPointer tidPtr,
+ LOCKT lockt,
+ int action)
{
- LOCKTAG tag;
-
- /*
- * LOCKTAG has two bytes of padding, unfortunately. The
- * hash function will return miss if the padding bytes aren't
- * zero'd.
- */
- memset(&tag,0,sizeof(tag));
- tag.relId = linfo->lRelId.relId;
- tag.dbId = linfo->lRelId.dbId;
- BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid));
- tag.tupleId.ip_posid = InvalidOffsetNumber;
-
-
- if (action == UNLOCK)
- return(LockRelease(MultiTableId, &tag, lockt));
- else
- return(LockAcquire(MultiTableId, &tag, lockt));
-}
+ LOCKTAG tag;
+ /*
+ * LOCKTAG has two bytes of padding, unfortunately. The hash function
+ * will return miss if the padding bytes aren't zero'd.
+ */
+ memset(&tag, 0, sizeof(tag));
+ tag.relId = linfo->lRelId.relId;
+ tag.dbId = linfo->lRelId.dbId;
+ BlockIdCopy(&(tag.tupleId.ip_blkid), &(tidPtr->ip_blkid));
+ tag.tupleId.ip_posid = InvalidOffsetNumber;
+
+
+ if (action == UNLOCK)
+ return (LockRelease(MultiTableId, &tag, lockt));
+ else
+ return (LockAcquire(MultiTableId, &tag, lockt));
+}
diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c
index 98d1c59d5f0..75e1b5da9e7 100644
--- a/src/backend/storage/page/bufpage.c
+++ b/src/backend/storage/page/bufpage.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* bufpage.c--
- * POSTGRES standard buffer page code.
+ * POSTGRES standard buffer page code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.8 1997/08/24 23:07:30 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.9 1997/09/07 04:49:06 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,341 +26,368 @@
#include "lib/qsort.h"
-static void PageIndexTupleDeleteAdjustLinePointers(PageHeader phdr,
- char *location, Size size);
+static void
+PageIndexTupleDeleteAdjustLinePointers(PageHeader phdr,
+ char *location, Size size);
-static bool PageManagerShuffle = true; /* default is shuffle mode */
+static bool PageManagerShuffle = true; /* default is shuffle mode */
/* ----------------------------------------------------------------
- * Page support functions
+ * Page support functions
* ----------------------------------------------------------------
*/
/*
* PageInit --
- * Initializes the contents of a page.
+ * Initializes the contents of a page.
*/
void
PageInit(Page page, Size pageSize, Size specialSize)
{
- PageHeader p = (PageHeader) page;
-
- Assert(pageSize == BLCKSZ);
- Assert(pageSize >
- specialSize + sizeof(PageHeaderData) - sizeof(ItemIdData));
-
- specialSize = DOUBLEALIGN(specialSize);
-
- p->pd_lower = sizeof(PageHeaderData) - sizeof(ItemIdData);
- p->pd_upper = pageSize - specialSize;
- p->pd_special = pageSize - specialSize;
- PageSetPageSize(page, pageSize);
+ PageHeader p = (PageHeader) page;
+
+ Assert(pageSize == BLCKSZ);
+ Assert(pageSize >
+ specialSize + sizeof(PageHeaderData) - sizeof(ItemIdData));
+
+ specialSize = DOUBLEALIGN(specialSize);
+
+ p->pd_lower = sizeof(PageHeaderData) - sizeof(ItemIdData);
+ p->pd_upper = pageSize - specialSize;
+ p->pd_special = pageSize - specialSize;
+ PageSetPageSize(page, pageSize);
}
/*
* PageAddItem --
- * Adds item to the given page.
+ * Adds item to the given page.
*
* Note:
- * This does not assume that the item resides on a single page.
- * It is the responsiblity of the caller to act appropriately
- * depending on this fact. The "pskip" routines provide a
- * friendlier interface, in this case.
- *
- * This does change the status of any of the resources passed.
- * The semantics may change in the future.
+ * This does not assume that the item resides on a single page.
+ * It is the responsiblity of the caller to act appropriately
+ * depending on this fact. The "pskip" routines provide a
+ * friendlier interface, in this case.
+ *
+ * This does change the status of any of the resources passed.
+ * The semantics may change in the future.
*
- * This routine should probably be combined with others?
+ * This routine should probably be combined with others?
*/
/* ----------------
- * PageAddItem
+ * PageAddItem
*
- * add an item to a page.
+ * add an item to a page.
*
- * Notes on interface:
- * If offsetNumber is valid, shuffle ItemId's down to make room
- * to use it, if PageManagerShuffle is true. If PageManagerShuffle is
- * false, then overwrite the specified ItemId. (PageManagerShuffle is
- * true by default, and is modified by calling PageManagerModeSet.)
- * If offsetNumber is not valid, then assign one by finding the first
- * one that is both unused and deallocated.
+ * Notes on interface:
+ * If offsetNumber is valid, shuffle ItemId's down to make room
+ * to use it, if PageManagerShuffle is true. If PageManagerShuffle is
+ * false, then overwrite the specified ItemId. (PageManagerShuffle is
+ * true by default, and is modified by calling PageManagerModeSet.)
+ * If offsetNumber is not valid, then assign one by finding the first
+ * one that is both unused and deallocated.
*
- * NOTE: If offsetNumber is valid, and PageManagerShuffle is true, it
- * is assumed that there is room on the page to shuffle the ItemId's
- * down by one.
+ * NOTE: If offsetNumber is valid, and PageManagerShuffle is true, it
+ * is assumed that there is room on the page to shuffle the ItemId's
+ * down by one.
* ----------------
*/
OffsetNumber
PageAddItem(Page page,
- Item item,
- Size size,
- OffsetNumber offsetNumber,
- ItemIdFlags flags)
+ Item item,
+ Size size,
+ OffsetNumber offsetNumber,
+ ItemIdFlags flags)
{
- register i;
- Size alignedSize;
- Offset lower;
- Offset upper;
- ItemId itemId;
- ItemId fromitemId, toitemId;
- OffsetNumber limit;
-
- bool shuffled = false;
-
- /*
- * Find first unallocated offsetNumber
- */
- limit = OffsetNumberNext(PageGetMaxOffsetNumber(page));
-
- /* was offsetNumber passed in? */
- if (OffsetNumberIsValid(offsetNumber)) {
- if (PageManagerShuffle == true) {
- /* shuffle ItemId's (Do the PageManager Shuffle...) */
- for (i = (limit - 1); i >= offsetNumber; i--) {
- fromitemId = &((PageHeader)page)->pd_linp[i - 1];
- toitemId = &((PageHeader)page)->pd_linp[i];
- *toitemId = *fromitemId;
- }
- shuffled = true; /* need to increase "lower" */
- } else { /* overwrite mode */
- itemId = &((PageHeader)page)->pd_linp[offsetNumber - 1];
- if (((*itemId).lp_flags & LP_USED) ||
- ((*itemId).lp_len != 0)) {
- elog(WARN, "PageAddItem: tried overwrite of used ItemId");
- return (InvalidOffsetNumber);
- }
+ register i;
+ Size alignedSize;
+ Offset lower;
+ Offset upper;
+ ItemId itemId;
+ ItemId fromitemId,
+ toitemId;
+ OffsetNumber limit;
+
+ bool shuffled = false;
+
+ /*
+ * Find first unallocated offsetNumber
+ */
+ limit = OffsetNumberNext(PageGetMaxOffsetNumber(page));
+
+ /* was offsetNumber passed in? */
+ if (OffsetNumberIsValid(offsetNumber))
+ {
+ if (PageManagerShuffle == true)
+ {
+ /* shuffle ItemId's (Do the PageManager Shuffle...) */
+ for (i = (limit - 1); i >= offsetNumber; i--)
+ {
+ fromitemId = &((PageHeader) page)->pd_linp[i - 1];
+ toitemId = &((PageHeader) page)->pd_linp[i];
+ *toitemId = *fromitemId;
+ }
+ shuffled = true; /* need to increase "lower" */
+ }
+ else
+ { /* overwrite mode */
+ itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
+ if (((*itemId).lp_flags & LP_USED) ||
+ ((*itemId).lp_len != 0))
+ {
+ elog(WARN, "PageAddItem: tried overwrite of used ItemId");
+ return (InvalidOffsetNumber);
+ }
+ }
}
- } else { /* offsetNumber was not passed in, so find one */
- /* look for "recyclable" (unused & deallocated) ItemId */
- for (offsetNumber = 1; offsetNumber < limit; offsetNumber++) {
- itemId = &((PageHeader)page)->pd_linp[offsetNumber - 1];
- if ((((*itemId).lp_flags & LP_USED) == 0) &&
- ((*itemId).lp_len == 0))
- break;
+ else
+ { /* offsetNumber was not passed in, so find
+ * one */
+ /* look for "recyclable" (unused & deallocated) ItemId */
+ for (offsetNumber = 1; offsetNumber < limit; offsetNumber++)
+ {
+ itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
+ if ((((*itemId).lp_flags & LP_USED) == 0) &&
+ ((*itemId).lp_len == 0))
+ break;
+ }
}
- }
- if (offsetNumber > limit)
- lower = (Offset) (((char *) (&((PageHeader)page)->pd_linp[offsetNumber])) - ((char *) page));
- else if (offsetNumber == limit || shuffled == true)
- lower = ((PageHeader)page)->pd_lower + sizeof (ItemIdData);
- else
- lower = ((PageHeader)page)->pd_lower;
-
- alignedSize = DOUBLEALIGN(size);
-
- upper = ((PageHeader)page)->pd_upper - alignedSize;
-
- if (lower > upper) {
- return (InvalidOffsetNumber);
- }
-
- itemId = &((PageHeader)page)->pd_linp[offsetNumber - 1];
- (*itemId).lp_off = upper;
- (*itemId).lp_len = size;
- (*itemId).lp_flags = flags;
- memmove((char *)page + upper, item, size);
- ((PageHeader)page)->pd_lower = lower;
- ((PageHeader)page)->pd_upper = upper;
-
- return (offsetNumber);
+ if (offsetNumber > limit)
+ lower = (Offset) (((char *) (&((PageHeader) page)->pd_linp[offsetNumber])) - ((char *) page));
+ else if (offsetNumber == limit || shuffled == true)
+ lower = ((PageHeader) page)->pd_lower + sizeof(ItemIdData);
+ else
+ lower = ((PageHeader) page)->pd_lower;
+
+ alignedSize = DOUBLEALIGN(size);
+
+ upper = ((PageHeader) page)->pd_upper - alignedSize;
+
+ if (lower > upper)
+ {
+ return (InvalidOffsetNumber);
+ }
+
+ itemId = &((PageHeader) page)->pd_linp[offsetNumber - 1];
+ (*itemId).lp_off = upper;
+ (*itemId).lp_len = size;
+ (*itemId).lp_flags = flags;
+ memmove((char *) page + upper, item, size);
+ ((PageHeader) page)->pd_lower = lower;
+ ((PageHeader) page)->pd_upper = upper;
+
+ return (offsetNumber);
}
/*
* PageGetTempPage --
- * Get a temporary page in local memory for special processing
+ * Get a temporary page in local memory for special processing
*/
Page
PageGetTempPage(Page page, Size specialSize)
{
- Size pageSize;
- Size size;
- Page temp;
- PageHeader thdr;
-
- pageSize = PageGetPageSize(page);
-
- if ((temp = (Page) palloc(pageSize)) == (Page) NULL)
- elog(FATAL, "Cannot allocate %d bytes for temp page.", pageSize);
- thdr = (PageHeader) temp;
-
- /* copy old page in */
- memmove(temp, page, pageSize);
-
- /* clear out the middle */
- size = (pageSize - sizeof(PageHeaderData)) + sizeof(ItemIdData);
- size -= DOUBLEALIGN(specialSize);
- memset((char *) &(thdr->pd_linp[0]), 0, size);
-
- /* set high, low water marks */
- thdr->pd_lower = sizeof (PageHeaderData) - sizeof (ItemIdData);
- thdr->pd_upper = pageSize - DOUBLEALIGN(specialSize);
-
- return (temp);
+ Size pageSize;
+ Size size;
+ Page temp;
+ PageHeader thdr;
+
+ pageSize = PageGetPageSize(page);
+
+ if ((temp = (Page) palloc(pageSize)) == (Page) NULL)
+ elog(FATAL, "Cannot allocate %d bytes for temp page.", pageSize);
+ thdr = (PageHeader) temp;
+
+ /* copy old page in */
+ memmove(temp, page, pageSize);
+
+ /* clear out the middle */
+ size = (pageSize - sizeof(PageHeaderData)) + sizeof(ItemIdData);
+ size -= DOUBLEALIGN(specialSize);
+ memset((char *) &(thdr->pd_linp[0]), 0, size);
+
+ /* set high, low water marks */
+ thdr->pd_lower = sizeof(PageHeaderData) - sizeof(ItemIdData);
+ thdr->pd_upper = pageSize - DOUBLEALIGN(specialSize);
+
+ return (temp);
}
/*
* PageRestoreTempPage --
- * Copy temporary page back to permanent page after special processing
- * and release the temporary page.
+ * Copy temporary page back to permanent page after special processing
+ * and release the temporary page.
*/
void
PageRestoreTempPage(Page tempPage, Page oldPage)
{
- Size pageSize;
-
- pageSize = PageGetPageSize(tempPage);
- memmove((char *) oldPage, (char *) tempPage, pageSize);
-
- pfree(tempPage);
+ Size pageSize;
+
+ pageSize = PageGetPageSize(tempPage);
+ memmove((char *) oldPage, (char *) tempPage, pageSize);
+
+ pfree(tempPage);
}
/*
* PageGetMaxOffsetNumber --
- * Returns the maximum offset number used by the given page.
+ * Returns the maximum offset number used by the given page.
*
- * NOTE: The offset is invalid if the page is non-empty.
- * Test whether PageIsEmpty before calling this routine
- * and/or using its return value.
+ * NOTE: The offset is invalid if the page is non-empty.
+ * Test whether PageIsEmpty before calling this routine
+ * and/or using its return value.
*/
OffsetNumber
PageGetMaxOffsetNumber(Page page)
{
- LocationIndex low;
- OffsetNumber i;
-
- low = ((PageHeader) page)->pd_lower;
- i = (low - (sizeof(PageHeaderData) - sizeof(ItemIdData)))
- / sizeof(ItemIdData);
-
- return(i);
-}
+ LocationIndex low;
+ OffsetNumber i;
+
+ low = ((PageHeader) page)->pd_lower;
+ i = (low - (sizeof(PageHeaderData) - sizeof(ItemIdData)))
+ / sizeof(ItemIdData);
+
+ return (i);
+}
/* ----------------
- * itemid stuff for PageRepairFragmentation
+ * itemid stuff for PageRepairFragmentation
* ----------------
*/
-struct itemIdSortData {
- int offsetindex; /* linp array index */
- ItemIdData itemiddata;
+struct itemIdSortData
+{
+ int offsetindex;/* linp array index */
+ ItemIdData itemiddata;
};
static int
itemidcompare(void *itemidp1, void *itemidp2)
{
- if (((struct itemIdSortData *)itemidp1)->itemiddata.lp_off ==
- ((struct itemIdSortData *)itemidp2)->itemiddata.lp_off)
- return(0);
- else if (((struct itemIdSortData *)itemidp1)->itemiddata.lp_off <
- ((struct itemIdSortData *)itemidp2)->itemiddata.lp_off)
- return(1);
- else
- return(-1);
+ if (((struct itemIdSortData *) itemidp1)->itemiddata.lp_off ==
+ ((struct itemIdSortData *) itemidp2)->itemiddata.lp_off)
+ return (0);
+ else if (((struct itemIdSortData *) itemidp1)->itemiddata.lp_off <
+ ((struct itemIdSortData *) itemidp2)->itemiddata.lp_off)
+ return (1);
+ else
+ return (-1);
}
/*
* PageRepairFragmentation --
- * Frees fragmented space on a page.
+ * Frees fragmented space on a page.
*/
void
PageRepairFragmentation(Page page)
{
- int i;
- struct itemIdSortData *itemidbase, *itemidptr;
- ItemId lp;
- int nline, nused;
- Offset upper;
- Size alignedSize;
-
- nline = (int16) PageGetMaxOffsetNumber(page);
- nused = 0;
- for (i=0; i<nline; i++) {
- lp = ((PageHeader)page)->pd_linp + i;
- if ((*lp).lp_flags & LP_USED)
- nused++;
- }
-
- if (nused == 0) {
- for (i=0; i<nline; i++) {
- lp = ((PageHeader)page)->pd_linp + i;
- if ((*lp).lp_len > 0) /* unused, but allocated */
- (*lp).lp_len = 0; /* indicate unused & deallocated */
+ int i;
+ struct itemIdSortData *itemidbase,
+ *itemidptr;
+ ItemId lp;
+ int nline,
+ nused;
+ Offset upper;
+ Size alignedSize;
+
+ nline = (int16) PageGetMaxOffsetNumber(page);
+ nused = 0;
+ for (i = 0; i < nline; i++)
+ {
+ lp = ((PageHeader) page)->pd_linp + i;
+ if ((*lp).lp_flags & LP_USED)
+ nused++;
}
-
- ((PageHeader)page)->pd_upper = ((PageHeader)page)->pd_special;
- } else { /* nused != 0 */
- itemidbase = (struct itemIdSortData *)
- palloc(sizeof(struct itemIdSortData) * nused);
- memset((char *) itemidbase, 0, sizeof(struct itemIdSortData) * nused);
- itemidptr = itemidbase;
- for (i=0; i<nline; i++) {
- lp = ((PageHeader)page)->pd_linp + i;
- if ((*lp).lp_flags & LP_USED) {
- itemidptr->offsetindex = i;
- itemidptr->itemiddata = *lp;
- itemidptr++;
- } else {
- if ((*lp).lp_len > 0) /* unused, but allocated */
- (*lp).lp_len = 0; /* indicate unused & deallocated */
- }
+
+ if (nused == 0)
+ {
+ for (i = 0; i < nline; i++)
+ {
+ lp = ((PageHeader) page)->pd_linp + i;
+ if ((*lp).lp_len > 0) /* unused, but allocated */
+ (*lp).lp_len = 0; /* indicate unused & deallocated */
+ }
+
+ ((PageHeader) page)->pd_upper = ((PageHeader) page)->pd_special;
}
-
- /* sort itemIdSortData array...*/
- pg_qsort((char *) itemidbase, nused, sizeof(struct itemIdSortData),
- itemidcompare);
-
- /* compactify page */
- ((PageHeader)page)->pd_upper = ((PageHeader)page)->pd_special;
-
- for (i=0, itemidptr = itemidbase; i<nused; i++, itemidptr++) {
- lp = ((PageHeader)page)->pd_linp + itemidptr->offsetindex;
- alignedSize = DOUBLEALIGN((*lp).lp_len);
- upper = ((PageHeader)page)->pd_upper - alignedSize;
- memmove((char *) page + upper,
- (char *)page + (*lp).lp_off,
- (*lp).lp_len);
- (*lp).lp_off = upper;
- ((PageHeader)page)->pd_upper = upper;
+ else
+ { /* nused != 0 */
+ itemidbase = (struct itemIdSortData *)
+ palloc(sizeof(struct itemIdSortData) * nused);
+ memset((char *) itemidbase, 0, sizeof(struct itemIdSortData) * nused);
+ itemidptr = itemidbase;
+ for (i = 0; i < nline; i++)
+ {
+ lp = ((PageHeader) page)->pd_linp + i;
+ if ((*lp).lp_flags & LP_USED)
+ {
+ itemidptr->offsetindex = i;
+ itemidptr->itemiddata = *lp;
+ itemidptr++;
+ }
+ else
+ {
+ if ((*lp).lp_len > 0) /* unused, but allocated */
+ (*lp).lp_len = 0; /* indicate unused & deallocated */
+ }
+ }
+
+ /* sort itemIdSortData array... */
+ pg_qsort((char *) itemidbase, nused, sizeof(struct itemIdSortData),
+ itemidcompare);
+
+ /* compactify page */
+ ((PageHeader) page)->pd_upper = ((PageHeader) page)->pd_special;
+
+ for (i = 0, itemidptr = itemidbase; i < nused; i++, itemidptr++)
+ {
+ lp = ((PageHeader) page)->pd_linp + itemidptr->offsetindex;
+ alignedSize = DOUBLEALIGN((*lp).lp_len);
+ upper = ((PageHeader) page)->pd_upper - alignedSize;
+ memmove((char *) page + upper,
+ (char *) page + (*lp).lp_off,
+ (*lp).lp_len);
+ (*lp).lp_off = upper;
+ ((PageHeader) page)->pd_upper = upper;
+ }
+
+ pfree(itemidbase);
}
-
- pfree(itemidbase);
- }
}
/*
* PageGetFreeSpace --
- * Returns the size of the free (allocatable) space on a page.
+ * Returns the size of the free (allocatable) space on a page.
*/
Size
PageGetFreeSpace(Page page)
{
- Size space;
-
-
- space = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
-
- if (space < sizeof (ItemIdData)) {
- return (0);
- }
- space -= sizeof (ItemIdData); /* XXX not always true */
-
- return (space);
+ Size space;
+
+
+ space = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
+
+ if (space < sizeof(ItemIdData))
+ {
+ return (0);
+ }
+ space -= sizeof(ItemIdData);/* XXX not always true */
+
+ return (space);
}
/*
* PageManagerModeSet --
*
- * Sets mode to either: ShufflePageManagerMode (the default) or
- * OverwritePageManagerMode. For use by access methods code
- * for determining semantics of PageAddItem when the offsetNumber
- * argument is passed in.
+ * Sets mode to either: ShufflePageManagerMode (the default) or
+ * OverwritePageManagerMode. For use by access methods code
+ * for determining semantics of PageAddItem when the offsetNumber
+ * argument is passed in.
*/
void
PageManagerModeSet(PageManagerMode mode)
{
- if (mode == ShufflePageManagerMode)
- PageManagerShuffle = true;
- else if (mode == OverwritePageManagerMode)
- PageManagerShuffle = false;
+ if (mode == ShufflePageManagerMode)
+ PageManagerShuffle = true;
+ else if (mode == OverwritePageManagerMode)
+ PageManagerShuffle = false;
}
/*
@@ -368,65 +395,64 @@ PageManagerModeSet(PageManagerMode mode)
* PageIndexTupleDelete
*----------------------------------------------------------------
*
- * This routine does the work of removing a tuple from an index page.
+ * This routine does the work of removing a tuple from an index page.
*/
void
PageIndexTupleDelete(Page page, OffsetNumber offnum)
{
- PageHeader phdr;
- char *addr;
- ItemId tup;
- Size size;
- char *locn;
- int nbytes;
- int offidx;
-
- phdr = (PageHeader) page;
-
- /* change offset number to offset index */
- offidx = offnum - 1;
-
- tup = PageGetItemId(page, offnum);
- size = ItemIdGetLength(tup);
- size = DOUBLEALIGN(size);
-
- /* location of deleted tuple data */
- locn = (char *) (page + ItemIdGetOffset(tup));
-
- /*
- * First, we want to get rid of the pd_linp entry for the index
- * tuple. We copy all subsequent linp's back one slot in the
- * array.
- */
-
- nbytes = phdr->pd_lower -
- ((char *)&phdr->pd_linp[offidx + 1] - (char *) phdr);
- memmove((char *) &(phdr->pd_linp[offidx]),
- (char *) &(phdr->pd_linp[offidx + 1]),
- nbytes);
-
- /*
- * Now move everything between the old upper bound (beginning of tuple
- * space) and the beginning of the deleted tuple forward, so that
- * space in the middle of the page is left free. If we've just deleted
- * the tuple at the beginning of tuple space, then there's no need
- * to do the copy (and bcopy on some architectures SEGV's if asked
- * to move zero bytes).
- */
-
- /* beginning of tuple space */
- addr = (char *) (page + phdr->pd_upper);
-
- if (locn != addr)
- memmove(addr + size, addr, (int) (locn - addr));
-
- /* adjust free space boundary pointers */
- phdr->pd_upper += size;
- phdr->pd_lower -= sizeof (ItemIdData);
-
- /* finally, we need to adjust the linp entries that remain */
- if (!PageIsEmpty(page))
- PageIndexTupleDeleteAdjustLinePointers(phdr, locn, size);
+ PageHeader phdr;
+ char *addr;
+ ItemId tup;
+ Size size;
+ char *locn;
+ int nbytes;
+ int offidx;
+
+ phdr = (PageHeader) page;
+
+ /* change offset number to offset index */
+ offidx = offnum - 1;
+
+ tup = PageGetItemId(page, offnum);
+ size = ItemIdGetLength(tup);
+ size = DOUBLEALIGN(size);
+
+ /* location of deleted tuple data */
+ locn = (char *) (page + ItemIdGetOffset(tup));
+
+ /*
+ * First, we want to get rid of the pd_linp entry for the index tuple.
+ * We copy all subsequent linp's back one slot in the array.
+ */
+
+ nbytes = phdr->pd_lower -
+ ((char *) &phdr->pd_linp[offidx + 1] - (char *) phdr);
+ memmove((char *) &(phdr->pd_linp[offidx]),
+ (char *) &(phdr->pd_linp[offidx + 1]),
+ nbytes);
+
+ /*
+ * Now move everything between the old upper bound (beginning of tuple
+ * space) and the beginning of the deleted tuple forward, so that
+ * space in the middle of the page is left free. If we've just
+ * deleted the tuple at the beginning of tuple space, then there's no
+ * need to do the copy (and bcopy on some architectures SEGV's if
+ * asked to move zero bytes).
+ */
+
+ /* beginning of tuple space */
+ addr = (char *) (page + phdr->pd_upper);
+
+ if (locn != addr)
+ memmove(addr + size, addr, (int) (locn - addr));
+
+ /* adjust free space boundary pointers */
+ phdr->pd_upper += size;
+ phdr->pd_lower -= sizeof(ItemIdData);
+
+ /* finally, we need to adjust the linp entries that remain */
+ if (!PageIsEmpty(page))
+ PageIndexTupleDeleteAdjustLinePointers(phdr, locn, size);
}
/*
@@ -434,33 +460,35 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum)
* PageIndexTupleDeleteAdjustLinePointers
*----------------------------------------------------------------
*
- * Once the line pointers and tuple data have been shifted around
- * on the page, we need to go down the line pointer vector and
- * adjust pointers to reflect new locations. Anything that used
- * to be before the deleted tuple's data was moved forward by the
- * size of the deleted tuple.
+ * Once the line pointers and tuple data have been shifted around
+ * on the page, we need to go down the line pointer vector and
+ * adjust pointers to reflect new locations. Anything that used
+ * to be before the deleted tuple's data was moved forward by the
+ * size of the deleted tuple.
*
- * This routine does the work of adjusting the line pointers.
- * Location is where the tuple data used to lie; size is how
- * much space it occupied. We assume that size has been aligned
- * as required by the time we get here.
+ * This routine does the work of adjusting the line pointers.
+ * Location is where the tuple data used to lie; size is how
+ * much space it occupied. We assume that size has been aligned
+ * as required by the time we get here.
*
- * This routine should never be called on an empty page.
+ * This routine should never be called on an empty page.
*/
static void
PageIndexTupleDeleteAdjustLinePointers(PageHeader phdr,
- char *location,
- Size size)
+ char *location,
+ Size size)
{
- int i;
- unsigned offset;
-
- /* location is an index into the page... */
- offset = (unsigned)(location - (char *)phdr);
-
- for (i = PageGetMaxOffsetNumber((Page) phdr) - 1; i >= 0; i--) {
- if (phdr->pd_linp[i].lp_off <= offset) {
- phdr->pd_linp[i].lp_off += size;
+ int i;
+ unsigned offset;
+
+ /* location is an index into the page... */
+ offset = (unsigned) (location - (char *) phdr);
+
+ for (i = PageGetMaxOffsetNumber((Page) phdr) - 1; i >= 0; i--)
+ {
+ if (phdr->pd_linp[i].lp_off <= offset)
+ {
+ phdr->pd_linp[i].lp_off += size;
+ }
}
- }
}
diff --git a/src/backend/storage/page/itemptr.c b/src/backend/storage/page/itemptr.c
index 608fbf03379..25daebab23c 100644
--- a/src/backend/storage/page/itemptr.c
+++ b/src/backend/storage/page/itemptr.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* itemptr.c--
- * POSTGRES disk item pointer code.
+ * POSTGRES disk item pointer code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/page/itemptr.c,v 1.2 1996/11/03 05:07:46 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/page/itemptr.c,v 1.3 1997/09/07 04:49:07 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,21 +20,20 @@
/*
* ItemPointerEquals --
- * Returns true if both item pointers point to the same item,
- * otherwise returns false.
+ * Returns true if both item pointers point to the same item,
+ * otherwise returns false.
*
* Note:
- * Assumes that the disk item pointers are not NULL.
+ * Assumes that the disk item pointers are not NULL.
*/
bool
ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2)
{
- if (ItemPointerGetBlockNumber(pointer1) ==
- ItemPointerGetBlockNumber(pointer2) &&
- ItemPointerGetOffsetNumber(pointer1) ==
- ItemPointerGetOffsetNumber(pointer2))
- return(true);
- else
- return(false);
+ if (ItemPointerGetBlockNumber(pointer1) ==
+ ItemPointerGetBlockNumber(pointer2) &&
+ ItemPointerGetOffsetNumber(pointer1) ==
+ ItemPointerGetOffsetNumber(pointer2))
+ return (true);
+ else
+ return (false);
}
-
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 2688ad3aed1..7a2903fff5c 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -1,28 +1,28 @@
/*-------------------------------------------------------------------------
*
* md.c--
- * This code manages relations that reside on magnetic disk.
+ * This code manages relations that reside on magnetic disk.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.18 1997/08/18 20:53:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/md.c,v 1.19 1997/09/07 04:49:17 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <unistd.h>
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
-#include <fcntl.h> /* for open() flags */
+#include <fcntl.h> /* for open() flags */
#include <sys/file.h>
#include "postgres.h"
-#include "miscadmin.h" /* for DataDir */
+#include "miscadmin.h" /* for DataDir */
#include "storage/block.h"
#include "storage/fd.h"
-#include "storage/smgr.h" /* where the declarations go */
+#include "storage/smgr.h" /* where the declarations go */
#include "storage/fd.h"
#include "utils/mcxt.h"
#include "utils/rel.h"
@@ -32,764 +32,802 @@
#undef DIAGNOSTIC
/*
- * The magnetic disk storage manager keeps track of open file descriptors
- * in its own descriptor pool. This happens for two reasons. First, at
- * transaction boundaries, we walk the list of descriptors and flush
- * anything that we've dirtied in the current transaction. Second, we
- * have to support relations of > 4GBytes. In order to do this, we break
- * relations up into chunks of < 2GBytes and store one chunk in each of
- * several files that represent the relation.
+ * The magnetic disk storage manager keeps track of open file descriptors
+ * in its own descriptor pool. This happens for two reasons. First, at
+ * transaction boundaries, we walk the list of descriptors and flush
+ * anything that we've dirtied in the current transaction. Second, we
+ * have to support relations of > 4GBytes. In order to do this, we break
+ * relations up into chunks of < 2GBytes and store one chunk in each of
+ * several files that represent the relation.
*/
-typedef struct _MdfdVec {
- int mdfd_vfd; /* fd number in vfd pool */
- uint16 mdfd_flags; /* clean, dirty, free */
- int mdfd_lstbcnt; /* most recent block count */
- int mdfd_nextFree; /* next free vector */
- struct _MdfdVec *mdfd_chain; /* for large relations */
-} MdfdVec;
+typedef struct _MdfdVec
+{
+ int mdfd_vfd; /* fd number in vfd pool */
+ uint16 mdfd_flags; /* clean, dirty, free */
+ int mdfd_lstbcnt; /* most recent block count */
+ int mdfd_nextFree; /* next free vector */
+ struct _MdfdVec *mdfd_chain;/* for large relations */
+} MdfdVec;
-static int Nfds = 100;
-static MdfdVec *Md_fdvec = (MdfdVec *) NULL;
-static int Md_Free = -1;
-static int CurFd = 0;
-static MemoryContext MdCxt;
+static int Nfds = 100;
+static MdfdVec *Md_fdvec = (MdfdVec *) NULL;
+static int Md_Free = -1;
+static int CurFd = 0;
+static MemoryContext MdCxt;
-#define MDFD_DIRTY (uint16) 0x01
-#define MDFD_FREE (uint16) 0x02
+#define MDFD_DIRTY (uint16) 0x01
+#define MDFD_FREE (uint16) 0x02
-#define RELSEG_SIZE 262144 /* (2 ** 31) / 8192 -- 2GB file */
+#define RELSEG_SIZE 262144 /* (2 ** 31) / 8192 -- 2GB file */
/* routines declared here */
-static MdfdVec *_mdfd_openseg(Relation reln, int segno, int oflags);
-static MdfdVec *_mdfd_getseg(Relation reln, int blkno, int oflag);
-static int _fdvec_alloc (void);
-static void _fdvec_free (int);
+static MdfdVec *_mdfd_openseg(Relation reln, int segno, int oflags);
+static MdfdVec *_mdfd_getseg(Relation reln, int blkno, int oflag);
+static int _fdvec_alloc(void);
+static void _fdvec_free(int);
static BlockNumber _mdnblocks(File file, Size blcksz);
/*
- * mdinit() -- Initialize private state for magnetic disk storage manager.
+ * mdinit() -- Initialize private state for magnetic disk storage manager.
*
- * We keep a private table of all file descriptors. Whenever we do
- * a write to one, we mark it dirty in our table. Whenever we force
- * changes to disk, we mark the file descriptor clean. At transaction
- * commit, we force changes to disk for all dirty file descriptors.
- * This routine allocates and initializes the table.
+ * We keep a private table of all file descriptors. Whenever we do
+ * a write to one, we mark it dirty in our table. Whenever we force
+ * changes to disk, we mark the file descriptor clean. At transaction
+ * commit, we force changes to disk for all dirty file descriptors.
+ * This routine allocates and initializes the table.
*
- * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
+ * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
*/
int
mdinit()
{
- MemoryContext oldcxt;
- int i;
+ MemoryContext oldcxt;
+ int i;
- MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
- if (MdCxt == (MemoryContext) NULL)
- return (SM_FAIL);
+ MdCxt = (MemoryContext) CreateGlobalMemory("MdSmgr");
+ if (MdCxt == (MemoryContext) NULL)
+ return (SM_FAIL);
- oldcxt = MemoryContextSwitchTo(MdCxt);
- Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
- MemoryContextSwitchTo(oldcxt);
+ oldcxt = MemoryContextSwitchTo(MdCxt);
+ Md_fdvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
+ MemoryContextSwitchTo(oldcxt);
- if (Md_fdvec == (MdfdVec *) NULL)
- return (SM_FAIL);
+ if (Md_fdvec == (MdfdVec *) NULL)
+ return (SM_FAIL);
- memset(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
+ memset(Md_fdvec, 0, Nfds * sizeof(MdfdVec));
- /* Set free list */
- for (i = 0; i < Nfds; i++ )
- {
- Md_fdvec[i].mdfd_nextFree = i + 1;
- Md_fdvec[i].mdfd_flags = MDFD_FREE;
- }
- Md_Free = 0;
- Md_fdvec[Nfds - 1].mdfd_nextFree = -1;
+ /* Set free list */
+ for (i = 0; i < Nfds; i++)
+ {
+ Md_fdvec[i].mdfd_nextFree = i + 1;
+ Md_fdvec[i].mdfd_flags = MDFD_FREE;
+ }
+ Md_Free = 0;
+ Md_fdvec[Nfds - 1].mdfd_nextFree = -1;
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
int
mdcreate(Relation reln)
{
- int fd, vfd;
- char *path;
-
- path = relpath(&(reln->rd_rel->relname.data[0]));
- fd = FileNameOpenFile(path, O_RDWR|O_CREAT|O_EXCL, 0600);
-
- /*
- * If the file already exists and is empty, we pretend that the
- * create succeeded. During bootstrap processing, we skip that check,
- * because pg_time, pg_variable, and pg_log get created before their
- * .bki file entries are processed.
- *
- * As the result of this pretence it was possible to have in
- * pg_class > 1 records with the same relname. Actually, it
- * should be fixed in upper levels, too, but... - vadim 05/06/97
- */
-
- if (fd < 0)
- {
- if ( !IsBootstrapProcessingMode() )
- return (-1);
- fd = FileNameOpenFile(path, O_RDWR, 0600); /* Bootstrap */
- if ( fd < 0 )
- return (-1);
- }
-
- vfd = _fdvec_alloc ();
- if ( vfd < 0 )
- return (-1);
-
- Md_fdvec[vfd].mdfd_vfd = fd;
- Md_fdvec[vfd].mdfd_flags = (uint16) 0;
- Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
- Md_fdvec[vfd].mdfd_lstbcnt = 0;
-
- return (vfd);
+ int fd,
+ vfd;
+ char *path;
+
+ path = relpath(&(reln->rd_rel->relname.data[0]));
+ fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL, 0600);
+
+ /*
+ * If the file already exists and is empty, we pretend that the create
+ * succeeded. During bootstrap processing, we skip that check,
+ * because pg_time, pg_variable, and pg_log get created before their
+ * .bki file entries are processed.
+ *
+ * As the result of this pretence it was possible to have in pg_class > 1
+ * records with the same relname. Actually, it should be fixed in
+ * upper levels, too, but... - vadim 05/06/97
+ */
+
+ if (fd < 0)
+ {
+ if (!IsBootstrapProcessingMode())
+ return (-1);
+ fd = FileNameOpenFile(path, O_RDWR, 0600); /* Bootstrap */
+ if (fd < 0)
+ return (-1);
+ }
+
+ vfd = _fdvec_alloc();
+ if (vfd < 0)
+ return (-1);
+
+ Md_fdvec[vfd].mdfd_vfd = fd;
+ Md_fdvec[vfd].mdfd_flags = (uint16) 0;
+ Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
+ Md_fdvec[vfd].mdfd_lstbcnt = 0;
+
+ return (vfd);
}
/*
- * mdunlink() -- Unlink a relation.
+ * mdunlink() -- Unlink a relation.
*/
int
mdunlink(Relation reln)
{
- int fd;
- int i;
- MdfdVec *v, *ov;
- MemoryContext oldcxt;
- char fname[NAMEDATALEN];
- char tname[NAMEDATALEN+10]; /* leave room for overflow suffixes*/
-
- /* On Windows NT you can't unlink a file if it is open so we have
- ** to do this.
- */
+ int fd;
+ int i;
+ MdfdVec *v,
+ *ov;
+ MemoryContext oldcxt;
+ char fname[NAMEDATALEN];
+ char tname[NAMEDATALEN + 10]; /* leave room for overflow
+ * suffixes */
+
+ /*
+ * On Windows NT you can't unlink a file if it is open so we have * to
+ * do this.
+ */
+
+ strNcpy(fname, RelationGetRelationName(reln)->data, NAMEDATALEN - 1);
+
+ if (FileNameUnlink(fname) < 0)
+ return (SM_FAIL);
+
+ /* unlink all the overflow files for large relations */
+ for (i = 1;; i++)
+ {
+ sprintf(tname, "%s.%d", fname, i);
+ if (FileNameUnlink(tname) < 0)
+ break;
+ }
+
+ /* finally, clean out the mdfd vector */
+ fd = RelationGetFile(reln);
+ Md_fdvec[fd].mdfd_flags = (uint16) 0;
+
+ oldcxt = MemoryContextSwitchTo(MdCxt);
+ for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
+ {
+ FileUnlink(v->mdfd_vfd);
+ ov = v;
+ v = v->mdfd_chain;
+ if (ov != &Md_fdvec[fd])
+ pfree(ov);
+ }
+ Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
+ MemoryContextSwitchTo(oldcxt);
- strNcpy(fname, RelationGetRelationName(reln)->data, NAMEDATALEN-1);
-
- if (FileNameUnlink(fname) < 0)
- return (SM_FAIL);
-
- /* unlink all the overflow files for large relations */
- for (i = 1; ; i++) {
- sprintf(tname, "%s.%d", fname, i);
- if (FileNameUnlink(tname) < 0)
- break;
- }
-
- /* finally, clean out the mdfd vector */
- fd = RelationGetFile(reln);
- Md_fdvec[fd].mdfd_flags = (uint16) 0;
-
- oldcxt = MemoryContextSwitchTo(MdCxt);
- for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL; )
- {
- FileUnlink(v->mdfd_vfd);
- ov = v;
- v = v->mdfd_chain;
- if (ov != &Md_fdvec[fd])
- pfree(ov);
- }
- Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
- MemoryContextSwitchTo(oldcxt);
-
- _fdvec_free (fd);
-
- return (SM_SUCCESS);
+ _fdvec_free(fd);
+
+ return (SM_SUCCESS);
}
/*
- * mdextend() -- Add a block to the specified relation.
+ * mdextend() -- Add a block to the specified relation.
*
- * This routine returns SM_FAIL or SM_SUCCESS, with errno set as
- * appropriate.
+ * This routine returns SM_FAIL or SM_SUCCESS, with errno set as
+ * appropriate.
*/
int
mdextend(Relation reln, char *buffer)
{
- long pos;
- int nblocks;
- MdfdVec *v;
+ long pos;
+ int nblocks;
+ MdfdVec *v;
- nblocks = mdnblocks(reln);
- v = _mdfd_getseg(reln, nblocks, O_CREAT);
+ nblocks = mdnblocks(reln);
+ v = _mdfd_getseg(reln, nblocks, O_CREAT);
- if ((pos = FileSeek(v->mdfd_vfd, 0L, SEEK_END)) < 0)
- return (SM_FAIL);
+ if ((pos = FileSeek(v->mdfd_vfd, 0L, SEEK_END)) < 0)
+ return (SM_FAIL);
- if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ)
- return (SM_FAIL);
+ if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ)
+ return (SM_FAIL);
- /* remember that we did a write, so we can sync at xact commit */
- v->mdfd_flags |= MDFD_DIRTY;
+ /* remember that we did a write, so we can sync at xact commit */
+ v->mdfd_flags |= MDFD_DIRTY;
- /* try to keep the last block count current, though it's just a hint */
- if ((v->mdfd_lstbcnt = (++nblocks % RELSEG_SIZE)) == 0)
- v->mdfd_lstbcnt = RELSEG_SIZE;
+ /* try to keep the last block count current, though it's just a hint */
+ if ((v->mdfd_lstbcnt = (++nblocks % RELSEG_SIZE)) == 0)
+ v->mdfd_lstbcnt = RELSEG_SIZE;
#ifdef DIAGNOSTIC
- if (_mdnblocks(v->mdfd_vfd, BLCKSZ) > RELSEG_SIZE
- || v->mdfd_lstbcnt > RELSEG_SIZE)
- elog(FATAL, "segment too big!");
+ if (_mdnblocks(v->mdfd_vfd, BLCKSZ) > RELSEG_SIZE
+ || v->mdfd_lstbcnt > RELSEG_SIZE)
+ elog(FATAL, "segment too big!");
#endif
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * mdopen() -- Open the specified relation.
+ * mdopen() -- Open the specified relation.
*/
int
mdopen(Relation reln)
{
- char *path;
- int fd;
- int vfd;
+ char *path;
+ int fd;
+ int vfd;
- path = relpath(&(reln->rd_rel->relname.data[0]));
+ path = relpath(&(reln->rd_rel->relname.data[0]));
- fd = FileNameOpenFile(path, O_RDWR, 0600);
+ fd = FileNameOpenFile(path, O_RDWR, 0600);
- /* this should only happen during bootstrap processing */
- if (fd < 0)
- fd = FileNameOpenFile(path, O_RDWR|O_CREAT|O_EXCL, 0600);
+ /* this should only happen during bootstrap processing */
+ if (fd < 0)
+ fd = FileNameOpenFile(path, O_RDWR | O_CREAT | O_EXCL, 0600);
- vfd = _fdvec_alloc ();
- if ( vfd < 0 )
- return (-1);
+ vfd = _fdvec_alloc();
+ if (vfd < 0)
+ return (-1);
- Md_fdvec[vfd].mdfd_vfd = fd;
- Md_fdvec[vfd].mdfd_flags = (uint16) 0;
- Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
- Md_fdvec[vfd].mdfd_lstbcnt = _mdnblocks(fd, BLCKSZ);
+ Md_fdvec[vfd].mdfd_vfd = fd;
+ Md_fdvec[vfd].mdfd_flags = (uint16) 0;
+ Md_fdvec[vfd].mdfd_chain = (MdfdVec *) NULL;
+ Md_fdvec[vfd].mdfd_lstbcnt = _mdnblocks(fd, BLCKSZ);
#ifdef DIAGNOSTIC
- if (Md_fdvec[vfd].mdfd_lstbcnt > RELSEG_SIZE)
- elog(FATAL, "segment too big on relopen!");
+ if (Md_fdvec[vfd].mdfd_lstbcnt > RELSEG_SIZE)
+ elog(FATAL, "segment too big on relopen!");
#endif
- return (vfd);
+ return (vfd);
}
/*
- * mdclose() -- Close the specified relation
+ * mdclose() -- Close the specified relation
*
- * AND FREE fd vector! It may be re-used for other relation!
- * reln should be flushed from cache after closing !..
+ * AND FREE fd vector! It may be re-used for other relation!
+ * reln should be flushed from cache after closing !..
*
- * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
+ * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
*/
int
mdclose(Relation reln)
{
- int fd;
- MdfdVec *v, *ov;
- MemoryContext oldcxt;
+ int fd;
+ MdfdVec *v,
+ *ov;
+ MemoryContext oldcxt;
- fd = RelationGetFile(reln);
+ fd = RelationGetFile(reln);
- oldcxt = MemoryContextSwitchTo(MdCxt);
- for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL; )
- {
- /* if not closed already */
- if ( v->mdfd_vfd >= 0 )
+ oldcxt = MemoryContextSwitchTo(MdCxt);
+ for (v = &Md_fdvec[fd]; v != (MdfdVec *) NULL;)
{
- /*
- * We sync the file descriptor so that we don't need to reopen it at
- * transaction commit to force changes to disk.
- */
+ /* if not closed already */
+ if (v->mdfd_vfd >= 0)
+ {
+
+ /*
+ * We sync the file descriptor so that we don't need to reopen
+ * it at transaction commit to force changes to disk.
+ */
+
+ FileSync(v->mdfd_vfd);
+ FileClose(v->mdfd_vfd);
+
+ /* mark this file descriptor as clean in our private table */
+ v->mdfd_flags &= ~MDFD_DIRTY;
+ }
+ /* Now free vector */
+ ov = v;
+ v = v->mdfd_chain;
+ if (ov != &Md_fdvec[fd])
+ pfree(ov);
+ }
- FileSync(v->mdfd_vfd);
- FileClose(v->mdfd_vfd);
+ MemoryContextSwitchTo(oldcxt);
+ Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
- /* mark this file descriptor as clean in our private table */
- v->mdfd_flags &= ~MDFD_DIRTY;
- }
- /* Now free vector */
- ov = v;
- v = v->mdfd_chain;
- if (ov != &Md_fdvec[fd])
- pfree(ov);
- }
-
- MemoryContextSwitchTo(oldcxt);
- Md_fdvec[fd].mdfd_chain = (MdfdVec *) NULL;
-
- _fdvec_free (fd);
-
- return (SM_SUCCESS);
+ _fdvec_free(fd);
+
+ return (SM_SUCCESS);
}
/*
- * mdread() -- Read the specified block from a relation.
+ * mdread() -- Read the specified block from a relation.
*
- * Returns SM_SUCCESS or SM_FAIL.
+ * Returns SM_SUCCESS or SM_FAIL.
*/
int
mdread(Relation reln, BlockNumber blocknum, char *buffer)
{
- int status;
- long seekpos;
- int nbytes;
- MdfdVec *v;
+ int status;
+ long seekpos;
+ int nbytes;
+ MdfdVec *v;
- v = _mdfd_getseg(reln, blocknum, 0);
+ v = _mdfd_getseg(reln, blocknum, 0);
- seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
+ seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
#ifdef DIAGNOSTIC
- if (seekpos >= BLCKSZ * RELSEG_SIZE)
- elog(FATAL, "seekpos too big!");
+ if (seekpos >= BLCKSZ * RELSEG_SIZE)
+ elog(FATAL, "seekpos too big!");
#endif
- if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos) {
- return (SM_FAIL);
- }
+ if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
+ {
+ return (SM_FAIL);
+ }
- status = SM_SUCCESS;
- if ((nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ) {
- if (nbytes == 0) {
- memset(buffer, 0, BLCKSZ);
- } else {
- status = SM_FAIL;
+ status = SM_SUCCESS;
+ if ((nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
+ {
+ if (nbytes == 0)
+ {
+ memset(buffer, 0, BLCKSZ);
+ }
+ else
+ {
+ status = SM_FAIL;
+ }
}
- }
- return (status);
+ return (status);
}
/*
- * mdwrite() -- Write the supplied block at the appropriate location.
+ * mdwrite() -- Write the supplied block at the appropriate location.
*
- * Returns SM_SUCCESS or SM_FAIL.
+ * Returns SM_SUCCESS or SM_FAIL.
*/
int
mdwrite(Relation reln, BlockNumber blocknum, char *buffer)
{
- int status;
- long seekpos;
- MdfdVec *v;
+ int status;
+ long seekpos;
+ MdfdVec *v;
- v = _mdfd_getseg(reln, blocknum, 0);
+ v = _mdfd_getseg(reln, blocknum, 0);
- seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
+ seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
#ifdef DIAGNOSTIC
- if (seekpos >= BLCKSZ * RELSEG_SIZE)
- elog(FATAL, "seekpos too big!");
+ if (seekpos >= BLCKSZ * RELSEG_SIZE)
+ elog(FATAL, "seekpos too big!");
#endif
- if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos) {
- return (SM_FAIL);
- }
+ if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
+ {
+ return (SM_FAIL);
+ }
- status = SM_SUCCESS;
- if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ)
- status = SM_FAIL;
+ status = SM_SUCCESS;
+ if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ)
+ status = SM_FAIL;
- v->mdfd_flags |= MDFD_DIRTY;
+ v->mdfd_flags |= MDFD_DIRTY;
- return (status);
+ return (status);
}
/*
- * mdflush() -- Synchronously write a block to disk.
+ * mdflush() -- Synchronously write a block to disk.
*
- * This is exactly like mdwrite(), but doesn't return until the file
- * system buffer cache has been flushed.
+ * This is exactly like mdwrite(), but doesn't return until the file
+ * system buffer cache has been flushed.
*/
int
mdflush(Relation reln, BlockNumber blocknum, char *buffer)
{
- int status;
- long seekpos;
- MdfdVec *v;
+ int status;
+ long seekpos;
+ MdfdVec *v;
- v = _mdfd_getseg(reln, blocknum, 0);
+ v = _mdfd_getseg(reln, blocknum, 0);
- seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
+ seekpos = (long) (BLCKSZ * (blocknum % RELSEG_SIZE));
#ifdef DIAGNOSTIC
- if (seekpos >= BLCKSZ * RELSEG_SIZE)
- elog(FATAL, "seekpos too big!");
+ if (seekpos >= BLCKSZ * RELSEG_SIZE)
+ elog(FATAL, "seekpos too big!");
#endif
- if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos) {
- return (SM_FAIL);
- }
+ if (FileSeek(v->mdfd_vfd, seekpos, SEEK_SET) != seekpos)
+ {
+ return (SM_FAIL);
+ }
- /* write and sync the block */
- status = SM_SUCCESS;
- if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ
- || FileSync(v->mdfd_vfd) < 0)
- status = SM_FAIL;
+ /* write and sync the block */
+ status = SM_SUCCESS;
+ if (FileWrite(v->mdfd_vfd, buffer, BLCKSZ) != BLCKSZ
+ || FileSync(v->mdfd_vfd) < 0)
+ status = SM_FAIL;
- /*
- * By here, the block is written and changes have been forced to stable
- * storage. Mark the descriptor as clean until the next write, so we
- * don't sync it again unnecessarily at transaction commit.
- */
+ /*
+ * By here, the block is written and changes have been forced to
+ * stable storage. Mark the descriptor as clean until the next write,
+ * so we don't sync it again unnecessarily at transaction commit.
+ */
- v->mdfd_flags &= ~MDFD_DIRTY;
+ v->mdfd_flags &= ~MDFD_DIRTY;
- return (status);
+ return (status);
}
/*
- * mdblindwrt() -- Write a block to disk blind.
+ * mdblindwrt() -- Write a block to disk blind.
*
- * We have to be able to do this using only the name and OID of
- * the database and relation in which the block belongs. This
- * is a synchronous write.
+ * We have to be able to do this using only the name and OID of
+ * the database and relation in which the block belongs. This
+ * is a synchronous write.
*/
int
mdblindwrt(char *dbstr,
- char *relstr,
- Oid dbid,
- Oid relid,
- BlockNumber blkno,
- char *buffer)
+ char *relstr,
+ Oid dbid,
+ Oid relid,
+ BlockNumber blkno,
+ char *buffer)
{
- int fd;
- int segno;
- long seekpos;
- int status;
- char *path;
- int nchars;
-
- /* be sure we have enough space for the '.segno', if any */
- segno = blkno / RELSEG_SIZE;
- if (segno > 0)
- nchars = 10;
- else
- nchars = 0;
-
- /* construct the path to the file and open it */
- if (dbid == (Oid) 0) {
- path = (char *) palloc(strlen(DataDir) + sizeof(NameData) + 2 + nchars);
- if (segno == 0)
- sprintf(path, "%s/%s", DataDir, relstr);
+ int fd;
+ int segno;
+ long seekpos;
+ int status;
+ char *path;
+ int nchars;
+
+ /* be sure we have enough space for the '.segno', if any */
+ segno = blkno / RELSEG_SIZE;
+ if (segno > 0)
+ nchars = 10;
else
- sprintf(path, "%s/%s.%d", DataDir, relstr, segno);
- } else {
- path = (char *) palloc(strlen(DataDir) + strlen("/base/") + 2 * sizeof(NameData) + 2 + nchars);
- if (segno == 0)
- sprintf(path, "%s/base/%s/%s", DataDir,
- dbstr, relstr);
+ nchars = 0;
+
+ /* construct the path to the file and open it */
+ if (dbid == (Oid) 0)
+ {
+ path = (char *) palloc(strlen(DataDir) + sizeof(NameData) + 2 + nchars);
+ if (segno == 0)
+ sprintf(path, "%s/%s", DataDir, relstr);
+ else
+ sprintf(path, "%s/%s.%d", DataDir, relstr, segno);
+ }
else
- sprintf(path, "%s/base/%s/%s.%d", DataDir, dbstr,
- relstr, segno);
- }
+ {
+ path = (char *) palloc(strlen(DataDir) + strlen("/base/") + 2 * sizeof(NameData) + 2 + nchars);
+ if (segno == 0)
+ sprintf(path, "%s/base/%s/%s", DataDir,
+ dbstr, relstr);
+ else
+ sprintf(path, "%s/base/%s/%s.%d", DataDir, dbstr,
+ relstr, segno);
+ }
- if ((fd = open(path, O_RDWR, 0600)) < 0)
- return (SM_FAIL);
+ if ((fd = open(path, O_RDWR, 0600)) < 0)
+ return (SM_FAIL);
- /* seek to the right spot */
- seekpos = (long) (BLCKSZ * (blkno % RELSEG_SIZE));
- if (lseek(fd, seekpos, SEEK_SET) != seekpos) {
- close(fd);
- return (SM_FAIL);
- }
+ /* seek to the right spot */
+ seekpos = (long) (BLCKSZ * (blkno % RELSEG_SIZE));
+ if (lseek(fd, seekpos, SEEK_SET) != seekpos)
+ {
+ close(fd);
+ return (SM_FAIL);
+ }
- status = SM_SUCCESS;
+ status = SM_SUCCESS;
- /* write and sync the block */
- if (write(fd, buffer, BLCKSZ) != BLCKSZ || (pg_fsync(fd) < 0))
- status = SM_FAIL;
+ /* write and sync the block */
+ if (write(fd, buffer, BLCKSZ) != BLCKSZ || (pg_fsync(fd) < 0))
+ status = SM_FAIL;
- if (close(fd) < 0)
- status = SM_FAIL;
+ if (close(fd) < 0)
+ status = SM_FAIL;
- pfree(path);
+ pfree(path);
- return (status);
+ return (status);
}
/*
- * mdnblocks() -- Get the number of blocks stored in a relation.
+ * mdnblocks() -- Get the number of blocks stored in a relation.
*
- * Returns # of blocks or -1 on error.
+ * Returns # of blocks or -1 on error.
*/
int
mdnblocks(Relation reln)
{
- int fd;
- MdfdVec *v;
- int nblocks;
- int segno;
+ int fd;
+ MdfdVec *v;
+ int nblocks;
+ int segno;
- fd = RelationGetFile(reln);
- v = &Md_fdvec[fd];
+ fd = RelationGetFile(reln);
+ v = &Md_fdvec[fd];
#ifdef DIAGNOSTIC
- if (_mdnblocks(v->mdfd_vfd, BLCKSZ) > RELSEG_SIZE)
- elog(FATAL, "segment too big in getseg!");
+ if (_mdnblocks(v->mdfd_vfd, BLCKSZ) > RELSEG_SIZE)
+ elog(FATAL, "segment too big in getseg!");
#endif
- segno = 0;
- for (;;) {
- if (v->mdfd_lstbcnt == RELSEG_SIZE
- || (nblocks = _mdnblocks(v->mdfd_vfd, BLCKSZ)) == RELSEG_SIZE) {
-
- v->mdfd_lstbcnt = RELSEG_SIZE;
- segno++;
-
- if (v->mdfd_chain == (MdfdVec *) NULL) {
- v->mdfd_chain = _mdfd_openseg(reln, segno, O_CREAT);
- if (v->mdfd_chain == (MdfdVec *) NULL)
- elog(WARN, "cannot count blocks for %.16s -- open failed",
- RelationGetRelationName(reln));
- }
-
- v = v->mdfd_chain;
- } else {
- return ((segno * RELSEG_SIZE) + nblocks);
+ segno = 0;
+ for (;;)
+ {
+ if (v->mdfd_lstbcnt == RELSEG_SIZE
+ || (nblocks = _mdnblocks(v->mdfd_vfd, BLCKSZ)) == RELSEG_SIZE)
+ {
+
+ v->mdfd_lstbcnt = RELSEG_SIZE;
+ segno++;
+
+ if (v->mdfd_chain == (MdfdVec *) NULL)
+ {
+ v->mdfd_chain = _mdfd_openseg(reln, segno, O_CREAT);
+ if (v->mdfd_chain == (MdfdVec *) NULL)
+ elog(WARN, "cannot count blocks for %.16s -- open failed",
+ RelationGetRelationName(reln));
+ }
+
+ v = v->mdfd_chain;
+ }
+ else
+ {
+ return ((segno * RELSEG_SIZE) + nblocks);
+ }
}
- }
}
/*
- * mdtruncate() -- Truncate relation to specified number of blocks.
+ * mdtruncate() -- Truncate relation to specified number of blocks.
*
- * Returns # of blocks or -1 on error.
+ * Returns # of blocks or -1 on error.
*/
int
-mdtruncate (Relation reln, int nblocks)
+mdtruncate(Relation reln, int nblocks)
{
- int fd;
- MdfdVec *v;
- int curnblk;
+ int fd;
+ MdfdVec *v;
+ int curnblk;
- curnblk = mdnblocks (reln);
- if ( curnblk / RELSEG_SIZE > 0 )
- {
- elog (NOTICE, "Can't truncate multi-segments relation %s",
- &(reln->rd_rel->relname.data[0]));
- return (curnblk);
- }
+ curnblk = mdnblocks(reln);
+ if (curnblk / RELSEG_SIZE > 0)
+ {
+ elog(NOTICE, "Can't truncate multi-segments relation %s",
+ &(reln->rd_rel->relname.data[0]));
+ return (curnblk);
+ }
+
+ fd = RelationGetFile(reln);
+ v = &Md_fdvec[fd];
- fd = RelationGetFile(reln);
- v = &Md_fdvec[fd];
+ if (FileTruncate(v->mdfd_vfd, nblocks * BLCKSZ) < 0)
+ return (-1);
- if ( FileTruncate (v->mdfd_vfd, nblocks * BLCKSZ) < 0 )
- return (-1);
-
- return (nblocks);
+ return (nblocks);
-} /* mdtruncate */
+} /* mdtruncate */
/*
- * mdcommit() -- Commit a transaction.
+ * mdcommit() -- Commit a transaction.
*
- * All changes to magnetic disk relations must be forced to stable
- * storage. This routine makes a pass over the private table of
- * file descriptors. Any descriptors to which we have done writes,
- * but not synced, are synced here.
+ * All changes to magnetic disk relations must be forced to stable
+ * storage. This routine makes a pass over the private table of
+ * file descriptors. Any descriptors to which we have done writes,
+ * but not synced, are synced here.
*
- * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
+ * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
*/
int
mdcommit()
{
- int i;
- MdfdVec *v;
+ int i;
+ MdfdVec *v;
- for (i = 0; i < CurFd; i++) {
- for (v = &Md_fdvec[i]; v != (MdfdVec *) NULL; v = v->mdfd_chain) {
- if (v->mdfd_flags & MDFD_DIRTY) {
- if (FileSync(v->mdfd_vfd) < 0)
- return (SM_FAIL);
-
- v->mdfd_flags &= ~MDFD_DIRTY;
- }
+ for (i = 0; i < CurFd; i++)
+ {
+ for (v = &Md_fdvec[i]; v != (MdfdVec *) NULL; v = v->mdfd_chain)
+ {
+ if (v->mdfd_flags & MDFD_DIRTY)
+ {
+ if (FileSync(v->mdfd_vfd) < 0)
+ return (SM_FAIL);
+
+ v->mdfd_flags &= ~MDFD_DIRTY;
+ }
+ }
}
- }
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * mdabort() -- Abort a transaction.
+ * mdabort() -- Abort a transaction.
*
- * Changes need not be forced to disk at transaction abort. We mark
- * all file descriptors as clean here. Always returns SM_SUCCESS.
+ * Changes need not be forced to disk at transaction abort. We mark
+ * all file descriptors as clean here. Always returns SM_SUCCESS.
*/
int
mdabort()
{
- int i;
- MdfdVec *v;
+ int i;
+ MdfdVec *v;
- for (i = 0; i < CurFd; i++) {
- for (v = &Md_fdvec[i]; v != (MdfdVec *) NULL; v = v->mdfd_chain) {
- v->mdfd_flags &= ~MDFD_DIRTY;
+ for (i = 0; i < CurFd; i++)
+ {
+ for (v = &Md_fdvec[i]; v != (MdfdVec *) NULL; v = v->mdfd_chain)
+ {
+ v->mdfd_flags &= ~MDFD_DIRTY;
+ }
}
- }
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * _fdvec_alloc () -- grab a free (or new) md file descriptor vector.
+ * _fdvec_alloc () -- grab a free (or new) md file descriptor vector.
*
*/
static
-int _fdvec_alloc ()
+int
+_fdvec_alloc()
{
- MdfdVec *nvec;
- int fdvec, i;
- MemoryContext oldcxt;
-
- if ( Md_Free >= 0 ) /* get from free list */
- {
- fdvec = Md_Free;
- Md_Free = Md_fdvec[fdvec].mdfd_nextFree;
- Assert ( Md_fdvec[fdvec].mdfd_flags == MDFD_FREE );
- Md_fdvec[fdvec].mdfd_flags = 0;
- if ( fdvec >= CurFd )
+ MdfdVec *nvec;
+ int fdvec,
+ i;
+ MemoryContext oldcxt;
+
+ if (Md_Free >= 0) /* get from free list */
{
- Assert ( fdvec == CurFd );
- CurFd++;
+ fdvec = Md_Free;
+ Md_Free = Md_fdvec[fdvec].mdfd_nextFree;
+ Assert(Md_fdvec[fdvec].mdfd_flags == MDFD_FREE);
+ Md_fdvec[fdvec].mdfd_flags = 0;
+ if (fdvec >= CurFd)
+ {
+ Assert(fdvec == CurFd);
+ CurFd++;
+ }
+ return (fdvec);
}
- return (fdvec);
- }
- /* Must allocate more room */
-
- if ( Nfds != CurFd )
- elog (FATAL, "_fdvec_alloc error");
-
- Nfds *= 2;
+ /* Must allocate more room */
+
+ if (Nfds != CurFd)
+ elog(FATAL, "_fdvec_alloc error");
- oldcxt = MemoryContextSwitchTo(MdCxt);
+ Nfds *= 2;
- nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
- memset(nvec, 0, Nfds * sizeof(MdfdVec));
- memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
- pfree(Md_fdvec);
+ oldcxt = MemoryContextSwitchTo(MdCxt);
- MemoryContextSwitchTo(oldcxt);
+ nvec = (MdfdVec *) palloc(Nfds * sizeof(MdfdVec));
+ memset(nvec, 0, Nfds * sizeof(MdfdVec));
+ memmove(nvec, (char *) Md_fdvec, CurFd * sizeof(MdfdVec));
+ pfree(Md_fdvec);
- Md_fdvec = nvec;
+ MemoryContextSwitchTo(oldcxt);
- /* Set new free list */
- for (i = CurFd; i < Nfds; i++ )
- {
- Md_fdvec[i].mdfd_nextFree = i + 1;
- Md_fdvec[i].mdfd_flags = MDFD_FREE;
- }
- Md_fdvec[Nfds - 1].mdfd_nextFree = -1;
- Md_Free = CurFd + 1;
+ Md_fdvec = nvec;
- fdvec = CurFd;
- CurFd++;
- Md_fdvec[fdvec].mdfd_flags = 0;
+ /* Set new free list */
+ for (i = CurFd; i < Nfds; i++)
+ {
+ Md_fdvec[i].mdfd_nextFree = i + 1;
+ Md_fdvec[i].mdfd_flags = MDFD_FREE;
+ }
+ Md_fdvec[Nfds - 1].mdfd_nextFree = -1;
+ Md_Free = CurFd + 1;
- return (fdvec);
+ fdvec = CurFd;
+ CurFd++;
+ Md_fdvec[fdvec].mdfd_flags = 0;
+
+ return (fdvec);
}
/*
- * _fdvec_free () -- free md file descriptor vector.
+ * _fdvec_free () -- free md file descriptor vector.
*
*/
static
-void _fdvec_free (int fdvec)
+void
+_fdvec_free(int fdvec)
{
-
- Assert ( Md_Free < 0 || Md_fdvec[Md_Free].mdfd_flags == MDFD_FREE );
- Md_fdvec[fdvec].mdfd_nextFree = Md_Free;
- Md_fdvec[fdvec].mdfd_flags = MDFD_FREE;
- Md_Free = fdvec;
+
+ Assert(Md_Free < 0 || Md_fdvec[Md_Free].mdfd_flags == MDFD_FREE);
+ Md_fdvec[fdvec].mdfd_nextFree = Md_Free;
+ Md_fdvec[fdvec].mdfd_flags = MDFD_FREE;
+ Md_Free = fdvec;
}
static MdfdVec *
_mdfd_openseg(Relation reln, int segno, int oflags)
{
- MemoryContext oldcxt;
- MdfdVec *v;
- int fd;
- bool dofree;
- char *path, *fullpath;
-
- /* be sure we have enough space for the '.segno', if any */
- path = relpath(RelationGetRelationName(reln)->data);
-
- dofree = false;
- if (segno > 0) {
- dofree = true;
- fullpath = (char *) palloc(strlen(path) + 12);
- sprintf(fullpath, "%s.%d", path, segno);
- } else
- fullpath = path;
-
- /* open the file */
- fd = PathNameOpenFile(fullpath, O_RDWR|oflags, 0600);
-
- if (dofree)
- pfree(fullpath);
-
- if (fd < 0)
- return ((MdfdVec *) NULL);
-
- /* allocate an mdfdvec entry for it */
- oldcxt = MemoryContextSwitchTo(MdCxt);
- v = (MdfdVec *) palloc(sizeof(MdfdVec));
- MemoryContextSwitchTo(oldcxt);
-
- /* fill the entry */
- v->mdfd_vfd = fd;
- v->mdfd_flags = (uint16) 0;
- v->mdfd_chain = (MdfdVec *) NULL;
- v->mdfd_lstbcnt = _mdnblocks(fd, BLCKSZ);
+ MemoryContext oldcxt;
+ MdfdVec *v;
+ int fd;
+ bool dofree;
+ char *path,
+ *fullpath;
+
+ /* be sure we have enough space for the '.segno', if any */
+ path = relpath(RelationGetRelationName(reln)->data);
+
+ dofree = false;
+ if (segno > 0)
+ {
+ dofree = true;
+ fullpath = (char *) palloc(strlen(path) + 12);
+ sprintf(fullpath, "%s.%d", path, segno);
+ }
+ else
+ fullpath = path;
+
+ /* open the file */
+ fd = PathNameOpenFile(fullpath, O_RDWR | oflags, 0600);
+
+ if (dofree)
+ pfree(fullpath);
+
+ if (fd < 0)
+ return ((MdfdVec *) NULL);
+
+ /* allocate an mdfdvec entry for it */
+ oldcxt = MemoryContextSwitchTo(MdCxt);
+ v = (MdfdVec *) palloc(sizeof(MdfdVec));
+ MemoryContextSwitchTo(oldcxt);
+
+ /* fill the entry */
+ v->mdfd_vfd = fd;
+ v->mdfd_flags = (uint16) 0;
+ v->mdfd_chain = (MdfdVec *) NULL;
+ v->mdfd_lstbcnt = _mdnblocks(fd, BLCKSZ);
#ifdef DIAGNOSTIC
- if (v->mdfd_lstbcnt > RELSEG_SIZE)
- elog(FATAL, "segment too big on open!");
+ if (v->mdfd_lstbcnt > RELSEG_SIZE)
+ elog(FATAL, "segment too big on open!");
#endif
- /* all done */
- return (v);
+ /* all done */
+ return (v);
}
static MdfdVec *
_mdfd_getseg(Relation reln, int blkno, int oflag)
{
- MdfdVec *v;
- int segno;
- int fd;
- int i;
-
- fd = RelationGetFile(reln);
- if (fd < 0) {
- if ((fd = mdopen(reln)) < 0)
- elog(WARN, "cannot open relation %.16s",
- RelationGetRelationName(reln));
- reln->rd_fd = fd;
- }
-
- for (v = &Md_fdvec[fd], segno = blkno / RELSEG_SIZE, i = 1;
- segno > 0;
- i++, segno--) {
-
- if (v->mdfd_chain == (MdfdVec *) NULL) {
- v->mdfd_chain = _mdfd_openseg(reln, i, oflag);
-
- if (v->mdfd_chain == (MdfdVec *) NULL)
- elog(WARN, "cannot open segment %d of relation %.16s",
- i, RelationGetRelationName(reln));
+ MdfdVec *v;
+ int segno;
+ int fd;
+ int i;
+
+ fd = RelationGetFile(reln);
+ if (fd < 0)
+ {
+ if ((fd = mdopen(reln)) < 0)
+ elog(WARN, "cannot open relation %.16s",
+ RelationGetRelationName(reln));
+ reln->rd_fd = fd;
+ }
+
+ for (v = &Md_fdvec[fd], segno = blkno / RELSEG_SIZE, i = 1;
+ segno > 0;
+ i++, segno--)
+ {
+
+ if (v->mdfd_chain == (MdfdVec *) NULL)
+ {
+ v->mdfd_chain = _mdfd_openseg(reln, i, oflag);
+
+ if (v->mdfd_chain == (MdfdVec *) NULL)
+ elog(WARN, "cannot open segment %d of relation %.16s",
+ i, RelationGetRelationName(reln));
+ }
+ v = v->mdfd_chain;
}
- v = v->mdfd_chain;
- }
- return (v);
+ return (v);
}
-static BlockNumber
+static BlockNumber
_mdnblocks(File file, Size blcksz)
{
- long len;
-
- len = FileSeek(file, 0L, SEEK_END) - 1;
- return((BlockNumber)((len < 0) ? 0 : 1 + len / blcksz));
+ long len;
+
+ len = FileSeek(file, 0L, SEEK_END) - 1;
+ return ((BlockNumber) ((len < 0) ? 0 : 1 + len / blcksz));
}
diff --git a/src/backend/storage/smgr/mm.c b/src/backend/storage/smgr/mm.c
index fd6c32da3a3..d0015e4f138 100644
--- a/src/backend/storage/smgr/mm.c
+++ b/src/backend/storage/smgr/mm.c
@@ -1,16 +1,16 @@
/*-------------------------------------------------------------------------
*
* mm.c--
- * main memory storage manager
+ * main memory storage manager
*
- * This code manages relations that reside in (presumably stable)
- * main memory.
+ * This code manages relations that reside in (presumably stable)
+ * main memory.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.4 1996/11/08 05:59:11 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.5 1997/09/07 04:49:22 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,7 +20,7 @@
#include <math.h>
#include "storage/ipc.h"
-#include "storage/smgr.h" /* where the declarations go */
+#include "storage/smgr.h" /* where the declarations go */
#include "storage/block.h"
#include "storage/shmem.h"
#include "storage/spin.h"
@@ -31,555 +31,582 @@
#include "utils/memutils.h"
/*
- * MMCacheTag -- Unique triplet for blocks stored by the main memory
- * storage manager.
+ * MMCacheTag -- Unique triplet for blocks stored by the main memory
+ * storage manager.
*/
-typedef struct MMCacheTag {
- Oid mmct_dbid;
- Oid mmct_relid;
- BlockNumber mmct_blkno;
-} MMCacheTag;
+typedef struct MMCacheTag
+{
+ Oid mmct_dbid;
+ Oid mmct_relid;
+ BlockNumber mmct_blkno;
+} MMCacheTag;
/*
- * Shared-memory hash table for main memory relations contains
- * entries of this form.
+ * Shared-memory hash table for main memory relations contains
+ * entries of this form.
*/
-typedef struct MMHashEntry {
- MMCacheTag mmhe_tag;
- int mmhe_bufno;
-} MMHashEntry;
+typedef struct MMHashEntry
+{
+ MMCacheTag mmhe_tag;
+ int mmhe_bufno;
+} MMHashEntry;
/*
* MMRelTag -- Unique identifier for each relation that is stored in the
- * main-memory storage manager.
+ * main-memory storage manager.
*/
-typedef struct MMRelTag {
- Oid mmrt_dbid;
- Oid mmrt_relid;
-} MMRelTag;
+typedef struct MMRelTag
+{
+ Oid mmrt_dbid;
+ Oid mmrt_relid;
+} MMRelTag;
/*
- * Shared-memory hash table for # blocks in main memory relations contains
- * entries of this form.
+ * Shared-memory hash table for # blocks in main memory relations contains
+ * entries of this form.
*/
-typedef struct MMRelHashEntry {
- MMRelTag mmrhe_tag;
- int mmrhe_nblocks;
-} MMRelHashEntry;
+typedef struct MMRelHashEntry
+{
+ MMRelTag mmrhe_tag;
+ int mmrhe_nblocks;
+} MMRelHashEntry;
-#define MMNBUFFERS 10
+#define MMNBUFFERS 10
#define MMNRELATIONS 2
-SPINLOCK MMCacheLock;
-extern bool IsPostmaster;
-extern Oid MyDatabaseId;
+SPINLOCK MMCacheLock;
+extern bool IsPostmaster;
+extern Oid MyDatabaseId;
-static int *MMCurTop;
-static int *MMCurRelno;
-static MMCacheTag *MMBlockTags;
-static char *MMBlockCache;
-static HTAB *MMCacheHT;
-static HTAB *MMRelCacheHT;
+static int *MMCurTop;
+static int *MMCurRelno;
+static MMCacheTag *MMBlockTags;
+static char *MMBlockCache;
+static HTAB *MMCacheHT;
+static HTAB *MMRelCacheHT;
int
mminit()
{
- char *mmcacheblk;
- int mmsize = 0;
- bool found;
- HASHCTL info;
+ char *mmcacheblk;
+ int mmsize = 0;
+ bool found;
+ HASHCTL info;
- SpinAcquire(MMCacheLock);
+ SpinAcquire(MMCacheLock);
- mmsize += MAXALIGN(BLCKSZ * MMNBUFFERS);
- mmsize += MAXALIGN(sizeof(*MMCurTop));
- mmsize += MAXALIGN(sizeof(*MMCurRelno));
- mmsize += MAXALIGN((MMNBUFFERS * sizeof(MMCacheTag)));
- mmcacheblk = (char *) ShmemInitStruct("Main memory smgr", mmsize, &found);
+ mmsize += MAXALIGN(BLCKSZ * MMNBUFFERS);
+ mmsize += MAXALIGN(sizeof(*MMCurTop));
+ mmsize += MAXALIGN(sizeof(*MMCurRelno));
+ mmsize += MAXALIGN((MMNBUFFERS * sizeof(MMCacheTag)));
+ mmcacheblk = (char *) ShmemInitStruct("Main memory smgr", mmsize, &found);
- if (mmcacheblk == (char *) NULL) {
- SpinRelease(MMCacheLock);
- return (SM_FAIL);
- }
+ if (mmcacheblk == (char *) NULL)
+ {
+ SpinRelease(MMCacheLock);
+ return (SM_FAIL);
+ }
- info.keysize = sizeof(MMCacheTag);
- info.datasize = sizeof(int);
- info.hash = tag_hash;
+ info.keysize = sizeof(MMCacheTag);
+ info.datasize = sizeof(int);
+ info.hash = tag_hash;
- MMCacheHT = (HTAB *) ShmemInitHash("Main memory store HT",
- MMNBUFFERS, MMNBUFFERS,
- &info, (HASH_ELEM|HASH_FUNCTION));
+ MMCacheHT = (HTAB *) ShmemInitHash("Main memory store HT",
+ MMNBUFFERS, MMNBUFFERS,
+ &info, (HASH_ELEM | HASH_FUNCTION));
- if (MMCacheHT == (HTAB *) NULL) {
- SpinRelease(MMCacheLock);
- return (SM_FAIL);
- }
+ if (MMCacheHT == (HTAB *) NULL)
+ {
+ SpinRelease(MMCacheLock);
+ return (SM_FAIL);
+ }
- info.keysize = sizeof(MMRelTag);
- info.datasize = sizeof(int);
- info.hash = tag_hash;
+ info.keysize = sizeof(MMRelTag);
+ info.datasize = sizeof(int);
+ info.hash = tag_hash;
- MMRelCacheHT = (HTAB *) ShmemInitHash("Main memory rel HT",
- MMNRELATIONS, MMNRELATIONS,
- &info, (HASH_ELEM|HASH_FUNCTION));
+ MMRelCacheHT = (HTAB *) ShmemInitHash("Main memory rel HT",
+ MMNRELATIONS, MMNRELATIONS,
+ &info, (HASH_ELEM | HASH_FUNCTION));
- if (MMRelCacheHT == (HTAB *) NULL) {
- SpinRelease(MMCacheLock);
- return (SM_FAIL);
- }
+ if (MMRelCacheHT == (HTAB *) NULL)
+ {
+ SpinRelease(MMCacheLock);
+ return (SM_FAIL);
+ }
- if (IsPostmaster) {
- memset(mmcacheblk, 0, mmsize);
- SpinRelease(MMCacheLock);
- return (SM_SUCCESS);
- }
+ if (IsPostmaster)
+ {
+ memset(mmcacheblk, 0, mmsize);
+ SpinRelease(MMCacheLock);
+ return (SM_SUCCESS);
+ }
- SpinRelease(MMCacheLock);
+ SpinRelease(MMCacheLock);
- MMCurTop = (int *) mmcacheblk;
- mmcacheblk += sizeof(int);
- MMCurRelno = (int *) mmcacheblk;
- mmcacheblk += sizeof(int);
- MMBlockTags = (MMCacheTag *) mmcacheblk;
- mmcacheblk += (MMNBUFFERS * sizeof(MMCacheTag));
- MMBlockCache = mmcacheblk;
+ MMCurTop = (int *) mmcacheblk;
+ mmcacheblk += sizeof(int);
+ MMCurRelno = (int *) mmcacheblk;
+ mmcacheblk += sizeof(int);
+ MMBlockTags = (MMCacheTag *) mmcacheblk;
+ mmcacheblk += (MMNBUFFERS * sizeof(MMCacheTag));
+ MMBlockCache = mmcacheblk;
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
int
mmshutdown()
{
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
int
mmcreate(Relation reln)
{
- MMRelHashEntry *entry;
- bool found;
- MMRelTag tag;
+ MMRelHashEntry *entry;
+ bool found;
+ MMRelTag tag;
- SpinAcquire(MMCacheLock);
+ SpinAcquire(MMCacheLock);
- if (*MMCurRelno == MMNRELATIONS) {
- SpinRelease(MMCacheLock);
- return (SM_FAIL);
- }
+ if (*MMCurRelno == MMNRELATIONS)
+ {
+ SpinRelease(MMCacheLock);
+ return (SM_FAIL);
+ }
- (*MMCurRelno)++;
+ (*MMCurRelno)++;
- tag.mmrt_relid = reln->rd_id;
- if (reln->rd_rel->relisshared)
- tag.mmrt_dbid = (Oid) 0;
- else
- tag.mmrt_dbid = MyDatabaseId;
+ tag.mmrt_relid = reln->rd_id;
+ if (reln->rd_rel->relisshared)
+ tag.mmrt_dbid = (Oid) 0;
+ else
+ tag.mmrt_dbid = MyDatabaseId;
- entry = (MMRelHashEntry *) hash_search(MMRelCacheHT,
- (char *) &tag, HASH_ENTER, &found);
+ entry = (MMRelHashEntry *) hash_search(MMRelCacheHT,
+ (char *) &tag, HASH_ENTER, &found);
- if (entry == (MMRelHashEntry *) NULL) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "main memory storage mgr rel cache hash table corrupt");
- }
+ if (entry == (MMRelHashEntry *) NULL)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "main memory storage mgr rel cache hash table corrupt");
+ }
- if (found) {
- /* already exists */
- SpinRelease(MMCacheLock);
- return (SM_FAIL);
- }
+ if (found)
+ {
+ /* already exists */
+ SpinRelease(MMCacheLock);
+ return (SM_FAIL);
+ }
- entry->mmrhe_nblocks = 0;
+ entry->mmrhe_nblocks = 0;
- SpinRelease(MMCacheLock);
+ SpinRelease(MMCacheLock);
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * mmunlink() -- Unlink a relation.
+ * mmunlink() -- Unlink a relation.
*/
int
mmunlink(Relation reln)
{
- int i;
- Oid reldbid;
- MMHashEntry *entry;
- MMRelHashEntry *rentry;
- bool found;
- MMRelTag rtag;
-
- if (reln->rd_rel->relisshared)
- reldbid = (Oid) 0;
- else
- reldbid = MyDatabaseId;
-
- SpinAcquire(MMCacheLock);
-
- for (i = 0; i < MMNBUFFERS; i++) {
- if (MMBlockTags[i].mmct_dbid == reldbid
- && MMBlockTags[i].mmct_relid == reln->rd_id) {
- entry = (MMHashEntry *) hash_search(MMCacheHT,
- (char *) &MMBlockTags[i],
- HASH_REMOVE, &found);
- if (entry == (MMHashEntry *) NULL || !found) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "mmunlink: cache hash table corrupted");
- }
- MMBlockTags[i].mmct_dbid = (Oid) 0;
- MMBlockTags[i].mmct_relid = (Oid) 0;
- MMBlockTags[i].mmct_blkno = (BlockNumber) 0;
+ int i;
+ Oid reldbid;
+ MMHashEntry *entry;
+ MMRelHashEntry *rentry;
+ bool found;
+ MMRelTag rtag;
+
+ if (reln->rd_rel->relisshared)
+ reldbid = (Oid) 0;
+ else
+ reldbid = MyDatabaseId;
+
+ SpinAcquire(MMCacheLock);
+
+ for (i = 0; i < MMNBUFFERS; i++)
+ {
+ if (MMBlockTags[i].mmct_dbid == reldbid
+ && MMBlockTags[i].mmct_relid == reln->rd_id)
+ {
+ entry = (MMHashEntry *) hash_search(MMCacheHT,
+ (char *) &MMBlockTags[i],
+ HASH_REMOVE, &found);
+ if (entry == (MMHashEntry *) NULL || !found)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "mmunlink: cache hash table corrupted");
+ }
+ MMBlockTags[i].mmct_dbid = (Oid) 0;
+ MMBlockTags[i].mmct_relid = (Oid) 0;
+ MMBlockTags[i].mmct_blkno = (BlockNumber) 0;
+ }
}
- }
- rtag.mmrt_dbid = reldbid;
- rtag.mmrt_relid = reln->rd_id;
+ rtag.mmrt_dbid = reldbid;
+ rtag.mmrt_relid = reln->rd_id;
- rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
- HASH_REMOVE, &found);
+ rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
+ HASH_REMOVE, &found);
- if (rentry == (MMRelHashEntry *) NULL || !found) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "mmunlink: rel cache hash table corrupted");
- }
+ if (rentry == (MMRelHashEntry *) NULL || !found)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "mmunlink: rel cache hash table corrupted");
+ }
- (*MMCurRelno)--;
+ (*MMCurRelno)--;
- SpinRelease(MMCacheLock);
- return 1;
+ SpinRelease(MMCacheLock);
+ return 1;
}
/*
- * mmextend() -- Add a block to the specified relation.
+ * mmextend() -- Add a block to the specified relation.
*
- * This routine returns SM_FAIL or SM_SUCCESS, with errno set as
- * appropriate.
+ * This routine returns SM_FAIL or SM_SUCCESS, with errno set as
+ * appropriate.
*/
int
mmextend(Relation reln, char *buffer)
{
- MMRelHashEntry *rentry;
- MMHashEntry *entry;
- int i;
- Oid reldbid;
- int offset;
- bool found;
- MMRelTag rtag;
- MMCacheTag tag;
-
- if (reln->rd_rel->relisshared)
- reldbid = (Oid) 0;
- else
- reldbid = MyDatabaseId;
-
- tag.mmct_dbid = rtag.mmrt_dbid = reldbid;
- tag.mmct_relid = rtag.mmrt_relid = reln->rd_id;
-
- SpinAcquire(MMCacheLock);
-
- if (*MMCurTop == MMNBUFFERS) {
- for (i = 0; i < MMNBUFFERS; i++) {
- if (MMBlockTags[i].mmct_dbid == 0 &&
- MMBlockTags[i].mmct_relid == 0)
- break;
+ MMRelHashEntry *rentry;
+ MMHashEntry *entry;
+ int i;
+ Oid reldbid;
+ int offset;
+ bool found;
+ MMRelTag rtag;
+ MMCacheTag tag;
+
+ if (reln->rd_rel->relisshared)
+ reldbid = (Oid) 0;
+ else
+ reldbid = MyDatabaseId;
+
+ tag.mmct_dbid = rtag.mmrt_dbid = reldbid;
+ tag.mmct_relid = rtag.mmrt_relid = reln->rd_id;
+
+ SpinAcquire(MMCacheLock);
+
+ if (*MMCurTop == MMNBUFFERS)
+ {
+ for (i = 0; i < MMNBUFFERS; i++)
+ {
+ if (MMBlockTags[i].mmct_dbid == 0 &&
+ MMBlockTags[i].mmct_relid == 0)
+ break;
+ }
+ if (i == MMNBUFFERS)
+ {
+ SpinRelease(MMCacheLock);
+ return (SM_FAIL);
+ }
}
- if (i == MMNBUFFERS) {
- SpinRelease(MMCacheLock);
- return (SM_FAIL);
+ else
+ {
+ i = *MMCurTop;
+ (*MMCurTop)++;
}
- } else {
- i = *MMCurTop;
- (*MMCurTop)++;
- }
-
- rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
- HASH_FIND, &found);
- if (rentry == (MMRelHashEntry *) NULL || !found) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "mmextend: rel cache hash table corrupt");
- }
- tag.mmct_blkno = rentry->mmrhe_nblocks;
+ rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
+ HASH_FIND, &found);
+ if (rentry == (MMRelHashEntry *) NULL || !found)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "mmextend: rel cache hash table corrupt");
+ }
- entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
- HASH_ENTER, &found);
- if (entry == (MMHashEntry *) NULL || found) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "mmextend: cache hash table corrupt");
- }
+ tag.mmct_blkno = rentry->mmrhe_nblocks;
- entry->mmhe_bufno = i;
- MMBlockTags[i].mmct_dbid = reldbid;
- MMBlockTags[i].mmct_relid = reln->rd_id;
- MMBlockTags[i].mmct_blkno = rentry->mmrhe_nblocks;
+ entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
+ HASH_ENTER, &found);
+ if (entry == (MMHashEntry *) NULL || found)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "mmextend: cache hash table corrupt");
+ }
- /* page numbers are zero-based, so we increment this at the end */
- (rentry->mmrhe_nblocks)++;
+ entry->mmhe_bufno = i;
+ MMBlockTags[i].mmct_dbid = reldbid;
+ MMBlockTags[i].mmct_relid = reln->rd_id;
+ MMBlockTags[i].mmct_blkno = rentry->mmrhe_nblocks;
- /* write the extended page */
- offset = (i * BLCKSZ);
- memmove(&(MMBlockCache[offset]), buffer, BLCKSZ);
+ /* page numbers are zero-based, so we increment this at the end */
+ (rentry->mmrhe_nblocks)++;
- SpinRelease(MMCacheLock);
+ /* write the extended page */
+ offset = (i * BLCKSZ);
+ memmove(&(MMBlockCache[offset]), buffer, BLCKSZ);
- return (SM_SUCCESS);
+ SpinRelease(MMCacheLock);
+
+ return (SM_SUCCESS);
}
/*
- * mmopen() -- Open the specified relation.
+ * mmopen() -- Open the specified relation.
*/
int
mmopen(Relation reln)
{
- /* automatically successful */
- return (0);
+ /* automatically successful */
+ return (0);
}
/*
- * mmclose() -- Close the specified relation.
+ * mmclose() -- Close the specified relation.
*
- * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
+ * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
*/
int
mmclose(Relation reln)
{
- /* automatically successful */
- return (SM_SUCCESS);
+ /* automatically successful */
+ return (SM_SUCCESS);
}
/*
- * mmread() -- Read the specified block from a relation.
+ * mmread() -- Read the specified block from a relation.
*
- * Returns SM_SUCCESS or SM_FAIL.
+ * Returns SM_SUCCESS or SM_FAIL.
*/
int
mmread(Relation reln, BlockNumber blocknum, char *buffer)
{
- MMHashEntry *entry;
- bool found;
- int offset;
- MMCacheTag tag;
+ MMHashEntry *entry;
+ bool found;
+ int offset;
+ MMCacheTag tag;
- if (reln->rd_rel->relisshared)
- tag.mmct_dbid = (Oid) 0;
- else
- tag.mmct_dbid = MyDatabaseId;
+ if (reln->rd_rel->relisshared)
+ tag.mmct_dbid = (Oid) 0;
+ else
+ tag.mmct_dbid = MyDatabaseId;
- tag.mmct_relid = reln->rd_id;
- tag.mmct_blkno = blocknum;
+ tag.mmct_relid = reln->rd_id;
+ tag.mmct_blkno = blocknum;
- SpinAcquire(MMCacheLock);
- entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
- HASH_FIND, &found);
+ SpinAcquire(MMCacheLock);
+ entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
+ HASH_FIND, &found);
- if (entry == (MMHashEntry *) NULL) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "mmread: hash table corrupt");
- }
+ if (entry == (MMHashEntry *) NULL)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "mmread: hash table corrupt");
+ }
- if (!found) {
- /* reading nonexistent pages is defined to fill them with zeroes */
- SpinRelease(MMCacheLock);
- memset(buffer, 0, BLCKSZ);
- return (SM_SUCCESS);
- }
+ if (!found)
+ {
+ /* reading nonexistent pages is defined to fill them with zeroes */
+ SpinRelease(MMCacheLock);
+ memset(buffer, 0, BLCKSZ);
+ return (SM_SUCCESS);
+ }
- offset = (entry->mmhe_bufno * BLCKSZ);
- memmove(buffer, &MMBlockCache[offset], BLCKSZ);
+ offset = (entry->mmhe_bufno * BLCKSZ);
+ memmove(buffer, &MMBlockCache[offset], BLCKSZ);
- SpinRelease(MMCacheLock);
+ SpinRelease(MMCacheLock);
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * mmwrite() -- Write the supplied block at the appropriate location.
+ * mmwrite() -- Write the supplied block at the appropriate location.
*
- * Returns SM_SUCCESS or SM_FAIL.
+ * Returns SM_SUCCESS or SM_FAIL.
*/
int
mmwrite(Relation reln, BlockNumber blocknum, char *buffer)
{
- MMHashEntry *entry;
- bool found;
- int offset;
- MMCacheTag tag;
+ MMHashEntry *entry;
+ bool found;
+ int offset;
+ MMCacheTag tag;
- if (reln->rd_rel->relisshared)
- tag.mmct_dbid = (Oid) 0;
- else
- tag.mmct_dbid = MyDatabaseId;
+ if (reln->rd_rel->relisshared)
+ tag.mmct_dbid = (Oid) 0;
+ else
+ tag.mmct_dbid = MyDatabaseId;
- tag.mmct_relid = reln->rd_id;
- tag.mmct_blkno = blocknum;
+ tag.mmct_relid = reln->rd_id;
+ tag.mmct_blkno = blocknum;
- SpinAcquire(MMCacheLock);
- entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
- HASH_FIND, &found);
+ SpinAcquire(MMCacheLock);
+ entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
+ HASH_FIND, &found);
- if (entry == (MMHashEntry *) NULL) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "mmread: hash table corrupt");
- }
+ if (entry == (MMHashEntry *) NULL)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "mmread: hash table corrupt");
+ }
- if (!found) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "mmwrite: hash table missing requested page");
- }
+ if (!found)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "mmwrite: hash table missing requested page");
+ }
- offset = (entry->mmhe_bufno * BLCKSZ);
- memmove(&MMBlockCache[offset], buffer, BLCKSZ);
+ offset = (entry->mmhe_bufno * BLCKSZ);
+ memmove(&MMBlockCache[offset], buffer, BLCKSZ);
- SpinRelease(MMCacheLock);
+ SpinRelease(MMCacheLock);
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * mmflush() -- Synchronously write a block to stable storage.
+ * mmflush() -- Synchronously write a block to stable storage.
*
- * For main-memory relations, this is exactly equivalent to mmwrite().
+ * For main-memory relations, this is exactly equivalent to mmwrite().
*/
int
mmflush(Relation reln, BlockNumber blocknum, char *buffer)
{
- return (mmwrite(reln, blocknum, buffer));
+ return (mmwrite(reln, blocknum, buffer));
}
/*
- * mmblindwrt() -- Write a block to stable storage blind.
+ * mmblindwrt() -- Write a block to stable storage blind.
*
- * We have to be able to do this using only the name and OID of
- * the database and relation in which the block belongs.
+ * We have to be able to do this using only the name and OID of
+ * the database and relation in which the block belongs.
*/
int
mmblindwrt(char *dbstr,
- char *relstr,
- Oid dbid,
- Oid relid,
- BlockNumber blkno,
- char *buffer)
+ char *relstr,
+ Oid dbid,
+ Oid relid,
+ BlockNumber blkno,
+ char *buffer)
{
- return (SM_FAIL);
+ return (SM_FAIL);
}
/*
- * mmnblocks() -- Get the number of blocks stored in a relation.
+ * mmnblocks() -- Get the number of blocks stored in a relation.
*
- * Returns # of blocks or -1 on error.
+ * Returns # of blocks or -1 on error.
*/
int
mmnblocks(Relation reln)
{
- MMRelTag rtag;
- MMRelHashEntry *rentry;
- bool found;
- int nblocks;
+ MMRelTag rtag;
+ MMRelHashEntry *rentry;
+ bool found;
+ int nblocks;
- if (reln->rd_rel->relisshared)
- rtag.mmrt_dbid = (Oid) 0;
- else
- rtag.mmrt_dbid = MyDatabaseId;
+ if (reln->rd_rel->relisshared)
+ rtag.mmrt_dbid = (Oid) 0;
+ else
+ rtag.mmrt_dbid = MyDatabaseId;
- rtag.mmrt_relid = reln->rd_id;
+ rtag.mmrt_relid = reln->rd_id;
- SpinAcquire(MMCacheLock);
+ SpinAcquire(MMCacheLock);
- rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
- HASH_FIND, &found);
+ rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
+ HASH_FIND, &found);
- if (rentry == (MMRelHashEntry *) NULL) {
- SpinRelease(MMCacheLock);
- elog(FATAL, "mmnblocks: rel cache hash table corrupt");
- }
+ if (rentry == (MMRelHashEntry *) NULL)
+ {
+ SpinRelease(MMCacheLock);
+ elog(FATAL, "mmnblocks: rel cache hash table corrupt");
+ }
- if (found)
- nblocks = rentry->mmrhe_nblocks;
- else
- nblocks = -1;
+ if (found)
+ nblocks = rentry->mmrhe_nblocks;
+ else
+ nblocks = -1;
- SpinRelease(MMCacheLock);
+ SpinRelease(MMCacheLock);
- return (nblocks);
+ return (nblocks);
}
/*
- * mmcommit() -- Commit a transaction.
+ * mmcommit() -- Commit a transaction.
*
- * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
+ * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
*/
int
mmcommit()
{
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * mmabort() -- Abort a transaction.
+ * mmabort() -- Abort a transaction.
*/
int
mmabort()
{
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * MMShmemSize() -- Declare amount of shared memory we require.
+ * MMShmemSize() -- Declare amount of shared memory we require.
*
- * The shared memory initialization code creates a block of shared
- * memory exactly big enough to hold all the structures it needs to.
- * This routine declares how much space the main memory storage
- * manager will use.
+ * The shared memory initialization code creates a block of shared
+ * memory exactly big enough to hold all the structures it needs to.
+ * This routine declares how much space the main memory storage
+ * manager will use.
*/
int
MMShmemSize()
{
- int size = 0;
- int nbuckets;
- int nsegs;
- int tmp;
-
- /*
- * first compute space occupied by the (dbid,relid,blkno) hash table
- */
-
- nbuckets = 1 << (int)my_log2((MMNBUFFERS - 1) / DEF_FFACTOR + 1);
- nsegs = 1 << (int)my_log2((nbuckets - 1) / DEF_SEGSIZE + 1);
-
- size += MAXALIGN(my_log2(MMNBUFFERS) * sizeof(void *));
- size += MAXALIGN(sizeof(HHDR));
- size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
- tmp = (int)ceil((double)MMNBUFFERS/BUCKET_ALLOC_INCR);
- size += tmp * BUCKET_ALLOC_INCR *
- (MAXALIGN(sizeof(BUCKET_INDEX)) +
- MAXALIGN(sizeof(MMHashEntry))); /* contains hash key */
-
- /*
- * now do the same for the rel hash table
- */
-
- size += MAXALIGN(my_log2(MMNRELATIONS) * sizeof(void *));
- size += MAXALIGN(sizeof(HHDR));
- size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
- tmp = (int)ceil((double)MMNRELATIONS/BUCKET_ALLOC_INCR);
- size += tmp * BUCKET_ALLOC_INCR *
- (MAXALIGN(sizeof(BUCKET_INDEX)) +
- MAXALIGN(sizeof(MMRelHashEntry))); /* contains hash key */
-
- /*
- * finally, add in the memory block we use directly
- */
-
- size += MAXALIGN(BLCKSZ * MMNBUFFERS);
- size += MAXALIGN(sizeof(*MMCurTop));
- size += MAXALIGN(sizeof(*MMCurRelno));
- size += MAXALIGN(MMNBUFFERS * sizeof(MMCacheTag));
-
- return (size);
+ int size = 0;
+ int nbuckets;
+ int nsegs;
+ int tmp;
+
+ /*
+ * first compute space occupied by the (dbid,relid,blkno) hash table
+ */
+
+ nbuckets = 1 << (int) my_log2((MMNBUFFERS - 1) / DEF_FFACTOR + 1);
+ nsegs = 1 << (int) my_log2((nbuckets - 1) / DEF_SEGSIZE + 1);
+
+ size += MAXALIGN(my_log2(MMNBUFFERS) * sizeof(void *));
+ size += MAXALIGN(sizeof(HHDR));
+ size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
+ tmp = (int) ceil((double) MMNBUFFERS / BUCKET_ALLOC_INCR);
+ size += tmp * BUCKET_ALLOC_INCR *
+ (MAXALIGN(sizeof(BUCKET_INDEX)) +
+ MAXALIGN(sizeof(MMHashEntry))); /* contains hash key */
+
+ /*
+ * now do the same for the rel hash table
+ */
+
+ size += MAXALIGN(my_log2(MMNRELATIONS) * sizeof(void *));
+ size += MAXALIGN(sizeof(HHDR));
+ size += nsegs * MAXALIGN(DEF_SEGSIZE * sizeof(SEGMENT));
+ tmp = (int) ceil((double) MMNRELATIONS / BUCKET_ALLOC_INCR);
+ size += tmp * BUCKET_ALLOC_INCR *
+ (MAXALIGN(sizeof(BUCKET_INDEX)) +
+ MAXALIGN(sizeof(MMRelHashEntry))); /* contains hash key */
+
+ /*
+ * finally, add in the memory block we use directly
+ */
+
+ size += MAXALIGN(BLCKSZ * MMNBUFFERS);
+ size += MAXALIGN(sizeof(*MMCurTop));
+ size += MAXALIGN(sizeof(*MMCurRelno));
+ size += MAXALIGN(MMNBUFFERS * sizeof(MMCacheTag));
+
+ return (size);
}
-#endif /* MAIN_MEMORY */
+#endif /* MAIN_MEMORY */
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 89ac5e92cb7..9fc395da0d9 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -1,16 +1,16 @@
/*-------------------------------------------------------------------------
*
* smgr.c--
- * public interface routines to storage manager switch.
+ * public interface routines to storage manager switch.
*
- * All file system operations in POSTGRES dispatch through these
- * routines.
+ * All file system operations in POSTGRES dispatch through these
+ * routines.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.8 1997/08/19 21:33:38 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgr.c,v 1.9 1997/09/07 04:49:25 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,380 +23,390 @@
#include "utils/rel.h"
#include "utils/palloc.h"
-static void smgrshutdown(int dummy);
-
-typedef struct f_smgr {
- int (*smgr_init)(); /* may be NULL */
- int (*smgr_shutdown)(); /* may be NULL */
- int (*smgr_create)();
- int (*smgr_unlink)();
- int (*smgr_extend)();
- int (*smgr_open)();
- int (*smgr_close)();
- int (*smgr_read)();
- int (*smgr_write)();
- int (*smgr_flush)();
- int (*smgr_blindwrt)();
- int (*smgr_nblocks)();
- int (*smgr_truncate)();
- int (*smgr_commit)(); /* may be NULL */
- int (*smgr_abort)(); /* may be NULL */
-} f_smgr;
+static void smgrshutdown(int dummy);
+
+typedef struct f_smgr
+{
+ int (*smgr_init) (); /* may be NULL */
+ int (*smgr_shutdown) (); /* may be NULL */
+ int (*smgr_create) ();
+ int (*smgr_unlink) ();
+ int (*smgr_extend) ();
+ int (*smgr_open) ();
+ int (*smgr_close) ();
+ int (*smgr_read) ();
+ int (*smgr_write) ();
+ int (*smgr_flush) ();
+ int (*smgr_blindwrt) ();
+ int (*smgr_nblocks) ();
+ int (*smgr_truncate) ();
+ int (*smgr_commit) (); /* may be NULL */
+ int (*smgr_abort) (); /* may be NULL */
+} f_smgr;
/*
- * The weird placement of commas in this init block is to keep the compiler
- * happy, regardless of what storage managers we have (or don't have).
+ * The weird placement of commas in this init block is to keep the compiler
+ * happy, regardless of what storage managers we have (or don't have).
*/
-static f_smgr smgrsw[] = {
+static f_smgr smgrsw[] = {
- /* magnetic disk */
- { mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
- mdread, mdwrite, mdflush, mdblindwrt, mdnblocks, mdtruncate,
- mdcommit, mdabort },
+ /* magnetic disk */
+ {mdinit, NULL, mdcreate, mdunlink, mdextend, mdopen, mdclose,
+ mdread, mdwrite, mdflush, mdblindwrt, mdnblocks, mdtruncate,
+ mdcommit, mdabort},
#ifdef MAIN_MEMORY
- /* main memory */
- { mminit, mmshutdown, mmcreate, mmunlink, mmextend, mmopen, mmclose,
- mmread, mmwrite, mmflush, mmblindwrt, mmnblocks, NULL,
- mmcommit, mmabort },
+ /* main memory */
+ {mminit, mmshutdown, mmcreate, mmunlink, mmextend, mmopen, mmclose,
+ mmread, mmwrite, mmflush, mmblindwrt, mmnblocks, NULL,
+ mmcommit, mmabort},
-#endif /* MAIN_MEMORY */
+#endif /* MAIN_MEMORY */
};
/*
- * This array records which storage managers are write-once, and which
- * support overwrite. A 'true' entry means that the storage manager is
- * write-once. In the best of all possible worlds, there would be no
- * write-once storage managers.
+ * This array records which storage managers are write-once, and which
+ * support overwrite. A 'true' entry means that the storage manager is
+ * write-once. In the best of all possible worlds, there would be no
+ * write-once storage managers.
*/
-static bool smgrwo[] = {
- false, /* magnetic disk */
+static bool smgrwo[] = {
+ false, /* magnetic disk */
#ifdef MAIN_MEMORY
- false, /* main memory*/
-#endif /* MAIN_MEMORY */
+ false, /* main memory */
+#endif /* MAIN_MEMORY */
};
-static int NSmgr = lengthof(smgrsw);
+static int NSmgr = lengthof(smgrsw);
/*
- * smgrinit(), smgrshutdown() -- Initialize or shut down all storage
- * managers.
+ * smgrinit(), smgrshutdown() -- Initialize or shut down all storage
+ * managers.
*
*/
int
smgrinit()
{
- int i;
-
- for (i = 0; i < NSmgr; i++) {
- if (smgrsw[i].smgr_init) {
- if ((*(smgrsw[i].smgr_init))() == SM_FAIL)
- elog(FATAL, "initialization failed on %s", smgrout(i));
+ int i;
+
+ for (i = 0; i < NSmgr; i++)
+ {
+ if (smgrsw[i].smgr_init)
+ {
+ if ((*(smgrsw[i].smgr_init)) () == SM_FAIL)
+ elog(FATAL, "initialization failed on %s", smgrout(i));
+ }
}
- }
- /* register the shutdown proc */
- on_exitpg(smgrshutdown, 0);
+ /* register the shutdown proc */
+ on_exitpg(smgrshutdown, 0);
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
static void
smgrshutdown(int dummy)
{
- int i;
-
- for (i = 0; i < NSmgr; i++) {
- if (smgrsw[i].smgr_shutdown) {
- if ((*(smgrsw[i].smgr_shutdown))() == SM_FAIL)
- elog(FATAL, "shutdown failed on %s", smgrout(i));
+ int i;
+
+ for (i = 0; i < NSmgr; i++)
+ {
+ if (smgrsw[i].smgr_shutdown)
+ {
+ if ((*(smgrsw[i].smgr_shutdown)) () == SM_FAIL)
+ elog(FATAL, "shutdown failed on %s", smgrout(i));
+ }
}
- }
}
/*
- * smgrcreate() -- Create a new relation.
+ * smgrcreate() -- Create a new relation.
*
- * This routine takes a reldesc, creates the relation on the appropriate
- * device, and returns a file descriptor for it.
+ * This routine takes a reldesc, creates the relation on the appropriate
+ * device, and returns a file descriptor for it.
*/
int
smgrcreate(int16 which, Relation reln)
{
- int fd;
+ int fd;
- if ((fd = (*(smgrsw[which].smgr_create))(reln)) < 0)
- elog(WARN, "cannot open %s",
- &(reln->rd_rel->relname.data[0]));
+ if ((fd = (*(smgrsw[which].smgr_create)) (reln)) < 0)
+ elog(WARN, "cannot open %s",
+ &(reln->rd_rel->relname.data[0]));
- return (fd);
+ return (fd);
}
/*
- * smgrunlink() -- Unlink a relation.
+ * smgrunlink() -- Unlink a relation.
*
- * The relation is removed from the store.
+ * The relation is removed from the store.
*/
int
smgrunlink(int16 which, Relation reln)
{
- int status;
+ int status;
- if ((status = (*(smgrsw[which].smgr_unlink))(reln)) == SM_FAIL)
- elog(WARN, "cannot unlink %s",
- &(reln->rd_rel->relname.data[0]));
+ if ((status = (*(smgrsw[which].smgr_unlink)) (reln)) == SM_FAIL)
+ elog(WARN, "cannot unlink %s",
+ &(reln->rd_rel->relname.data[0]));
- return (status);
+ return (status);
}
/*
- * smgrextend() -- Add a new block to a file.
+ * smgrextend() -- Add a new block to a file.
*
- * Returns SM_SUCCESS on success; aborts the current transaction on
- * failure.
+ * Returns SM_SUCCESS on success; aborts the current transaction on
+ * failure.
*/
int
smgrextend(int16 which, Relation reln, char *buffer)
{
- int status;
+ int status;
- status = (*(smgrsw[which].smgr_extend))(reln, buffer);
+ status = (*(smgrsw[which].smgr_extend)) (reln, buffer);
- if (status == SM_FAIL)
- elog(WARN, "%s: cannot extend",
- &(reln->rd_rel->relname.data[0]));
+ if (status == SM_FAIL)
+ elog(WARN, "%s: cannot extend",
+ &(reln->rd_rel->relname.data[0]));
- return (status);
+ return (status);
}
/*
- * smgropen() -- Open a relation using a particular storage manager.
+ * smgropen() -- Open a relation using a particular storage manager.
*
- * Returns the fd for the open relation on success, aborts the
- * transaction on failure.
+ * Returns the fd for the open relation on success, aborts the
+ * transaction on failure.
*/
int
smgropen(int16 which, Relation reln)
{
- int fd;
+ int fd;
- if ((fd = (*(smgrsw[which].smgr_open))(reln)) < 0)
- elog(WARN, "cannot open %s",
- &(reln->rd_rel->relname.data[0]));
+ if ((fd = (*(smgrsw[which].smgr_open)) (reln)) < 0)
+ elog(WARN, "cannot open %s",
+ &(reln->rd_rel->relname.data[0]));
- return (fd);
+ return (fd);
}
/*
- * smgrclose() -- Close a relation.
+ * smgrclose() -- Close a relation.
*
- * NOTE: mdclose frees fd vector! It may be re-used for other relation!
- * reln should be flushed from cache after closing !..
- * Currently, smgrclose is calling by
- * relcache.c:RelationPurgeLocalRelation() only.
- * It would be nice to have smgrfree(), but because of
- * smgrclose is called from single place... - vadim 05/22/97
+ * NOTE: mdclose frees fd vector! It may be re-used for other relation!
+ * reln should be flushed from cache after closing !..
+ * Currently, smgrclose is calling by
+ * relcache.c:RelationPurgeLocalRelation() only.
+ * It would be nice to have smgrfree(), but because of
+ * smgrclose is called from single place... - vadim 05/22/97
*
- * Returns SM_SUCCESS on success, aborts on failure.
+ * Returns SM_SUCCESS on success, aborts on failure.
*/
int
smgrclose(int16 which, Relation reln)
{
- if ((*(smgrsw[which].smgr_close))(reln) == SM_FAIL)
- elog(WARN, "cannot close %s",
- &(reln->rd_rel->relname.data[0]));
+ if ((*(smgrsw[which].smgr_close)) (reln) == SM_FAIL)
+ elog(WARN, "cannot close %s",
+ &(reln->rd_rel->relname.data[0]));
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
/*
- * smgrread() -- read a particular block from a relation into the supplied
- * buffer.
+ * smgrread() -- read a particular block from a relation into the supplied
+ * buffer.
*
- * This routine is called from the buffer manager in order to
- * instantiate pages in the shared buffer cache. All storage managers
- * return pages in the format that POSTGRES expects. This routine
- * dispatches the read. On success, it returns SM_SUCCESS. On failure,
- * the current transaction is aborted.
+ * This routine is called from the buffer manager in order to
+ * instantiate pages in the shared buffer cache. All storage managers
+ * return pages in the format that POSTGRES expects. This routine
+ * dispatches the read. On success, it returns SM_SUCCESS. On failure,
+ * the current transaction is aborted.
*/
int
smgrread(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
- int status;
+ int status;
- status = (*(smgrsw[which].smgr_read))(reln, blocknum, buffer);
+ status = (*(smgrsw[which].smgr_read)) (reln, blocknum, buffer);
- if (status == SM_FAIL)
- elog(WARN, "cannot read block %d of %s",
- blocknum, &(reln->rd_rel->relname.data[0]));
+ if (status == SM_FAIL)
+ elog(WARN, "cannot read block %d of %s",
+ blocknum, &(reln->rd_rel->relname.data[0]));
- return (status);
+ return (status);
}
/*
- * smgrwrite() -- Write the supplied buffer out.
+ * smgrwrite() -- Write the supplied buffer out.
*
- * This is not a synchronous write -- the interface for that is
- * smgrflush(). The buffer is written out via the appropriate
- * storage manager. This routine returns SM_SUCCESS or aborts
- * the current transaction.
+ * This is not a synchronous write -- the interface for that is
+ * smgrflush(). The buffer is written out via the appropriate
+ * storage manager. This routine returns SM_SUCCESS or aborts
+ * the current transaction.
*/
int
smgrwrite(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
- int status;
+ int status;
- status = (*(smgrsw[which].smgr_write))(reln, blocknum, buffer);
+ status = (*(smgrsw[which].smgr_write)) (reln, blocknum, buffer);
- if (status == SM_FAIL)
- elog(WARN, "cannot write block %d of %s",
- blocknum, &(reln->rd_rel->relname.data[0]));
+ if (status == SM_FAIL)
+ elog(WARN, "cannot write block %d of %s",
+ blocknum, &(reln->rd_rel->relname.data[0]));
- return (status);
+ return (status);
}
/*
- * smgrflush() -- A synchronous smgrwrite().
+ * smgrflush() -- A synchronous smgrwrite().
*/
int
smgrflush(int16 which, Relation reln, BlockNumber blocknum, char *buffer)
{
- int status;
+ int status;
- status = (*(smgrsw[which].smgr_flush))(reln, blocknum, buffer);
+ status = (*(smgrsw[which].smgr_flush)) (reln, blocknum, buffer);
- if (status == SM_FAIL)
- elog(WARN, "cannot flush block %d of %s to stable store",
- blocknum, &(reln->rd_rel->relname.data[0]));
+ if (status == SM_FAIL)
+ elog(WARN, "cannot flush block %d of %s to stable store",
+ blocknum, &(reln->rd_rel->relname.data[0]));
- return (status);
+ return (status);
}
/*
- * smgrblindwrt() -- Write a page out blind.
+ * smgrblindwrt() -- Write a page out blind.
*
- * In some cases, we may find a page in the buffer cache that we
- * can't make a reldesc for. This happens, for example, when we
- * want to reuse a dirty page that was written by a transaction
- * that has not yet committed, which created a new relation. In
- * this case, the buffer manager will call smgrblindwrt() with
- * the name and OID of the database and the relation to which the
- * buffer belongs. Every storage manager must be able to force
- * this page down to stable storage in this circumstance.
+ * In some cases, we may find a page in the buffer cache that we
+ * can't make a reldesc for. This happens, for example, when we
+ * want to reuse a dirty page that was written by a transaction
+ * that has not yet committed, which created a new relation. In
+ * this case, the buffer manager will call smgrblindwrt() with
+ * the name and OID of the database and the relation to which the
+ * buffer belongs. Every storage manager must be able to force
+ * this page down to stable storage in this circumstance.
*/
int
smgrblindwrt(int16 which,
- char *dbname,
- char *relname,
- Oid dbid,
- Oid relid,
- BlockNumber blkno,
- char *buffer)
+ char *dbname,
+ char *relname,
+ Oid dbid,
+ Oid relid,
+ BlockNumber blkno,
+ char *buffer)
{
- char *dbstr;
- char *relstr;
- int status;
+ char *dbstr;
+ char *relstr;
+ int status;
- dbstr = pstrdup(dbname);
- relstr = pstrdup(relname);
+ dbstr = pstrdup(dbname);
+ relstr = pstrdup(relname);
- status = (*(smgrsw[which].smgr_blindwrt))(dbstr, relstr, dbid, relid,
- blkno, buffer);
+ status = (*(smgrsw[which].smgr_blindwrt)) (dbstr, relstr, dbid, relid,
+ blkno, buffer);
- if (status == SM_FAIL)
- elog(WARN, "cannot write block %d of %s [%s] blind",
- blkno, relstr, dbstr);
+ if (status == SM_FAIL)
+ elog(WARN, "cannot write block %d of %s [%s] blind",
+ blkno, relstr, dbstr);
- pfree(dbstr);
- pfree(relstr);
+ pfree(dbstr);
+ pfree(relstr);
- return (status);
+ return (status);
}
/*
- * smgrnblocks() -- Calculate the number of POSTGRES blocks in the
- * supplied relation.
+ * smgrnblocks() -- Calculate the number of POSTGRES blocks in the
+ * supplied relation.
*
- * Returns the number of blocks on success, aborts the current
- * transaction on failure.
+ * Returns the number of blocks on success, aborts the current
+ * transaction on failure.
*/
int
smgrnblocks(int16 which, Relation reln)
{
- int nblocks;
+ int nblocks;
- if ((nblocks = (*(smgrsw[which].smgr_nblocks))(reln)) < 0)
- elog(WARN, "cannot count blocks for %s",
- &(reln->rd_rel->relname.data[0]));
+ if ((nblocks = (*(smgrsw[which].smgr_nblocks)) (reln)) < 0)
+ elog(WARN, "cannot count blocks for %s",
+ &(reln->rd_rel->relname.data[0]));
- return (nblocks);
+ return (nblocks);
}
/*
- * smgrtruncate() -- Truncate supplied relation to a specified number
- * of blocks
+ * smgrtruncate() -- Truncate supplied relation to a specified number
+ * of blocks
*
- * Returns the number of blocks on success, aborts the current
- * transaction on failure.
+ * Returns the number of blocks on success, aborts the current
+ * transaction on failure.
*/
int
smgrtruncate(int16 which, Relation reln, int nblocks)
{
- int newblks;
-
- newblks = nblocks;
- if (smgrsw[which].smgr_truncate)
- {
- if ((newblks = (*(smgrsw[which].smgr_truncate))(reln, nblocks)) < 0)
- elog(WARN, "cannot truncate %s to %d blocks",
- &(reln->rd_rel->relname.data[0]), nblocks);
- }
-
- return (newblks);
+ int newblks;
+
+ newblks = nblocks;
+ if (smgrsw[which].smgr_truncate)
+ {
+ if ((newblks = (*(smgrsw[which].smgr_truncate)) (reln, nblocks)) < 0)
+ elog(WARN, "cannot truncate %s to %d blocks",
+ &(reln->rd_rel->relname.data[0]), nblocks);
+ }
+
+ return (newblks);
}
/*
- * smgrcommit(), smgrabort() -- Commit or abort changes made during the
- * current transaction.
+ * smgrcommit(), smgrabort() -- Commit or abort changes made during the
+ * current transaction.
*/
int
smgrcommit()
{
- int i;
-
- for (i = 0; i < NSmgr; i++) {
- if (smgrsw[i].smgr_commit) {
- if ((*(smgrsw[i].smgr_commit))() == SM_FAIL)
- elog(FATAL, "transaction commit failed on %s", smgrout(i));
+ int i;
+
+ for (i = 0; i < NSmgr; i++)
+ {
+ if (smgrsw[i].smgr_commit)
+ {
+ if ((*(smgrsw[i].smgr_commit)) () == SM_FAIL)
+ elog(FATAL, "transaction commit failed on %s", smgrout(i));
+ }
}
- }
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
#ifdef NOT_USED
int
smgrabort()
{
- int i;
-
- for (i = 0; i < NSmgr; i++) {
- if (smgrsw[i].smgr_abort) {
- if ((*(smgrsw[i].smgr_abort))() == SM_FAIL)
- elog(FATAL, "transaction abort failed on %s", smgrout(i));
+ int i;
+
+ for (i = 0; i < NSmgr; i++)
+ {
+ if (smgrsw[i].smgr_abort)
+ {
+ if ((*(smgrsw[i].smgr_abort)) () == SM_FAIL)
+ elog(FATAL, "transaction abort failed on %s", smgrout(i));
+ }
}
- }
- return (SM_SUCCESS);
+ return (SM_SUCCESS);
}
+
#endif
bool
smgriswo(int16 smgrno)
{
- if (smgrno < 0 || smgrno >= NSmgr)
- elog(WARN, "illegal storage manager number %d", smgrno);
+ if (smgrno < 0 || smgrno >= NSmgr)
+ elog(WARN, "illegal storage manager number %d", smgrno);
- return (smgrwo[smgrno]);
+ return (smgrwo[smgrno]);
}
diff --git a/src/backend/storage/smgr/smgrtype.c b/src/backend/storage/smgr/smgrtype.c
index cb32d458b82..64fb53c9c2e 100644
--- a/src/backend/storage/smgr/smgrtype.c
+++ b/src/backend/storage/smgr/smgrtype.c
@@ -1,81 +1,83 @@
/*-------------------------------------------------------------------------
*
* smgrtype.c--
- * storage manager type
+ * storage manager type
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgrtype.c,v 1.2 1996/11/03 05:08:01 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/smgr/smgrtype.c,v 1.3 1997/09/07 04:49:26 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
-#include "utils/builtins.h" /* where the declarations go */
+#include "utils/builtins.h" /* where the declarations go */
#include "utils/palloc.h"
#include "storage/smgr.h"
-typedef struct smgrid {
- char *smgr_name;
-} smgrid;
+typedef struct smgrid
+{
+ char *smgr_name;
+} smgrid;
/*
- * StorageManager[] -- List of defined storage managers.
+ * StorageManager[] -- List of defined storage managers.
*
- * The weird comma placement is to keep compilers happy no matter
- * which of these is (or is not) defined.
+ * The weird comma placement is to keep compilers happy no matter
+ * which of these is (or is not) defined.
*/
-static smgrid StorageManager[] = {
+static smgrid StorageManager[] = {
{"magnetic disk"},
#ifdef MAIN_MEMORY
{"main memory"}
-#endif /* MAIN_MEMORY */
+#endif /* MAIN_MEMORY */
};
-static int NStorageManagers = lengthof(StorageManager);
+static int NStorageManagers = lengthof(StorageManager);
int2
smgrin(char *s)
{
- int i;
+ int i;
- for (i = 0; i < NStorageManagers; i++) {
- if (strcmp(s, StorageManager[i].smgr_name) == 0)
- return((int2) i);
- }
- elog(WARN, "smgrin: illegal storage manager name %s", s);
- return 0;
+ for (i = 0; i < NStorageManagers; i++)
+ {
+ if (strcmp(s, StorageManager[i].smgr_name) == 0)
+ return ((int2) i);
+ }
+ elog(WARN, "smgrin: illegal storage manager name %s", s);
+ return 0;
}
-char *
+char *
smgrout(int2 i)
{
- char *s;
+ char *s;
- if (i >= NStorageManagers || i < 0)
- elog(WARN, "Illegal storage manager id %d", i);
+ if (i >= NStorageManagers || i < 0)
+ elog(WARN, "Illegal storage manager id %d", i);
- s = (char *) palloc(strlen(StorageManager[i].smgr_name) + 1);
- strcpy(s, StorageManager[i].smgr_name);
- return (s);
+ s = (char *) palloc(strlen(StorageManager[i].smgr_name) + 1);
+ strcpy(s, StorageManager[i].smgr_name);
+ return (s);
}
bool
smgreq(int2 a, int2 b)
{
- if (a == b)
- return (true);
- return (false);
+ if (a == b)
+ return (true);
+ return (false);
}
bool
smgrne(int2 a, int2 b)
{
- if (a == b)
- return (false);
- return (true);
+ if (a == b)
+ return (false);
+ return (true);
}
diff --git a/src/backend/tcop/aclchk.c b/src/backend/tcop/aclchk.c
index fade9d09826..db6932586b7 100644
--- a/src/backend/tcop/aclchk.c
+++ b/src/backend/tcop/aclchk.c
@@ -1,23 +1,23 @@
/*-------------------------------------------------------------------------
*
* aclchk.c--
- * Routines to check access control permissions.
+ * Routines to check access control permissions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.13 1997/08/19 21:33:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.14 1997/09/07 04:49:28 momjian Exp $
*
* NOTES
- * See acl.h.
+ * See acl.h.
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
-#include "utils/acl.h" /* where declarations for this file go */
+#include "utils/acl.h" /* where declarations for this file go */
#include "access/heapam.h"
#include "access/htup.h"
#include "access/tupmacs.h"
@@ -36,7 +36,7 @@
#include "parser/catalog_utils.h"
#include "fmgr.h"
-static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
+static int32 aclcheck(Acl * acl, AclId id, AclIdType idtype, AclMode mode);
/*
* Enable use of user relations in place of real system catalogs.
@@ -49,209 +49,226 @@ static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
* relname and relowner are in the same place, happily.
*/
#undef Anum_pg_class_relacl
-#define Anum_pg_class_relacl 3
+#define Anum_pg_class_relacl 3
#undef Natts_pg_class
-#define Natts_pg_class 3
+#define Natts_pg_class 3
#undef Name_pg_class
-#define Name_pg_class "pgacls"
+#define Name_pg_class "pgacls"
#undef Name_pg_group
-#define Name_pg_group "pggroup"
+#define Name_pg_group "pggroup"
#endif
/* warning messages, now more explicit. */
/* should correspond to the order of the ACLCHK_* result codes above. */
-char *aclcheck_error_strings[] = {
- "No error.",
- "Permission denied.",
- "Table does not exist.",
- "Must be table owner."
+char *aclcheck_error_strings[] = {
+ "No error.",
+ "Permission denied.",
+ "Table does not exist.",
+ "Must be table owner."
};
#ifdef ACLDEBUG_TRACE
static
-dumpacl(Acl *acl)
+dumpacl(Acl * acl)
{
- register unsigned i;
- AclItem *aip;
-
- elog(DEBUG, "acl size = %d, # acls = %d",
- ACL_SIZE(acl), ACL_NUM(acl));
- aip = (AclItem *) ACL_DAT(acl);
- for (i = 0; i < ACL_NUM(acl); ++i)
- elog(DEBUG, " acl[%d]: %s", i, aclitemout(aip + i));
+ register unsigned i;
+ AclItem *aip;
+
+ elog(DEBUG, "acl size = %d, # acls = %d",
+ ACL_SIZE(acl), ACL_NUM(acl));
+ aip = (AclItem *) ACL_DAT(acl);
+ for (i = 0; i < ACL_NUM(acl); ++i)
+ elog(DEBUG, " acl[%d]: %s", i, aclitemout(aip + i));
}
+
#endif
/*
- *
+ *
*/
void
-ChangeAcl(char *relname,
- AclItem *mod_aip,
- unsigned modechg)
+ChangeAcl(char *relname,
+ AclItem * mod_aip,
+ unsigned modechg)
{
- register unsigned i;
- Acl *old_acl = (Acl *) NULL, *new_acl;
- Relation relation;
- static ScanKeyData relkey[1] = {
- { 0, Anum_pg_class_relname, NameEqualRegProcedure }
- };
- HeapScanDesc hsdp;
- HeapTuple htp;
- Buffer buffer;
- Datum values[Natts_pg_class];
- char nulls[Natts_pg_class];
- char replaces[Natts_pg_class];
- ItemPointerData tmp_ipd;
- Relation idescs[Num_pg_class_indices];
- int free_old_acl = 0;
-
- /*
- * Find the pg_class tuple matching 'relname' and extract the ACL.
- * If there's no ACL, create a default using the pg_class.relowner
- * field.
- *
- * We can't use the syscache here, since we need to do a heap_replace
- * on the tuple we find. Feh.
- */
- relation = heap_openr(RelationRelationName);
- if (!RelationIsValid(relation))
- elog(WARN, "ChangeAcl: could not open '%s'??",
- RelationRelationName);
- fmgr_info(NameEqualRegProcedure, &relkey[0].sk_func, &relkey[0].sk_nargs);
- relkey[0].sk_argument = NameGetDatum(relname);
- hsdp = heap_beginscan(relation,
- 0,
- NowTimeQual,
- (unsigned) 1,
- relkey);
- htp = heap_getnext(hsdp, 0, &buffer);
- if (!HeapTupleIsValid(htp)) {
- heap_endscan(hsdp);
- heap_close(relation);
- elog(WARN, "ChangeAcl: class \"%s\" not found",
- relname);
- return;
- }
- if (!heap_attisnull(htp, Anum_pg_class_relacl))
- old_acl = (Acl *) heap_getattr(htp, buffer,
- Anum_pg_class_relacl,
- RelationGetTupleDescriptor(relation),
- (bool *) NULL);
- if (!old_acl || ACL_NUM(old_acl) < 1) {
+ register unsigned i;
+ Acl *old_acl = (Acl *) NULL,
+ *new_acl;
+ Relation relation;
+ static ScanKeyData relkey[1] = {
+ {0, Anum_pg_class_relname, NameEqualRegProcedure}
+ };
+ HeapScanDesc hsdp;
+ HeapTuple htp;
+ Buffer buffer;
+ Datum values[Natts_pg_class];
+ char nulls[Natts_pg_class];
+ char replaces[Natts_pg_class];
+ ItemPointerData tmp_ipd;
+ Relation idescs[Num_pg_class_indices];
+ int free_old_acl = 0;
+
+ /*
+ * Find the pg_class tuple matching 'relname' and extract the ACL. If
+ * there's no ACL, create a default using the pg_class.relowner field.
+ *
+ * We can't use the syscache here, since we need to do a heap_replace on
+ * the tuple we find. Feh.
+ */
+ relation = heap_openr(RelationRelationName);
+ if (!RelationIsValid(relation))
+ elog(WARN, "ChangeAcl: could not open '%s'??",
+ RelationRelationName);
+ fmgr_info(NameEqualRegProcedure, &relkey[0].sk_func, &relkey[0].sk_nargs);
+ relkey[0].sk_argument = NameGetDatum(relname);
+ hsdp = heap_beginscan(relation,
+ 0,
+ NowTimeQual,
+ (unsigned) 1,
+ relkey);
+ htp = heap_getnext(hsdp, 0, &buffer);
+ if (!HeapTupleIsValid(htp))
+ {
+ heap_endscan(hsdp);
+ heap_close(relation);
+ elog(WARN, "ChangeAcl: class \"%s\" not found",
+ relname);
+ return;
+ }
+ if (!heap_attisnull(htp, Anum_pg_class_relacl))
+ old_acl = (Acl *) heap_getattr(htp, buffer,
+ Anum_pg_class_relacl,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
+ if (!old_acl || ACL_NUM(old_acl) < 1)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "ChangeAcl: using default ACL");
+ elog(DEBUG, "ChangeAcl: using default ACL");
#endif
-/* old_acl = acldefault(((Form_pg_class) GETSTRUCT(htp))->relowner); */
- old_acl = acldefault();
- free_old_acl = 1;
- }
+/* old_acl = acldefault(((Form_pg_class) GETSTRUCT(htp))->relowner); */
+ old_acl = acldefault();
+ free_old_acl = 1;
+ }
#ifdef ACLDEBUG_TRACE
- dumpacl(old_acl);
+ dumpacl(old_acl);
#endif
- new_acl = aclinsert3(old_acl, mod_aip, modechg);
+ new_acl = aclinsert3(old_acl, mod_aip, modechg);
#ifdef ACLDEBUG_TRACE
- dumpacl(new_acl);
+ dumpacl(new_acl);
#endif
- for (i = 0; i < Natts_pg_class; ++i) {
- replaces[i] = ' ';
- nulls[i] = ' '; /* ignored if replaces[i] == ' ' anyway */
- values[i] = (Datum)NULL;/* ignored if replaces[i] == ' ' anyway */
- }
- replaces[Anum_pg_class_relacl - 1] = 'r';
- values[Anum_pg_class_relacl - 1] = (Datum)new_acl;
- htp = heap_modifytuple(htp, buffer, relation, values, nulls, replaces);
- /* XXX is this necessary? */
- ItemPointerCopy(&htp->t_ctid, &tmp_ipd);
- /* XXX handle index on pg_class? */
- setheapoverride(true);
- heap_replace(relation, &tmp_ipd, htp);
- setheapoverride(false);
- heap_endscan(hsdp);
-
- /* keep the catalog indices up to date */
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
- idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, relation, htp);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
-
- heap_close(relation);
- if (free_old_acl)
- pfree(old_acl);
- pfree(new_acl);
+ for (i = 0; i < Natts_pg_class; ++i)
+ {
+ replaces[i] = ' ';
+ nulls[i] = ' '; /* ignored if replaces[i] == ' ' anyway */
+ values[i] = (Datum) NULL; /* ignored if replaces[i] == ' '
+ * anyway */
+ }
+ replaces[Anum_pg_class_relacl - 1] = 'r';
+ values[Anum_pg_class_relacl - 1] = (Datum) new_acl;
+ htp = heap_modifytuple(htp, buffer, relation, values, nulls, replaces);
+ /* XXX is this necessary? */
+ ItemPointerCopy(&htp->t_ctid, &tmp_ipd);
+ /* XXX handle index on pg_class? */
+ setheapoverride(true);
+ heap_replace(relation, &tmp_ipd, htp);
+ setheapoverride(false);
+ heap_endscan(hsdp);
+
+ /* keep the catalog indices up to date */
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
+ idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, relation, htp);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+
+ heap_close(relation);
+ if (free_old_acl)
+ pfree(old_acl);
+ pfree(new_acl);
}
AclId
get_grosysid(char *groname)
{
- HeapTuple htp;
- AclId id = 0;
-
- htp = SearchSysCacheTuple(GRONAME, PointerGetDatum(groname),
- 0,0,0);
- if (HeapTupleIsValid(htp)) {
- id = ((Form_pg_group) GETSTRUCT(htp))->grosysid;
- } else {
- elog(WARN, "non-existent group \"%s\"", groname);
- }
- return(id);
+ HeapTuple htp;
+ AclId id = 0;
+
+ htp = SearchSysCacheTuple(GRONAME, PointerGetDatum(groname),
+ 0, 0, 0);
+ if (HeapTupleIsValid(htp))
+ {
+ id = ((Form_pg_group) GETSTRUCT(htp))->grosysid;
+ }
+ else
+ {
+ elog(WARN, "non-existent group \"%s\"", groname);
+ }
+ return (id);
}
-char*
+char *
get_groname(AclId grosysid)
{
- HeapTuple htp;
- char *name = NULL;
-
- htp = SearchSysCacheTuple(GROSYSID, PointerGetDatum(grosysid),
- 0,0,0);
- if (HeapTupleIsValid(htp)) {
- name = (((Form_pg_group) GETSTRUCT(htp))->groname).data;
- } else {
- elog(NOTICE, "get_groname: group %d not found", grosysid);
- }
- return(name);
+ HeapTuple htp;
+ char *name = NULL;
+
+ htp = SearchSysCacheTuple(GROSYSID, PointerGetDatum(grosysid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(htp))
+ {
+ name = (((Form_pg_group) GETSTRUCT(htp))->groname).data;
+ }
+ else
+ {
+ elog(NOTICE, "get_groname: group %d not found", grosysid);
+ }
+ return (name);
}
-static int32
+static int32
in_group(AclId uid, AclId gid)
{
- Relation relation;
- HeapTuple htp;
- Acl *tmp;
- unsigned i, num;
- AclId *aidp;
- int32 found = 0;
+ Relation relation;
+ HeapTuple htp;
+ Acl *tmp;
+ unsigned i,
+ num;
+ AclId *aidp;
+ int32 found = 0;
relation = heap_openr(GroupRelationName);
- if (!RelationIsValid(relation)) {
+ if (!RelationIsValid(relation))
+ {
elog(NOTICE, "in_group: could not open \"%s\"??",
- GroupRelationName);
- return(0);
+ GroupRelationName);
+ return (0);
}
htp = SearchSysCacheTuple(GROSYSID, ObjectIdGetDatum(gid),
- 0,0,0);
+ 0, 0, 0);
if (HeapTupleIsValid(htp) &&
- !heap_attisnull(htp, Anum_pg_group_grolist)) {
+ !heap_attisnull(htp, Anum_pg_group_grolist))
+ {
tmp = (IdList *) heap_getattr(htp, InvalidBuffer,
- Anum_pg_group_grolist,
- RelationGetTupleDescriptor(relation),
- (bool *) NULL);
+ Anum_pg_group_grolist,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
/* XXX make me a function */
num = IDLIST_NUM(tmp);
aidp = IDLIST_DAT(tmp);
for (i = 0; i < num; ++i)
- if (aidp[i] == uid) {
+ if (aidp[i] == uid)
+ {
found = 1;
break;
}
- } else {
+ }
+ else
+ {
elog(NOTICE, "in_group: group %d not found", gid);
}
heap_close(relation);
- return(found);
+ return (found);
}
/*
@@ -259,348 +276,387 @@ in_group(AclId uid, AclId gid)
* Returns 1 if the 'id' of type 'idtype' has ACL entries in 'acl' to satisfy
* any one of the requirements of 'mode'. Returns 0 otherwise.
*/
-static int32
-aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
+static int32
+aclcheck(Acl * acl, AclId id, AclIdType idtype, AclMode mode)
{
- register unsigned i;
- register AclItem *aip, *aidat;
- unsigned num, found_group;
-
- /* if no acl is found, use world default */
- if (!acl) {
- acl = acldefault();
- }
-
- num = ACL_NUM(acl);
- aidat = ACL_DAT(acl);
-
- /*
- * We'll treat the empty ACL like that, too, although this is more
- * like an error (i.e., you manually blew away your ACL array) --
- * the system never creates an empty ACL.
- */
- if (num < 1) {
+ register unsigned i;
+ register AclItem *aip,
+ *aidat;
+ unsigned num,
+ found_group;
+
+ /* if no acl is found, use world default */
+ if (!acl)
+ {
+ acl = acldefault();
+ }
+
+ num = ACL_NUM(acl);
+ aidat = ACL_DAT(acl);
+
+ /*
+ * We'll treat the empty ACL like that, too, although this is more
+ * like an error (i.e., you manually blew away your ACL array) -- the
+ * system never creates an empty ACL.
+ */
+ if (num < 1)
+ {
#if ACLDEBUG_TRACE || 1
- elog(DEBUG, "aclcheck: zero-length ACL, returning 1");
+ elog(DEBUG, "aclcheck: zero-length ACL, returning 1");
#endif
- return ACLCHECK_OK;
- }
-
- switch (idtype) {
- case ACL_IDTYPE_UID:
- for (i = 1, aip = aidat + 1; /* skip world entry */
- i < num && aip->ai_idtype == ACL_IDTYPE_UID;
- ++i, ++aip) {
- if (aip->ai_id == id) {
+ return ACLCHECK_OK;
+ }
+
+ switch (idtype)
+ {
+ case ACL_IDTYPE_UID:
+ for (i = 1, aip = aidat + 1; /* skip world entry */
+ i < num && aip->ai_idtype == ACL_IDTYPE_UID;
+ ++i, ++aip)
+ {
+ if (aip->ai_id == id)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "aclcheck: found %d/%d",
- aip->ai_id, aip->ai_mode);
+ elog(DEBUG, "aclcheck: found %d/%d",
+ aip->ai_id, aip->ai_mode);
#endif
- return((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
- }
- }
- for (found_group = 0;
- i < num && aip->ai_idtype == ACL_IDTYPE_GID;
- ++i, ++aip) {
- if (in_group(id, aip->ai_id)) {
- if (aip->ai_mode & mode) {
- found_group = 1;
- break;
+ return ((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
+ }
}
- }
- }
- if (found_group) {
+ for (found_group = 0;
+ i < num && aip->ai_idtype == ACL_IDTYPE_GID;
+ ++i, ++aip)
+ {
+ if (in_group(id, aip->ai_id))
+ {
+ if (aip->ai_mode & mode)
+ {
+ found_group = 1;
+ break;
+ }
+ }
+ }
+ if (found_group)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG,"aclcheck: all groups ok");
+ elog(DEBUG, "aclcheck: all groups ok");
#endif
- return ACLCHECK_OK;
- }
- break;
- case ACL_IDTYPE_GID:
- for (i = 1, aip = aidat + 1; /* skip world entry and UIDs */
- i < num && aip->ai_idtype == ACL_IDTYPE_UID;
- ++i, ++aip)
- ;
- for (;
- i < num && aip->ai_idtype == ACL_IDTYPE_GID;
- ++i, ++aip) {
- if (aip->ai_id == id) {
+ return ACLCHECK_OK;
+ }
+ break;
+ case ACL_IDTYPE_GID:
+ for (i = 1, aip = aidat + 1; /* skip world entry and UIDs */
+ i < num && aip->ai_idtype == ACL_IDTYPE_UID;
+ ++i, ++aip)
+ ;
+ for (;
+ i < num && aip->ai_idtype == ACL_IDTYPE_GID;
+ ++i, ++aip)
+ {
+ if (aip->ai_id == id)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "aclcheck: found %d/%d",
- aip->ai_id, aip->ai_mode);
+ elog(DEBUG, "aclcheck: found %d/%d",
+ aip->ai_id, aip->ai_mode);
#endif
- return((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
- }
+ return ((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
+ }
+ }
+ break;
+ case ACL_IDTYPE_WORLD:
+ break;
+ default:
+ elog(WARN, "aclcheck: bogus ACL id type: %d", idtype);
+ break;
}
- break;
- case ACL_IDTYPE_WORLD:
- break;
- default:
- elog(WARN, "aclcheck: bogus ACL id type: %d", idtype);
- break;
- }
-
+
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
+ elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
#endif
- return((aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
+ return ((aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
}
int32
pg_aclcheck(char *relname, char *usename, AclMode mode)
{
- HeapTuple htp;
- AclId id;
- Acl *acl = (Acl *) NULL, *tmp;
- int32 result;
- Relation relation;
-
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_aclcheck: user \"%s\" not found",
- usename);
- id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
-
- /* for the 'pg_database' relation, check the usecreatedb
- field before checking normal permissions */
- if ( strcmp(DatabaseRelationName, relname) == 0 &&
- (((Form_pg_user) GETSTRUCT(htp))->usecreatedb)) {
- /* note that even though the user can now append to the
- pg_database table, there is still additional permissions checking
- in dbcommands.c */
- if (mode & ACL_AP)
- return ACLCHECK_OK;
- }
-
- /*
- * Deny anyone permission to update a system catalog unless
- * pg_user.usecatupd is set. (This is to let superusers protect
- * themselves from themselves.)
- */
- if (((mode & ACL_WR) || (mode & ACL_AP)) &&
- IsSystemRelationName(relname) &&
- !((Form_pg_user) GETSTRUCT(htp))->usecatupd) {
- elog(DEBUG, "pg_aclcheck: catalog update to \"%s\": permission denied",
- relname);
- return ACLCHECK_NO_PRIV;
- }
-
- /*
- * Otherwise, superusers bypass all permission-checking.
- */
- if (((Form_pg_user) GETSTRUCT(htp))->usesuper) {
+ HeapTuple htp;
+ AclId id;
+ Acl *acl = (Acl *) NULL,
+ *tmp;
+ int32 result;
+ Relation relation;
+
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_aclcheck: user \"%s\" not found",
+ usename);
+ id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+
+ /*
+ * for the 'pg_database' relation, check the usecreatedb field before
+ * checking normal permissions
+ */
+ if (strcmp(DatabaseRelationName, relname) == 0 &&
+ (((Form_pg_user) GETSTRUCT(htp))->usecreatedb))
+ {
+
+ /*
+ * note that even though the user can now append to the
+ * pg_database table, there is still additional permissions
+ * checking in dbcommands.c
+ */
+ if (mode & ACL_AP)
+ return ACLCHECK_OK;
+ }
+
+ /*
+ * Deny anyone permission to update a system catalog unless
+ * pg_user.usecatupd is set. (This is to let superusers protect
+ * themselves from themselves.)
+ */
+ if (((mode & ACL_WR) || (mode & ACL_AP)) &&
+ IsSystemRelationName(relname) &&
+ !((Form_pg_user) GETSTRUCT(htp))->usecatupd)
+ {
+ elog(DEBUG, "pg_aclcheck: catalog update to \"%s\": permission denied",
+ relname);
+ return ACLCHECK_NO_PRIV;
+ }
+
+ /*
+ * Otherwise, superusers bypass all permission-checking.
+ */
+ if (((Form_pg_user) GETSTRUCT(htp))->usesuper)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "pg_aclcheck: \"%s\" is superuser",
- usename);
+ elog(DEBUG, "pg_aclcheck: \"%s\" is superuser",
+ usename);
#endif
- return ACLCHECK_OK;
- }
-
-#ifndef ACLDEBUG
- htp = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname),
- 0,0,0);
- if (!HeapTupleIsValid(htp)) {
- elog(WARN, "pg_aclcheck: class \"%s\" not found",
- relname);
- /* an elog(WARN) kills us, so no need to return anything. */
- }
- if (!heap_attisnull(htp, Anum_pg_class_relacl)) {
- relation = heap_openr(RelationRelationName);
- tmp = (Acl *) heap_getattr(htp, InvalidBuffer,
- Anum_pg_class_relacl,
- RelationGetTupleDescriptor(relation),
- (bool *) NULL);
- acl = makeacl(ACL_NUM(tmp));
- memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
- heap_close(relation);
- } else {
- /* if the acl is null, by default the owner can do whatever
- he wants to with it */
- Oid ownerId;
- relation = heap_openr(RelationRelationName);
- ownerId = (Oid)heap_getattr(htp, InvalidBuffer,
- Anum_pg_class_relowner,
- RelationGetTupleDescriptor(relation),
- (bool*) NULL);
- acl = aclownerdefault(ownerId);
- }
-#else
- { /* This is why the syscache is great... */
- static ScanKeyData relkey[1] = {
- { 0, Anum_pg_class_relname, NameEqualRegProcedure }
- };
- HeapScanDesc hsdp;
+ return ACLCHECK_OK;
+ }
- relation = heap_openr(RelationRelationName);
- if (!RelationIsValid(relation)) {
- elog(NOTICE, "pg_checkacl: could not open \"%-.*s\"??",
- RelationRelationName);
- return ACLCHECK_NO_CLASS;
+#ifndef ACLDEBUG
+ htp = SearchSysCacheTuple(RELNAME, PointerGetDatum(relname),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ {
+ elog(WARN, "pg_aclcheck: class \"%s\" not found",
+ relname);
+ /* an elog(WARN) kills us, so no need to return anything. */
}
- fmgr_info(NameEqualRegProcedure,
- &relkey[0].sk_func,
- &relkey[0].sk_nargs);
- relkey[0].sk_argument = NameGetDatum(relname);
- hsdp = heap_beginscan(relation, 0, NowTimeQual, 1, relkey);
- htp = heap_getnext(hsdp, 0, (Buffer *) 0);
- if (HeapTupleIsValid(htp) &&
- !heap_attisnull(htp, Anum_pg_class_relacl)) {
- tmp = (Acl *) heap_getattr(htp, InvalidBuffer,
- Anum_pg_class_relacl,
- RelationGetTupleDescriptor(relation),
- (bool *) NULL);
- acl = makeacl(ACL_NUM(tmp));
- memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
+ if (!heap_attisnull(htp, Anum_pg_class_relacl))
+ {
+ relation = heap_openr(RelationRelationName);
+ tmp = (Acl *) heap_getattr(htp, InvalidBuffer,
+ Anum_pg_class_relacl,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
+ acl = makeacl(ACL_NUM(tmp));
+ memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
+ heap_close(relation);
+ }
+ else
+ {
+
+ /*
+ * if the acl is null, by default the owner can do whatever he
+ * wants to with it
+ */
+ Oid ownerId;
+
+ relation = heap_openr(RelationRelationName);
+ ownerId = (Oid) heap_getattr(htp, InvalidBuffer,
+ Anum_pg_class_relowner,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
+ acl = aclownerdefault(ownerId);
+ }
+#else
+ { /* This is why the syscache is great... */
+ static ScanKeyData relkey[1] = {
+ {0, Anum_pg_class_relname, NameEqualRegProcedure}
+ };
+ HeapScanDesc hsdp;
+
+ relation = heap_openr(RelationRelationName);
+ if (!RelationIsValid(relation))
+ {
+ elog(NOTICE, "pg_checkacl: could not open \"%-.*s\"??",
+ RelationRelationName);
+ return ACLCHECK_NO_CLASS;
+ }
+ fmgr_info(NameEqualRegProcedure,
+ &relkey[0].sk_func,
+ &relkey[0].sk_nargs);
+ relkey[0].sk_argument = NameGetDatum(relname);
+ hsdp = heap_beginscan(relation, 0, NowTimeQual, 1, relkey);
+ htp = heap_getnext(hsdp, 0, (Buffer *) 0);
+ if (HeapTupleIsValid(htp) &&
+ !heap_attisnull(htp, Anum_pg_class_relacl))
+ {
+ tmp = (Acl *) heap_getattr(htp, InvalidBuffer,
+ Anum_pg_class_relacl,
+ RelationGetTupleDescriptor(relation),
+ (bool *) NULL);
+ acl = makeacl(ACL_NUM(tmp));
+ memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
+ }
+ heap_endscan(hsdp);
+ heap_close(relation);
}
- heap_endscan(hsdp);
- heap_close(relation);
- }
#endif
- result = aclcheck(acl, id, (AclIdType) ACL_IDTYPE_UID, mode);
- if (acl)
- pfree(acl);
- return(result);
+ result = aclcheck(acl, id, (AclIdType) ACL_IDTYPE_UID, mode);
+ if (acl)
+ pfree(acl);
+ return (result);
}
int32
pg_ownercheck(char *usename,
- char *value,
- int cacheid)
+ char *value,
+ int cacheid)
{
- HeapTuple htp;
- AclId user_id, owner_id = 0;
-
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: user \"%s\" not found",
- usename);
- user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
-
- /*
- * Superusers bypass all permission-checking.
- */
- if (((Form_pg_user) GETSTRUCT(htp))->usesuper) {
+ HeapTuple htp;
+ AclId user_id,
+ owner_id = 0;
+
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: user \"%s\" not found",
+ usename);
+ user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+
+ /*
+ * Superusers bypass all permission-checking.
+ */
+ if (((Form_pg_user) GETSTRUCT(htp))->usesuper)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
- usename);
+ elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
+ usename);
#endif
- return(1);
- }
+ return (1);
+ }
- htp = SearchSysCacheTuple(cacheid, PointerGetDatum(value),
- 0,0,0);
- switch (cacheid) {
- case OPROID:
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: operator %ld not found",
- PointerGetDatum(value));
- owner_id = ((OperatorTupleForm) GETSTRUCT(htp))->oprowner;
- break;
- case PRONAME:
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: function \"%s\" not found",
- value);
- owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner;
- break;
- case RELNAME:
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: class \"%s\" not found",
- value);
- owner_id = ((Form_pg_class) GETSTRUCT(htp))->relowner;
- break;
- case TYPNAME:
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_ownercheck: type \"%s\" not found",
- value);
- owner_id = ((TypeTupleForm) GETSTRUCT(htp))->typowner;
- break;
- default:
- elog(WARN, "pg_ownercheck: invalid cache id: %d",
- cacheid);
- break;
- }
-
- return(user_id == owner_id);
+ htp = SearchSysCacheTuple(cacheid, PointerGetDatum(value),
+ 0, 0, 0);
+ switch (cacheid)
+ {
+ case OPROID:
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: operator %ld not found",
+ PointerGetDatum(value));
+ owner_id = ((OperatorTupleForm) GETSTRUCT(htp))->oprowner;
+ break;
+ case PRONAME:
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: function \"%s\" not found",
+ value);
+ owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner;
+ break;
+ case RELNAME:
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: class \"%s\" not found",
+ value);
+ owner_id = ((Form_pg_class) GETSTRUCT(htp))->relowner;
+ break;
+ case TYPNAME:
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_ownercheck: type \"%s\" not found",
+ value);
+ owner_id = ((TypeTupleForm) GETSTRUCT(htp))->typowner;
+ break;
+ default:
+ elog(WARN, "pg_ownercheck: invalid cache id: %d",
+ cacheid);
+ break;
+ }
+
+ return (user_id == owner_id);
}
int32
-pg_func_ownercheck(char *usename,
- char *funcname,
- int nargs,
- Oid *arglist)
+pg_func_ownercheck(char *usename,
+ char *funcname,
+ int nargs,
+ Oid * arglist)
{
- HeapTuple htp;
- AclId user_id, owner_id;
-
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_func_ownercheck: user \"%s\" not found",
- usename);
- user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
-
- /*
- * Superusers bypass all permission-checking.
- */
- if (((Form_pg_user) GETSTRUCT(htp))->usesuper) {
+ HeapTuple htp;
+ AclId user_id,
+ owner_id;
+
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_func_ownercheck: user \"%s\" not found",
+ usename);
+ user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+
+ /*
+ * Superusers bypass all permission-checking.
+ */
+ if (((Form_pg_user) GETSTRUCT(htp))->usesuper)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
- usename);
+ elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
+ usename);
#endif
- return(1);
- }
-
- htp = SearchSysCacheTuple(PRONAME,
- PointerGetDatum(funcname),
- PointerGetDatum(nargs),
- PointerGetDatum(arglist),
- 0);
- if (!HeapTupleIsValid(htp))
- func_error("pg_func_ownercheck", funcname, nargs, arglist);
-
- owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner;
-
- return(user_id == owner_id);
+ return (1);
+ }
+
+ htp = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(funcname),
+ PointerGetDatum(nargs),
+ PointerGetDatum(arglist),
+ 0);
+ if (!HeapTupleIsValid(htp))
+ func_error("pg_func_ownercheck", funcname, nargs, arglist);
+
+ owner_id = ((Form_pg_proc) GETSTRUCT(htp))->proowner;
+
+ return (user_id == owner_id);
}
int32
-pg_aggr_ownercheck(char *usename,
- char *aggname,
- Oid basetypeID)
+pg_aggr_ownercheck(char *usename,
+ char *aggname,
+ Oid basetypeID)
{
- HeapTuple htp;
- AclId user_id, owner_id;
-
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "pg_aggr_ownercheck: user \"%s\" not found",
- usename);
- user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
-
- /*
- * Superusers bypass all permission-checking.
- */
- if (((Form_pg_user) GETSTRUCT(htp))->usesuper) {
+ HeapTuple htp;
+ AclId user_id,
+ owner_id;
+
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(usename),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "pg_aggr_ownercheck: user \"%s\" not found",
+ usename);
+ user_id = (AclId) ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+
+ /*
+ * Superusers bypass all permission-checking.
+ */
+ if (((Form_pg_user) GETSTRUCT(htp))->usesuper)
+ {
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "pg_aggr_ownercheck: user \"%s\" is superuser",
- usename);
+ elog(DEBUG, "pg_aggr_ownercheck: user \"%s\" is superuser",
+ usename);
#endif
- return(1);
- }
+ return (1);
+ }
- htp = SearchSysCacheTuple(AGGNAME,
- PointerGetDatum(aggname),
- PointerGetDatum(basetypeID),
- 0,
- 0);
+ htp = SearchSysCacheTuple(AGGNAME,
+ PointerGetDatum(aggname),
+ PointerGetDatum(basetypeID),
+ 0,
+ 0);
+
+ if (!HeapTupleIsValid(htp))
+ agg_error("pg_aggr_ownercheck", aggname, basetypeID);
- if (!HeapTupleIsValid(htp))
- agg_error("pg_aggr_ownercheck", aggname, basetypeID);
+ owner_id = ((Form_pg_aggregate) GETSTRUCT(htp))->aggowner;
- owner_id = ((Form_pg_aggregate) GETSTRUCT(htp))->aggowner;
-
- return(user_id == owner_id);
+ return (user_id == owner_id);
}
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c
index ea1548cd3de..1c0306b18d9 100644
--- a/src/backend/tcop/dest.c
+++ b/src/backend/tcop/dest.c
@@ -1,29 +1,29 @@
/*-------------------------------------------------------------------------
*
* dest.c--
- * support for various communication destinations - see lib/H/tcop/dest.h
+ * support for various communication destinations - see lib/H/tcop/dest.h
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.10 1997/08/29 09:04:18 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.11 1997/09/07 04:49:31 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * INTERFACE ROUTINES
- * BeginCommand - prepare destination for tuples of the given type
- * EndCommand - tell destination that no more tuples will arrive
- * NullCommand - tell dest that the last of a query sequence was processed
- *
- * NOTES
- * These routines do the appropriate work before and after
- * tuples are returned by a query to keep the backend and the
- * "destination" portals synchronized.
+ * INTERFACE ROUTINES
+ * BeginCommand - prepare destination for tuples of the given type
+ * EndCommand - tell destination that no more tuples will arrive
+ * NullCommand - tell dest that the last of a query sequence was processed
+ *
+ * NOTES
+ * These routines do the appropriate work before and after
+ * tuples are returned by a query to keep the backend and the
+ * "destination" portals synchronized.
*
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
@@ -43,10 +43,10 @@
#include "commands/async.h"
-static char CommandInfo[32] = {0};
+static char CommandInfo[32] = {0};
/* ----------------
- * output functions
+ * output functions
* ----------------
*/
static void
@@ -54,85 +54,88 @@ donothing(HeapTuple tuple, TupleDesc attrdesc)
{
}
-extern void spi_printtup (HeapTuple tuple, TupleDesc tupdesc);
+extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc);
-void (*DestToFunction(CommandDest dest))(HeapTuple, TupleDesc)
+void (*
+ DestToFunction(CommandDest dest)) (HeapTuple, TupleDesc)
{
- switch (dest) {
- case RemoteInternal:
- return printtup_internal;
- break;
-
- case Remote:
- return printtup;
- break;
-
- case Local:
- return be_printtup;
- break;
-
- case Debug:
- return debugtup;
- break;
-
- case SPI:
- return spi_printtup;
- break;
-
- case None:
- default:
+ switch (dest)
+ {
+ case RemoteInternal:
+ return printtup_internal;
+ break;
+
+ case Remote:
+ return printtup;
+ break;
+
+ case Local:
+ return be_printtup;
+ break;
+
+ case Debug:
+ return debugtup;
+ break;
+
+ case SPI:
+ return spi_printtup;
+ break;
+
+ case None:
+ default:
+ return donothing;
+ break;
+ }
+
+ /*
+ * never gets here, but DECstation lint appears to be stupid...
+ */
+
return donothing;
- break;
- }
-
- /*
- * never gets here, but DECstation lint appears to be stupid...
- */
-
- return donothing;
}
/* ----------------
- * EndCommand - tell destination that no more tuples will arrive
+ * EndCommand - tell destination that no more tuples will arrive
* ----------------
*/
void
EndCommand(char *commandTag, CommandDest dest)
{
- char buf[64];
-
- switch (dest) {
- case RemoteInternal:
- case Remote:
- /* ----------------
- * tell the fe that the query is over
- * ----------------
- */
- pq_putnchar("C", 1);
- sprintf(buf, "%s%s", commandTag, CommandInfo);
- CommandInfo[0] = 0;
- pq_putstr(buf);
- pq_flush();
- break;
-
- case Local:
- case Debug:
- break;
- case CopyEnd:
- pq_putnchar("Z", 1);
- pq_flush();
- break;
- case None:
- default:
- break;
- }
+ char buf[64];
+
+ switch (dest)
+ {
+ case RemoteInternal:
+ case Remote:
+ /* ----------------
+ * tell the fe that the query is over
+ * ----------------
+ */
+ pq_putnchar("C", 1);
+ sprintf(buf, "%s%s", commandTag, CommandInfo);
+ CommandInfo[0] = 0;
+ pq_putstr(buf);
+ pq_flush();
+ break;
+
+ case Local:
+ case Debug:
+ break;
+ case CopyEnd:
+ pq_putnchar("Z", 1);
+ pq_flush();
+ break;
+ case None:
+ default:
+ break;
+ }
}
/*
* These are necessary to sync communications between fe/be processes doing
* COPY rel TO stdout
- *
- * or
+ *
+ * or
*
* COPY rel FROM stdin
*
@@ -140,198 +143,211 @@ EndCommand(char *commandTag, CommandDest dest)
void
SendCopyBegin(void)
{
- pq_putnchar("B", 1);
-/* pq_putint(0, 4); */
- pq_flush();
+ pq_putnchar("B", 1);
+/* pq_putint(0, 4); */
+ pq_flush();
}
void
ReceiveCopyBegin(void)
{
- pq_putnchar("D", 1);
-/* pq_putint(0, 4); */
- pq_flush();
+ pq_putnchar("D", 1);
+/* pq_putint(0, 4); */
+ pq_flush();
}
/* ----------------
- * NullCommand - tell dest that the last of a query sequence was processed
- *
- * Necessary to implement the hacky FE/BE interface to handle
- * multiple-return queries.
+ * NullCommand - tell dest that the last of a query sequence was processed
+ *
+ * Necessary to implement the hacky FE/BE interface to handle
+ * multiple-return queries.
* ----------------
*/
void
NullCommand(CommandDest dest)
{
- switch (dest) {
- case RemoteInternal:
- case Remote: {
+ switch (dest)
+ {
+ case RemoteInternal:
+ case Remote:
+ {
#if 0
- /* Do any asynchronous notification. If front end wants to poll,
- it can send null queries to call this function.
- */
- PQNotifyList *nPtr;
- MemoryContext orig;
-
- if (notifyContext == NULL) {
- notifyContext = CreateGlobalMemory("notify");
- }
- orig = MemoryContextSwitchTo((MemoryContext)notifyContext);
-
- for (nPtr = PQnotifies() ;
- nPtr != NULL;
- nPtr = (PQNotifyList *)SLGetSucc(&nPtr->Node)) {
- pq_putnchar("A",1);
- pq_putint(0, 4);
- pq_putstr(nPtr->relname);
- pq_putint(nPtr->be_pid,4);
- PQremoveNotify(nPtr);
- }
- pq_flush();
- PQcleanNotify(); /* garbage collect */
- MemoryContextSwitchTo(orig);
+
+ /*
+ * Do any asynchronous notification. If front end wants to
+ * poll, it can send null queries to call this function.
+ */
+ PQNotifyList *nPtr;
+ MemoryContext orig;
+
+ if (notifyContext == NULL)
+ {
+ notifyContext = CreateGlobalMemory("notify");
+ }
+ orig = MemoryContextSwitchTo((MemoryContext) notifyContext);
+
+ for (nPtr = PQnotifies();
+ nPtr != NULL;
+ nPtr = (PQNotifyList *) SLGetSucc(&nPtr->Node))
+ {
+ pq_putnchar("A", 1);
+ pq_putint(0, 4);
+ pq_putstr(nPtr->relname);
+ pq_putint(nPtr->be_pid, 4);
+ PQremoveNotify(nPtr);
+ }
+ pq_flush();
+ PQcleanNotify(); /* garbage collect */
+ MemoryContextSwitchTo(orig);
#endif
- /* ----------------
- * tell the fe that the last of the queries has finished
- * ----------------
- */
-/* pq_putnchar("I", 1); */
- pq_putstr("I");
- /* pq_putint(0, 4);*/
- pq_flush();
- }
- break;
-
- case Local:
- case Debug:
- case None:
- default:
- break;
- }
+ /* ----------------
+ * tell the fe that the last of the queries has finished
+ * ----------------
+ */
+/* pq_putnchar("I", 1); */
+ pq_putstr("I");
+ /* pq_putint(0, 4); */
+ pq_flush();
+ }
+ break;
+
+ case Local:
+ case Debug:
+ case None:
+ default:
+ break;
+ }
}
/* ----------------
- * BeginCommand - prepare destination for tuples of the given type
+ * BeginCommand - prepare destination for tuples of the given type
* ----------------
*/
void
BeginCommand(char *pname,
- int operation,
- TupleDesc tupdesc,
- bool isIntoRel,
- bool isIntoPortal,
- char *tag,
- CommandDest dest)
+ int operation,
+ TupleDesc tupdesc,
+ bool isIntoRel,
+ bool isIntoPortal,
+ char *tag,
+ CommandDest dest)
{
- PortalEntry *entry;
- AttributeTupleForm *attrs = tupdesc->attrs;
- int natts = tupdesc->natts;
- int i;
- char *p;
-
- switch (dest) {
- case RemoteInternal:
- case Remote:
- /* ----------------
- * if this is a "retrieve portal" query, just return
- * because nothing needs to be sent to the fe.
- * ----------------
- */
- CommandInfo[0] = 0;
- if (isIntoPortal)
- return;
-
- /* ----------------
- * if portal name not specified for remote query,
- * use the "blank" portal.
- * ----------------
- */
- if (pname == NULL)
- pname = "blank";
-
- /* ----------------
- * send fe info on tuples we're about to send
- * ----------------
- */
- pq_flush();
- pq_putnchar("P", 1); /* new portal.. */
- pq_putstr(pname); /* portal name */
-
- /* ----------------
- * if this is a retrieve, then we send back the tuple
- * descriptor of the tuples. "retrieve into" is an
- * exception because no tuples are returned in that case.
- * ----------------
- */
- if (operation == CMD_SELECT && !isIntoRel) {
- pq_putnchar("T", 1); /* type info to follow.. */
- pq_putint(natts, 2); /* number of attributes in tuples */
-
- for (i = 0; i < natts; ++i) {
- pq_putstr(attrs[i]->attname.data);/* if 16 char name oops.. */
- pq_putint((int) attrs[i]->atttypid, 4);
- pq_putint(attrs[i]->attlen, 2);
- }
- }
- pq_flush();
- break;
-
- case Local:
- /* ----------------
- * prepare local portal buffer for query results
- * and setup result for PQexec()
- * ----------------
- */
- entry = be_currentportal();
- if (pname != NULL)
- pbuf_setportalinfo(entry, pname);
-
- if (operation == CMD_SELECT && !isIntoRel) {
- be_typeinit(entry, tupdesc, natts);
- p = (char *) palloc(strlen(entry->name)+2);
- p[0] = 'P';
- strcpy(p+1,entry->name);
- } else {
- p = (char *) palloc(strlen(tag)+2);
- p[0] = 'C';
- strcpy(p+1,tag);
+ PortalEntry *entry;
+ AttributeTupleForm *attrs = tupdesc->attrs;
+ int natts = tupdesc->natts;
+ int i;
+ char *p;
+
+ switch (dest)
+ {
+ case RemoteInternal:
+ case Remote:
+ /* ----------------
+ * if this is a "retrieve portal" query, just return
+ * because nothing needs to be sent to the fe.
+ * ----------------
+ */
+ CommandInfo[0] = 0;
+ if (isIntoPortal)
+ return;
+
+ /* ----------------
+ * if portal name not specified for remote query,
+ * use the "blank" portal.
+ * ----------------
+ */
+ if (pname == NULL)
+ pname = "blank";
+
+ /* ----------------
+ * send fe info on tuples we're about to send
+ * ----------------
+ */
+ pq_flush();
+ pq_putnchar("P", 1); /* new portal.. */
+ pq_putstr(pname); /* portal name */
+
+ /* ----------------
+ * if this is a retrieve, then we send back the tuple
+ * descriptor of the tuples. "retrieve into" is an
+ * exception because no tuples are returned in that case.
+ * ----------------
+ */
+ if (operation == CMD_SELECT && !isIntoRel)
+ {
+ pq_putnchar("T", 1);/* type info to follow.. */
+ pq_putint(natts, 2);/* number of attributes in tuples */
+
+ for (i = 0; i < natts; ++i)
+ {
+ pq_putstr(attrs[i]->attname.data); /* if 16 char name
+ * oops.. */
+ pq_putint((int) attrs[i]->atttypid, 4);
+ pq_putint(attrs[i]->attlen, 2);
+ }
+ }
+ pq_flush();
+ break;
+
+ case Local:
+ /* ----------------
+ * prepare local portal buffer for query results
+ * and setup result for PQexec()
+ * ----------------
+ */
+ entry = be_currentportal();
+ if (pname != NULL)
+ pbuf_setportalinfo(entry, pname);
+
+ if (operation == CMD_SELECT && !isIntoRel)
+ {
+ be_typeinit(entry, tupdesc, natts);
+ p = (char *) palloc(strlen(entry->name) + 2);
+ p[0] = 'P';
+ strcpy(p + 1, entry->name);
+ }
+ else
+ {
+ p = (char *) palloc(strlen(tag) + 2);
+ p[0] = 'C';
+ strcpy(p + 1, tag);
+ }
+ entry->result = p;
+ break;
+
+ case Debug:
+ /* ----------------
+ * show the return type of the tuples
+ * ----------------
+ */
+ if (pname == NULL)
+ pname = "blank";
+
+ showatts(pname, tupdesc);
+ break;
+
+ case None:
+ default:
+ break;
}
- entry->result = p;
- break;
-
- case Debug:
- /* ----------------
- * show the return type of the tuples
- * ----------------
- */
- if (pname == NULL)
- pname = "blank";
-
- showatts(pname, tupdesc);
- break;
-
- case None:
- default:
- break;
- }
}
void
-UpdateCommandInfo (int operation, Oid lastoid, uint32 tuples)
+UpdateCommandInfo(int operation, Oid lastoid, uint32 tuples)
{
- switch (operation)
- {
- case CMD_INSERT :
- if ( tuples > 1 )
- lastoid = InvalidOid;
- sprintf (CommandInfo, " %u %u", lastoid, tuples);
- break;
- case CMD_DELETE :
- case CMD_UPDATE :
- sprintf (CommandInfo, " %u", tuples);
- break;
- default :
- CommandInfo[0] = 0;
- }
- return;
+ switch (operation)
+ {
+ case CMD_INSERT:
+ if (tuples > 1)
+ lastoid = InvalidOid;
+ sprintf(CommandInfo, " %u %u", lastoid, tuples);
+ break;
+ case CMD_DELETE:
+ case CMD_UPDATE:
+ sprintf(CommandInfo, " %u", tuples);
+ break;
+ default:
+ CommandInfo[0] = 0;
+ }
+ return;
}
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 20951fa4cb0..27c01ff1a17 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -1,59 +1,59 @@
/*-------------------------------------------------------------------------
*
* fastpath.c--
- * routines to handle function requests from the frontend
+ * routines to handle function requests from the frontend
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.4 1997/03/12 21:07:50 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.5 1997/09/07 04:49:32 momjian Exp $
*
* NOTES
- * This cruft is the server side of PQfn.
+ * This cruft is the server side of PQfn.
*
- * - jolly 07/11/95:
+ * - jolly 07/11/95:
*
- * no longer rely on return sizes provided by the frontend. Always
- * use the true lengths for the catalogs. Assume that the frontend
- * has allocated enough space to handle the result value returned.
- *
- * trust that the user knows what he is doing with the args. If the
- * sys catalog says it is a varlena, assume that the user is only sending
- * down VARDATA and that the argsize is the VARSIZE. If the arg is
- * fixed len, assume that the argsize given by the user is correct.
- *
- * if the function returns by value, then only send 4 bytes value
- * back to the frontend. If the return returns by reference,
- * send down only the data portion and set the return size appropriately.
- *
- * OLD COMMENTS FOLLOW
+ * no longer rely on return sizes provided by the frontend. Always
+ * use the true lengths for the catalogs. Assume that the frontend
+ * has allocated enough space to handle the result value returned.
*
- * The VAR_LENGTH_{ARGS,RESULT} stuff is limited to MAX_STRING_LENGTH
- * (see src/backend/tmp/fastpath.h) for no obvious reason. Since its
- * primary use (for us) is for Inversion path names, it should probably
- * be increased to 256 (MAXPATHLEN for Inversion, hidden in pg_type
- * as well as utils/adt/filename.c).
+ * trust that the user knows what he is doing with the args. If the
+ * sys catalog says it is a varlena, assume that the user is only sending
+ * down VARDATA and that the argsize is the VARSIZE. If the arg is
+ * fixed len, assume that the argsize given by the user is correct.
*
- * Quoth PMA on 08/15/93:
+ * if the function returns by value, then only send 4 bytes value
+ * back to the frontend. If the return returns by reference,
+ * send down only the data portion and set the return size appropriately.
*
- * This code has been almost completely rewritten with an eye to
- * keeping it as compatible as possible with the previous (broken)
- * implementation.
+ * OLD COMMENTS FOLLOW
*
- * The previous implementation would assume (1) that any value of
- * length <= 4 bytes was passed-by-value, and that any other value
- * was a struct varlena (by-reference). There was NO way to pass a
- * fixed-length by-reference argument (like char16) or a struct
- * varlena of size <= 4 bytes.
- *
- * The new implementation checks the catalogs to determine whether
- * a value is by-value (type "0" is null-delimited character string,
- * as it is for, e.g., the parser). The only other item obtained
- * from the catalogs is whether or not the value should be placed in
- * a struct varlena or not. Otherwise, the size given by the
- * frontend is assumed to be correct (probably a bad decision, but
- * we do strange things in the name of compatibility).
+ * The VAR_LENGTH_{ARGS,RESULT} stuff is limited to MAX_STRING_LENGTH
+ * (see src/backend/tmp/fastpath.h) for no obvious reason. Since its
+ * primary use (for us) is for Inversion path names, it should probably
+ * be increased to 256 (MAXPATHLEN for Inversion, hidden in pg_type
+ * as well as utils/adt/filename.c).
+ *
+ * Quoth PMA on 08/15/93:
+ *
+ * This code has been almost completely rewritten with an eye to
+ * keeping it as compatible as possible with the previous (broken)
+ * implementation.
+ *
+ * The previous implementation would assume (1) that any value of
+ * length <= 4 bytes was passed-by-value, and that any other value
+ * was a struct varlena (by-reference). There was NO way to pass a
+ * fixed-length by-reference argument (like char16) or a struct
+ * varlena of size <= 4 bytes.
+ *
+ * The new implementation checks the catalogs to determine whether
+ * a value is by-value (type "0" is null-delimited character string,
+ * as it is for, e.g., the parser). The only other item obtained
+ * from the catalogs is whether or not the value should be placed in
+ * a struct varlena or not. Otherwise, the size given by the
+ * frontend is assumed to be correct (probably a bad decision, but
+ * we do strange things in the name of compatibility).
*
*-------------------------------------------------------------------------
*/
@@ -65,11 +65,11 @@
#include "utils/palloc.h"
#include "fmgr.h"
-#include "utils/builtins.h" /* for oideq */
+#include "utils/builtins.h" /* for oideq */
#include "tcop/fastpath.h"
#include "libpq/libpq.h"
-#include "access/xact.h" /* for TransactionId/CommandId protos */
+#include "access/xact.h" /* for TransactionId/CommandId protos */
#include "utils/syscache.h"
#include "catalog/pg_proc.h"
@@ -77,90 +77,98 @@
/* ----------------
- * SendFunctionResult
+ * SendFunctionResult
* ----------------
*/
static void
-SendFunctionResult(Oid fid, /* function id */
- char *retval, /* actual return value */
- bool retbyval,
- int retlen /* the length according to the catalogs */
- )
+SendFunctionResult(Oid fid, /* function id */
+ char *retval,/* actual return value */
+ bool retbyval,
+ int retlen /* the length according to the catalogs */
+)
{
- pq_putnchar("V", 1);
-
- if (retlen != 0) {
- pq_putnchar("G", 1);
- if (retbyval) { /* by-value */
- pq_putint(retlen, 4);
- pq_putint((int)(Datum)retval, retlen);
- } else { /* by-reference ... */
- if (retlen < 0) { /* ... varlena */
- pq_putint(VARSIZE(retval) - VARHDRSZ, 4);
- pq_putnchar(VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
- } else { /* ... fixed */
- pq_putint(retlen, 4);
- pq_putnchar(retval, retlen);
- }
+ pq_putnchar("V", 1);
+
+ if (retlen != 0)
+ {
+ pq_putnchar("G", 1);
+ if (retbyval)
+ { /* by-value */
+ pq_putint(retlen, 4);
+ pq_putint((int) (Datum) retval, retlen);
+ }
+ else
+ { /* by-reference ... */
+ if (retlen < 0)
+ { /* ... varlena */
+ pq_putint(VARSIZE(retval) - VARHDRSZ, 4);
+ pq_putnchar(VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
+ }
+ else
+ { /* ... fixed */
+ pq_putint(retlen, 4);
+ pq_putnchar(retval, retlen);
+ }
+ }
}
- }
- pq_putnchar("0", 1);
- pq_flush();
+ pq_putnchar("0", 1);
+ pq_flush();
}
/*
* This structure saves enough state so that one can avoid having to
- * do catalog lookups over and over again. (Each RPC can require up
+ * do catalog lookups over and over again. (Each RPC can require up
* to MAXFMGRARGS+2 lookups, which is quite tedious.)
*
* The previous incarnation of this code just assumed that any argument
- * of size <= 4 was by value; this is not correct. There is no cheap
+ * of size <= 4 was by value; this is not correct. There is no cheap
* way to determine function argument length etc.; one must simply pay
* the price of catalog lookups.
*/
-struct fp_info {
- Oid funcid;
- int nargs;
- bool argbyval[MAXFMGRARGS];
- int32 arglen[MAXFMGRARGS]; /* signed (for varlena) */
- bool retbyval;
- int32 retlen; /* signed (for varlena) */
- TransactionId xid;
- CommandId cid;
+struct fp_info
+{
+ Oid funcid;
+ int nargs;
+ bool argbyval[MAXFMGRARGS];
+ int32 arglen[MAXFMGRARGS]; /* signed (for varlena) */
+ bool retbyval;
+ int32 retlen; /* signed (for varlena) */
+ TransactionId xid;
+ CommandId cid;
};
/*
- * We implement one-back caching here. If we need to do more, we can.
+ * We implement one-back caching here. If we need to do more, we can.
* Most routines in tight loops (like PQfswrite -> F_LOWRITE) will do
* the same thing repeatedly.
*/
-static struct fp_info last_fp = { InvalidOid };
+static struct fp_info last_fp = {InvalidOid};
/*
* valid_fp_info
*
* RETURNS:
- * 1 if the state in 'fip' is valid
- * 0 otherwise
+ * 1 if the state in 'fip' is valid
+ * 0 otherwise
*
* "valid" means:
* The saved state was either uninitialized, for another function,
- * or from a previous command. (Commands can do updates, which
- * may invalidate catalog entries for subsequent commands. This
+ * or from a previous command. (Commands can do updates, which
+ * may invalidate catalog entries for subsequent commands. This
* is overly pessimistic but since there is no smarter invalidation
* scheme...).
*/
static int
-valid_fp_info(Oid func_id, struct fp_info *fip)
+valid_fp_info(Oid func_id, struct fp_info * fip)
{
- Assert(OidIsValid(func_id));
- Assert(fip != (struct fp_info *) NULL);
-
- return(OidIsValid(fip->funcid) &&
- oideq(func_id, fip->funcid) &&
- TransactionIdIsCurrentTransactionId(fip->xid) &&
- CommandIdIsCurrentCommandId(fip->cid));
+ Assert(OidIsValid(func_id));
+ Assert(fip != (struct fp_info *) NULL);
+
+ return (OidIsValid(fip->funcid) &&
+ oideq(func_id, fip->funcid) &&
+ TransactionIdIsCurrentTransactionId(fip->xid) &&
+ CommandIdIsCurrentCommandId(fip->cid));
}
/*
@@ -170,79 +178,86 @@ valid_fp_info(Oid func_id, struct fp_info *fip)
* function 'func_id'.
*
* RETURNS:
- * The correct information in 'fip'. Sets 'fip->funcid' to
- * InvalidOid if an exception occurs.
+ * The correct information in 'fip'. Sets 'fip->funcid' to
+ * InvalidOid if an exception occurs.
*/
static void
-update_fp_info(Oid func_id, struct fp_info *fip)
+update_fp_info(Oid func_id, struct fp_info * fip)
{
- Oid *argtypes; /* an oid8 */
- Oid rettype;
- HeapTuple func_htp, type_htp;
- TypeTupleForm tp;
- Form_pg_proc pp;
- int i;
-
- Assert(OidIsValid(func_id));
- Assert(fip != (struct fp_info *) NULL);
-
- /*
- * Since the validity of this structure is determined by whether
- * the funcid is OK, we clear the funcid here. It must not be
- * set to the correct value until we are about to return with
- * a good struct fp_info, since we can be interrupted (i.e., with
- * an elog(WARN, ...)) at any time.
- */
- memset((char *) fip, 0, (int) sizeof(struct fp_info));
- fip->funcid = InvalidOid;
-
- func_htp = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func_id),
- 0,0,0);
- if (!HeapTupleIsValid(func_htp)) {
- elog(WARN, "update_fp_info: cache lookup for function %d failed",
- func_id);
- }
- pp = (Form_pg_proc) GETSTRUCT(func_htp);
- fip->nargs = pp->pronargs;
- rettype = pp->prorettype;
- argtypes = pp->proargtypes;
-
- for (i = 0; i < fip->nargs; ++i) {
- if (OidIsValid(argtypes[i])) {
- type_htp = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(argtypes[i]),
- 0,0,0);
- if (!HeapTupleIsValid(type_htp)) {
- elog(WARN, "update_fp_info: bad argument type %d for %d",
- argtypes[i], func_id);
- }
- tp = (TypeTupleForm) GETSTRUCT(type_htp);
- fip->argbyval[i] = tp->typbyval;
- fip->arglen[i] = tp->typlen;
- } /* else it had better be VAR_LENGTH_ARG */
- }
-
- if (OidIsValid(rettype)) {
- type_htp = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(rettype),
- 0,0,0);
- if (!HeapTupleIsValid(type_htp)) {
- elog(WARN, "update_fp_info: bad return type %d for %d",
- rettype, func_id);
+ Oid *argtypes; /* an oid8 */
+ Oid rettype;
+ HeapTuple func_htp,
+ type_htp;
+ TypeTupleForm tp;
+ Form_pg_proc pp;
+ int i;
+
+ Assert(OidIsValid(func_id));
+ Assert(fip != (struct fp_info *) NULL);
+
+ /*
+ * Since the validity of this structure is determined by whether the
+ * funcid is OK, we clear the funcid here. It must not be set to the
+ * correct value until we are about to return with a good struct
+ * fp_info, since we can be interrupted (i.e., with an elog(WARN,
+ * ...)) at any time.
+ */
+ memset((char *) fip, 0, (int) sizeof(struct fp_info));
+ fip->funcid = InvalidOid;
+
+ func_htp = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(func_id),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(func_htp))
+ {
+ elog(WARN, "update_fp_info: cache lookup for function %d failed",
+ func_id);
}
- tp = (TypeTupleForm) GETSTRUCT(type_htp);
- fip->retbyval = tp->typbyval;
- fip->retlen = tp->typlen;
- } /* else it had better by VAR_LENGTH_RESULT */
-
- fip->xid = GetCurrentTransactionId();
- fip->cid = GetCurrentCommandId();
-
- /*
- * This must be last!
- */
- fip->funcid = func_id;
+ pp = (Form_pg_proc) GETSTRUCT(func_htp);
+ fip->nargs = pp->pronargs;
+ rettype = pp->prorettype;
+ argtypes = pp->proargtypes;
+
+ for (i = 0; i < fip->nargs; ++i)
+ {
+ if (OidIsValid(argtypes[i]))
+ {
+ type_htp = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(argtypes[i]),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(type_htp))
+ {
+ elog(WARN, "update_fp_info: bad argument type %d for %d",
+ argtypes[i], func_id);
+ }
+ tp = (TypeTupleForm) GETSTRUCT(type_htp);
+ fip->argbyval[i] = tp->typbyval;
+ fip->arglen[i] = tp->typlen;
+ } /* else it had better be VAR_LENGTH_ARG */
+ }
+
+ if (OidIsValid(rettype))
+ {
+ type_htp = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(rettype),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(type_htp))
+ {
+ elog(WARN, "update_fp_info: bad return type %d for %d",
+ rettype, func_id);
+ }
+ tp = (TypeTupleForm) GETSTRUCT(type_htp);
+ fip->retbyval = tp->typbyval;
+ fip->retlen = tp->typlen;
+ } /* else it had better by VAR_LENGTH_RESULT */
+
+ fip->xid = GetCurrentTransactionId();
+ fip->cid = GetCurrentCommandId();
+
+ /*
+ * This must be last!
+ */
+ fip->funcid = func_id;
}
-
+
/*
* HandleFunctionRequest
@@ -251,104 +266,119 @@ update_fp_info(Oid func_id, struct fp_info *fip)
* This corresponds to the libpq protocol symbol "F".
*
* RETURNS:
- * nothing of significance.
- * All errors result in elog(WARN,...).
+ * nothing of significance.
+ * All errors result in elog(WARN,...).
*/
int
HandleFunctionRequest()
{
- Oid fid;
- int argsize;
- int nargs;
- char *arg[8];
- char *retval;
- int i;
- uint32 palloced;
- char *p;
- struct fp_info *fip;
-
- fid = (Oid) pq_getint(4); /* function oid */
- nargs = pq_getint(4); /* # of arguments */
-
- /*
- * This is where the one-back caching is done.
- * If you want to save more state, make this a loop around an array.
- */
- fip = &last_fp;
- if (!valid_fp_info(fid, fip)) {
- update_fp_info(fid, fip);
- }
-
- if (fip->nargs != nargs) {
- elog(WARN, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
- nargs, fip->nargs);
- }
-
- /*
- * Copy arguments into arg vector. If we palloc() an argument, we need
- * to remember, so that we pfree() it after the call.
- */
- palloced = 0x0;
- for (i = 0; i < 8; ++i) {
- if (i >= nargs) {
- arg[i] = (char *) NULL;
- } else {
- argsize = pq_getint(4);
-
- Assert(argsize > 0);
- if (fip->argbyval[i]) { /* by-value */
- Assert(argsize <= 4);
- arg[i] = (char *) pq_getint(argsize);
- } else { /* by-reference ... */
- if (fip->arglen[i] < 0) { /* ... varlena */
- if (!(p = palloc(argsize + VARHDRSZ))) {
- elog(WARN, "HandleFunctionRequest: palloc failed");
- }
- VARSIZE(p) = argsize + VARHDRSZ;
- pq_getnchar(VARDATA(p), 0, argsize);
- } else { /* ... fixed */
- /* XXX cross our fingers and trust "argsize" */
- if (!(p = palloc(argsize))) {
- elog(WARN, "HandleFunctionRequest: palloc failed");
+ Oid fid;
+ int argsize;
+ int nargs;
+ char *arg[8];
+ char *retval;
+ int i;
+ uint32 palloced;
+ char *p;
+ struct fp_info *fip;
+
+ fid = (Oid) pq_getint(4); /* function oid */
+ nargs = pq_getint(4); /* # of arguments */
+
+ /*
+ * This is where the one-back caching is done. If you want to save
+ * more state, make this a loop around an array.
+ */
+ fip = &last_fp;
+ if (!valid_fp_info(fid, fip))
+ {
+ update_fp_info(fid, fip);
+ }
+
+ if (fip->nargs != nargs)
+ {
+ elog(WARN, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
+ nargs, fip->nargs);
+ }
+
+ /*
+ * Copy arguments into arg vector. If we palloc() an argument, we
+ * need to remember, so that we pfree() it after the call.
+ */
+ palloced = 0x0;
+ for (i = 0; i < 8; ++i)
+ {
+ if (i >= nargs)
+ {
+ arg[i] = (char *) NULL;
+ }
+ else
+ {
+ argsize = pq_getint(4);
+
+ Assert(argsize > 0);
+ if (fip->argbyval[i])
+ { /* by-value */
+ Assert(argsize <= 4);
+ arg[i] = (char *) pq_getint(argsize);
}
- pq_getnchar(p, 0, argsize);
- }
- palloced |= (1 << i);
- arg[i] = p;
- }
+ else
+ { /* by-reference ... */
+ if (fip->arglen[i] < 0)
+ { /* ... varlena */
+ if (!(p = palloc(argsize + VARHDRSZ)))
+ {
+ elog(WARN, "HandleFunctionRequest: palloc failed");
+ }
+ VARSIZE(p) = argsize + VARHDRSZ;
+ pq_getnchar(VARDATA(p), 0, argsize);
+ }
+ else
+ { /* ... fixed */
+ /* XXX cross our fingers and trust "argsize" */
+ if (!(p = palloc(argsize)))
+ {
+ elog(WARN, "HandleFunctionRequest: palloc failed");
+ }
+ pq_getnchar(p, 0, argsize);
+ }
+ palloced |= (1 << i);
+ arg[i] = p;
+ }
+ }
}
- }
#ifndef NO_FASTPATH
- retval = fmgr(fid,
- arg[0], arg[1], arg[2], arg[3],
- arg[4], arg[5], arg[6], arg[7]);
+ retval = fmgr(fid,
+ arg[0], arg[1], arg[2], arg[3],
+ arg[4], arg[5], arg[6], arg[7]);
#else
- retval = NULL;
-#endif /* NO_FASTPATH */
-
- /* free palloc'ed arguments */
- for (i = 0; i < nargs; ++i) {
- if (palloced & (1 << i))
- pfree(arg[i]);
- }
-
- /*
- * If this is an ordinary query (not a retrieve portal p ...), then
- * we return the data to the user. If the return value was palloc'ed,
- * then it must also be freed.
- */
+ retval = NULL;
+#endif /* NO_FASTPATH */
+
+ /* free palloc'ed arguments */
+ for (i = 0; i < nargs; ++i)
+ {
+ if (palloced & (1 << i))
+ pfree(arg[i]);
+ }
+
+ /*
+ * If this is an ordinary query (not a retrieve portal p ...), then we
+ * return the data to the user. If the return value was palloc'ed,
+ * then it must also be freed.
+ */
#ifndef NO_FASTPATH
- SendFunctionResult(fid, retval, fip->retbyval, fip->retlen);
+ SendFunctionResult(fid, retval, fip->retbyval, fip->retlen);
#else
- SendFunctionResult(fid, retval, fip->retbyval, 0);
-#endif /* NO_FASTPATH */
+ SendFunctionResult(fid, retval, fip->retbyval, 0);
+#endif /* NO_FASTPATH */
+
+ if (!fip->retbyval)
+ pfree(retval);
+
- if (!fip->retbyval)
- pfree(retval);
-
-
- return(0);
+ return (0);
}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index cd658704f03..f70d30434bb 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* postgres.c--
- * POSTGRES C Backend Interface
+ * POSTGRES C Backend Interface
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.42 1997/08/19 21:34:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.43 1997/09/07 04:49:33 momjian Exp $
*
* NOTES
- * this is the "main" module of the postgres backend and
- * hence the main module of the "traffic cop".
+ * this is the "main" module of the postgres backend and
+ * hence the main module of the "traffic cop".
*
*-------------------------------------------------------------------------
*/
@@ -25,17 +25,17 @@
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.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
-#ifndef MAXHOSTNAMELEN /* for MAXHOSTNAMELEN under sco3.2v5.0.2 */
+#ifndef MAXHOSTNAMELEN /* for MAXHOSTNAMELEN under sco3.2v5.0.2 */
#include <sys/socket.h>
#endif
#include <errno.h>
#ifdef aix
#include <sys/select.h>
-#endif /* aix */
+#endif /* aix */
#include "postgres.h"
@@ -46,9 +46,9 @@
#include "lib/dllist.h"
#include "parser/catalog_utils.h"
-#include "parser/parse_query.h" /* for MakeTimeRange() */
+#include "parser/parse_query.h" /* for MakeTimeRange() */
#include "commands/async.h"
-#include "tcop/tcopprot.h" /* where declarations for this file go */
+#include "tcop/tcopprot.h" /* where declarations for this file go */
#include "optimizer/planner.h"
#include "tcop/tcopprot.h"
@@ -88,1488 +88,1623 @@
#include "libpq/libpq.h"
#include "libpq/pqsignal.h"
-#include "rewrite/rewriteHandler.h" /* for QueryRewrite() */
+#include "rewrite/rewriteHandler.h" /* for QueryRewrite() */
-static void quickdie(SIGNAL_ARGS);
+static void quickdie(SIGNAL_ARGS);
/* ----------------
- * global variables
+ * global variables
* ----------------
*/
-static bool DebugPrintQuery = false;
-static bool DebugPrintPlan = false;
-static bool DebugPrintParse = false;
-static bool DebugPrintRewrittenParsetree = false;
-/*static bool EnableRewrite = true; , never changes why have it*/
-CommandDest whereToSendOutput;
+static bool DebugPrintQuery = false;
+static bool DebugPrintPlan = false;
+static bool DebugPrintParse = false;
+static bool DebugPrintRewrittenParsetree = false;
+
+/*static bool EnableRewrite = true; , never changes why have it*/
+CommandDest whereToSendOutput;
#ifdef LOCK_MGR_DEBUG
-extern int lockDebug;
+extern int lockDebug;
+
#endif
-extern int lockingOff;
-extern int NBuffers;
+extern int lockingOff;
+extern int NBuffers;
-int dontExecute = 0;
-static int ShowStats;
-static bool IsEmptyQuery = false;
+int dontExecute = 0;
+static int ShowStats;
+static bool IsEmptyQuery = false;
-char relname[80]; /* current relation name */
+char relname[80]; /* current relation name */
#if defined(nextstep)
-jmp_buf Warn_restart;
-#define sigsetjmp(x,y) setjmp(x)
+jmp_buf Warn_restart;
+
+#define sigsetjmp(x,y) setjmp(x)
#define siglongjmp longjmp
#else
-sigjmp_buf Warn_restart;
-#endif /* defined(nextstep) */
-int InWarn;
-
-extern int NBuffers;
-
-static int EchoQuery = 0; /* default don't echo */
-time_t tim;
-char pg_pathname[256];
-static int ShowParserStats;
-static int ShowPlannerStats;
-int ShowExecutorStats;
-FILE *StatFp;
-
-typedef struct frontend {
- bool fn_connected;
- Port fn_port;
- FILE *fn_Pfin; /* the input fd */
- FILE *fn_Pfout; /* the output fd */
- bool fn_done; /* set after the frontend closes its connection */
-} FrontEnd;
-
-static Dllist* frontendList;
+sigjmp_buf Warn_restart;
+
+#endif /* defined(nextstep) */
+int InWarn;
+
+extern int NBuffers;
+
+static int EchoQuery = 0; /* default don't echo */
+time_t tim;
+char pg_pathname[256];
+static int ShowParserStats;
+static int ShowPlannerStats;
+int ShowExecutorStats;
+FILE *StatFp;
+
+typedef struct frontend
+{
+ bool fn_connected;
+ Port fn_port;
+ FILE *fn_Pfin; /* the input fd */
+ FILE *fn_Pfout; /* the output fd */
+ bool fn_done; /* set after the frontend closes its
+ * connection */
+} FrontEnd;
+
+static Dllist *frontendList;
/* ----------------
- * people who want to use EOF should #define DONTUSENEWLINE in
- * tcop/tcopdebug.h
+ * people who want to use EOF should #define DONTUSENEWLINE in
+ * tcop/tcopdebug.h
* ----------------
*/
#ifndef TCOP_DONTUSENEWLINE
-int UseNewLine = 1; /* Use newlines query delimiters (the default) */
+int UseNewLine = 1; /* Use newlines query delimiters (the
+ * default) */
+
#else
-int UseNewLine = 0; /* Use EOF as query delimiters */
-#endif /* TCOP_DONTUSENEWLINE */
+int UseNewLine = 0; /* Use EOF as query delimiters */
+
+#endif /* TCOP_DONTUSENEWLINE */
/* ----------------
- * bushy tree plan flag: if true planner will generate bushy-tree
- * plans
+ * bushy tree plan flag: if true planner will generate bushy-tree
+ * plans
* ----------------
*/
-int BushyPlanFlag = 0; /* default to false -- consider only left-deep trees */
+int BushyPlanFlag = 0; /* default to false -- consider
+ * only left-deep trees */
/*
** Flags for expensive function optimization -- JMH 3/9/92
*/
-int XfuncMode = 0;
+int XfuncMode = 0;
/*
* ----------------
- * Note: _exec_repeat_ defaults to 1 but may be changed
- * by a DEBUG command. If you set this to a large
- * number N, run a single query, and then set it
- * back to 1 and run N queries, you can get an idea
- * of how much time is being spent in the parser and
- * planner b/c in the first case this overhead only
- * happens once. -cim 6/9/91
+ * Note: _exec_repeat_ defaults to 1 but may be changed
+ * by a DEBUG command. If you set this to a large
+ * number N, run a single query, and then set it
+ * back to 1 and run N queries, you can get an idea
+ * of how much time is being spent in the parser and
+ * planner b/c in the first case this overhead only
+ * happens once. -cim 6/9/91
* ----------------
*/
-int _exec_repeat_ = 1;
+int _exec_repeat_ = 1;
/* ----------------------------------------------------------------
- * decls for routines only used in this file
+ * decls for routines only used in this file
* ----------------------------------------------------------------
*/
-static char InteractiveBackend(char *inBuf);
-static char SocketBackend(char *inBuf, bool multiplexedBackend);
-static char ReadCommand(char *inBuf, bool multiplexedBackend);
+static char InteractiveBackend(char *inBuf);
+static char SocketBackend(char *inBuf, bool multiplexedBackend);
+static char ReadCommand(char *inBuf, bool multiplexedBackend);
/* ----------------------------------------------------------------
- * routines to obtain user input
+ * routines to obtain user input
* ----------------------------------------------------------------
*/
/* ----------------
- * InteractiveBackend() is called for user interactive connections
- * the string entered by the user is placed in its parameter inBuf.
+ * InteractiveBackend() is called for user interactive connections
+ * the string entered by the user is placed in its parameter inBuf.
* ----------------
*/
static char
InteractiveBackend(char *inBuf)
{
- char *stuff = inBuf; /* current place in input buffer */
- int c; /* character read from getc() */
- bool end = false; /* end-of-input flag */
- bool backslashSeen = false; /* have we seen a \ ? */
-
- /* ----------------
- * display a prompt and obtain input from the user
- * ----------------
- */
- printf("> ");
-
- for (;;) {
- if (UseNewLine) {
- /* ----------------
- * if we are using \n as a delimiter, then read
- * characters until the \n.
- * ----------------
- */
- while ( (c = getc(stdin)) != EOF) {
- if (c == '\n') {
- if (backslashSeen) {
- stuff--;
- continue;
- } else {
- /* keep the newline character */
- *stuff++ = '\n';
- *stuff++ = '\0';
- break;
- }
- } else if (c == '\\')
- backslashSeen = true;
- else
- backslashSeen = false;
-
- *stuff++ = (char)c;
- }
-
- if (c == EOF)
- end = true;
- } else {
- /* ----------------
- * otherwise read characters until EOF.
- * ----------------
- */
- while ( (c = getc(stdin)) != EOF )
- *stuff++ = (char)c;
-
- if ( stuff == inBuf )
- end = true;
- }
-
- if (end) {
- if (!Quiet) puts("EOF");
- IsEmptyQuery = true;
- exitpg(0);
- }
-
- /* ----------------
- * otherwise we have a user query so process it.
- * ----------------
- */
- break;
- }
-
- /* ----------------
- * if the query echo flag was given, print the query..
- * ----------------
- */
- if (EchoQuery)
- printf("query is: %s\n", inBuf);
-
- return('Q');
+ char *stuff = inBuf; /* current place in input buffer */
+ int c; /* character read from getc() */
+ bool end = false;/* end-of-input flag */
+ bool backslashSeen = false; /* have we seen a \ ? */
+
+ /* ----------------
+ * display a prompt and obtain input from the user
+ * ----------------
+ */
+ printf("> ");
+
+ for (;;)
+ {
+ if (UseNewLine)
+ {
+ /* ----------------
+ * if we are using \n as a delimiter, then read
+ * characters until the \n.
+ * ----------------
+ */
+ while ((c = getc(stdin)) != EOF)
+ {
+ if (c == '\n')
+ {
+ if (backslashSeen)
+ {
+ stuff--;
+ continue;
+ }
+ else
+ {
+ /* keep the newline character */
+ *stuff++ = '\n';
+ *stuff++ = '\0';
+ break;
+ }
+ }
+ else if (c == '\\')
+ backslashSeen = true;
+ else
+ backslashSeen = false;
+
+ *stuff++ = (char) c;
+ }
+
+ if (c == EOF)
+ end = true;
+ }
+ else
+ {
+ /* ----------------
+ * otherwise read characters until EOF.
+ * ----------------
+ */
+ while ((c = getc(stdin)) != EOF)
+ *stuff++ = (char) c;
+
+ if (stuff == inBuf)
+ end = true;
+ }
+
+ if (end)
+ {
+ if (!Quiet)
+ puts("EOF");
+ IsEmptyQuery = true;
+ exitpg(0);
+ }
+
+ /* ----------------
+ * otherwise we have a user query so process it.
+ * ----------------
+ */
+ break;
+ }
+
+ /* ----------------
+ * if the query echo flag was given, print the query..
+ * ----------------
+ */
+ if (EchoQuery)
+ printf("query is: %s\n", inBuf);
+
+ return ('Q');
}
/* ----------------
- * SocketBackend() Is called for frontend-backend connections
+ * SocketBackend() Is called for frontend-backend connections
*
- * If the input is a query (case 'Q') then the string entered by
- * the user is placed in its parameter inBuf.
+ * If the input is a query (case 'Q') then the string entered by
+ * the user is placed in its parameter inBuf.
*
- * If the input is a fastpath function call (case 'F') then
- * the function call is processed in HandleFunctionRequest().
- * (now called from PostgresMain())
+ * If the input is a fastpath function call (case 'F') then
+ * the function call is processed in HandleFunctionRequest().
+ * (now called from PostgresMain())
* ----------------
*/
static char
SocketBackend(char *inBuf, bool multiplexedBackend)
{
- char qtype[2];
- char result = '\0';
-
- /* ----------------
- * get input from the frontend
- * ----------------
- */
- strcpy(qtype, "?");
- if (pq_getnchar(qtype,0,1) == EOF) {
- /* ------------
- * when front-end applications quits/dies
- * ------------
- */
- if (multiplexedBackend) {
- return 'X';
- }
- else
- exitpg(0);
- }
-
- switch(*qtype) {
- /* ----------------
- * 'Q': user entered a query
- * ----------------
- */
- case 'Q':
- pq_getstr(inBuf, MAX_PARSE_BUFFER);
- result = 'Q';
- break;
-
- /* ----------------
- * 'F': calling user/system functions
- * ----------------
- */
- case 'F':
- pq_getstr(inBuf, MAX_PARSE_BUFFER);/* ignore the rest of the line */
- result = 'F';
- break;
-
- /* ----------------
- * 'X': frontend is exiting
- * ----------------
- */
- case 'X':
- result = 'X';
- break;
-
- /* ----------------
- * otherwise we got garbage from the frontend.
- *
- * XXX are we certain that we want to do an elog(FATAL) here?
- * -cim 1/24/90
- * ----------------
- */
- default:
- elog(FATAL, "Socket command type %c unknown\n", *qtype);
- break;
- }
- return result;
+ char qtype[2];
+ char result = '\0';
+
+ /* ----------------
+ * get input from the frontend
+ * ----------------
+ */
+ strcpy(qtype, "?");
+ if (pq_getnchar(qtype, 0, 1) == EOF)
+ {
+ /* ------------
+ * when front-end applications quits/dies
+ * ------------
+ */
+ if (multiplexedBackend)
+ {
+ return 'X';
+ }
+ else
+ exitpg(0);
+ }
+
+ switch (*qtype)
+ {
+ /* ----------------
+ * 'Q': user entered a query
+ * ----------------
+ */
+ case 'Q':
+ pq_getstr(inBuf, MAX_PARSE_BUFFER);
+ result = 'Q';
+ break;
+
+ /* ----------------
+ * 'F': calling user/system functions
+ * ----------------
+ */
+ case 'F':
+ pq_getstr(inBuf, MAX_PARSE_BUFFER); /* ignore the rest of the
+ * line */
+ result = 'F';
+ break;
+
+ /* ----------------
+ * 'X': frontend is exiting
+ * ----------------
+ */
+ case 'X':
+ result = 'X';
+ break;
+
+ /* ----------------
+ * otherwise we got garbage from the frontend.
+ *
+ * XXX are we certain that we want to do an elog(FATAL) here?
+ * -cim 1/24/90
+ * ----------------
+ */
+ default:
+ elog(FATAL, "Socket command type %c unknown\n", *qtype);
+ break;
+ }
+ return result;
}
/* ----------------
- * ReadCommand reads a command from either the frontend or
- * standard input, places it in inBuf, and returns a char
- * representing whether the string is a 'Q'uery or a 'F'astpath
- * call.
+ * ReadCommand reads a command from either the frontend or
+ * standard input, places it in inBuf, and returns a char
+ * representing whether the string is a 'Q'uery or a 'F'astpath
+ * call.
* ----------------
*/
static char
ReadCommand(char *inBuf, bool multiplexedBackend)
{
- if (IsUnderPostmaster || multiplexedBackend)
- return SocketBackend(inBuf, multiplexedBackend);
- else
- return InteractiveBackend(inBuf);
+ if (IsUnderPostmaster || multiplexedBackend)
+ return SocketBackend(inBuf, multiplexedBackend);
+ else
+ return InteractiveBackend(inBuf);
}
-List *
-pg_plan(char *query_string, /* string to execute */
- Oid *typev, /* argument types */
- int nargs, /* number of arguments */
- QueryTreeList **queryListP, /* pointer to the parse trees */
- CommandDest dest) /* where results should go */
+List *
+pg_plan(char *query_string, /* string to execute */
+ Oid * typev, /* argument types */
+ int nargs, /* number of arguments */
+ QueryTreeList ** queryListP, /* pointer to the parse trees */
+ CommandDest dest) /* where results should go */
{
- QueryTreeList *querytree_list;
- int i;
- List *plan_list = NIL;
- Plan *plan;
- int j;
- QueryTreeList *new_list;
- List *rewritten = NIL;
- Query* querytree;
-
- /* ----------------
- * (1) parse the request string into a list of parse trees
- * ----------------
- */
- if (ShowParserStats)
- ResetUsage();
-
- querytree_list = parser(query_string, typev, nargs);
-
- if (ShowParserStats) {
- fprintf(stderr, "! Parser Stats:\n");
- ShowUsage();
- }
-
- /* new_list holds the rewritten queries */
- new_list = (QueryTreeList*)malloc(sizeof(QueryTreeList));
- new_list->len = querytree_list->len;
- new_list->qtrees = (Query**)malloc(new_list->len * sizeof(Query*));
-
- /* ----------------
- * (2) rewrite the queries, as necessary
- * ----------------
- */
- j = 0; /* counter for the new_list, new_list can be longer than
- old list as a result of rewrites */
- for (i=0;i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
-
- /* don't rewrite utilites */
- if (querytree->commandType == CMD_UTILITY) {
- new_list->qtrees[j++] = querytree;
- continue;
- }
-
- if ( DebugPrintQuery == true ) {
- printf("\n---- \tquery is:\n%s\n",query_string);
- printf("\n");
- fflush(stdout);
- }
-
- if ( DebugPrintParse == true ) {
- printf("\n---- \tparser outputs :\n");
- nodeDisplay(querytree);
- printf("\n");
- }
-
- /* rewrite queries (retrieve, append, delete, replace) */
- rewritten = QueryRewrite(querytree);
- if (rewritten != NULL) {
- int len, k;
- len = length(rewritten);
- if (len == 1)
- new_list->qtrees[j++] = (Query*)lfirst(rewritten);
- else {
- /* rewritten queries are longer than original query */
- /* grow the new_list to accommodate */
- new_list->len += len - 1; /* - 1 because originally we
- allocated one space for the query */
- new_list->qtrees = realloc(new_list->qtrees,
- new_list->len * sizeof(Query*));
- for (k=0;k<len;k++)
- new_list->qtrees[j++] = (Query*)nth(k, rewritten);
- }
- }
- }
-
- /* we're done with the original lists, free it */
- free(querytree_list->qtrees);
- free(querytree_list);
-
- querytree_list = new_list;
-
- /* ----------------
- * Fix time range quals
- * this _must_ go here, because it must take place after rewrites
- * ( if they take place ) so that time quals are usable by the executor
- *
- * Also, need to frob the range table entries here to plan union
- * queries for archived relations.
- * ----------------
- */
- for (i=0;i<querytree_list->len;i++) {
- List *l;
- List *rt = NULL;
-
- querytree = querytree_list->qtrees[i];
-
- /* ----------------
- * utilities don't have time ranges
- * ----------------
- */
- if (querytree->commandType == CMD_UTILITY)
- continue;
-
- rt = querytree->rtable;
-
- foreach (l, rt) {
- RangeTblEntry *rte = lfirst(l);
- TimeRange *timequal = rte->timeRange;
-
- if (timequal) {
- int timecode = (rte->timeRange->endDate == NULL)? 0 : 1;
-
- rte->timeQual = makeTimeRange(rte->timeRange->startDate,
- rte->timeRange->endDate,
- timecode);
- }else {
- rte->timeQual = NULL;
- }
- }
-
- /* check for archived relations */
- plan_archive(rt);
- }
-
- if (DebugPrintRewrittenParsetree == true) {
- printf("\n---- \tafter rewriting:\n");
-
- for (i=0; i<querytree_list->len; i++) {
- print(querytree_list->qtrees[i]);
- printf("\n");
- }
- }
-
- for (i=0; i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
- /*
- * For each query that isn't a utility invocation,
- * generate a plan.
- */
-
- if (querytree->commandType != CMD_UTILITY) {
-
- if (IsAbortedTransactionBlockState()) {
- /* ----------------
- * the EndCommand() stuff is to tell the frontend
- * that the command ended. -cim 6/1/90
- * ----------------
- */
- char *tag = "*ABORT STATE*";
- EndCommand(tag, dest);
-
- elog(NOTICE, "(transaction aborted): %s",
- "queries ignored until END");
-
- *queryListP = (QueryTreeList*)NULL;
- return (List*)NULL;
- }
-
- if (ShowPlannerStats) ResetUsage();
- plan = planner(querytree);
- if (ShowPlannerStats) {
- fprintf(stderr, "! Planner Stats:\n");
- ShowUsage();
- }
- plan_list = lappend(plan_list, plan);
+ QueryTreeList *querytree_list;
+ int i;
+ List *plan_list = NIL;
+ Plan *plan;
+ int j;
+ QueryTreeList *new_list;
+ List *rewritten = NIL;
+ Query *querytree;
+
+ /* ----------------
+ * (1) parse the request string into a list of parse trees
+ * ----------------
+ */
+ if (ShowParserStats)
+ ResetUsage();
+
+ querytree_list = parser(query_string, typev, nargs);
+
+ if (ShowParserStats)
+ {
+ fprintf(stderr, "! Parser Stats:\n");
+ ShowUsage();
+ }
+
+ /* new_list holds the rewritten queries */
+ new_list = (QueryTreeList *) malloc(sizeof(QueryTreeList));
+ new_list->len = querytree_list->len;
+ new_list->qtrees = (Query **) malloc(new_list->len * sizeof(Query *));
+
+ /* ----------------
+ * (2) rewrite the queries, as necessary
+ * ----------------
+ */
+ j = 0; /* counter for the new_list, new_list can
+ * be longer than old list as a result of
+ * rewrites */
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
+
+ /* don't rewrite utilites */
+ if (querytree->commandType == CMD_UTILITY)
+ {
+ new_list->qtrees[j++] = querytree;
+ continue;
+ }
+
+ if (DebugPrintQuery == true)
+ {
+ printf("\n---- \tquery is:\n%s\n", query_string);
+ printf("\n");
+ fflush(stdout);
+ }
+
+ if (DebugPrintParse == true)
+ {
+ printf("\n---- \tparser outputs :\n");
+ nodeDisplay(querytree);
+ printf("\n");
+ }
+
+ /* rewrite queries (retrieve, append, delete, replace) */
+ rewritten = QueryRewrite(querytree);
+ if (rewritten != NULL)
+ {
+ int len,
+ k;
+
+ len = length(rewritten);
+ if (len == 1)
+ new_list->qtrees[j++] = (Query *) lfirst(rewritten);
+ else
+ {
+ /* rewritten queries are longer than original query */
+ /* grow the new_list to accommodate */
+ new_list->len += len - 1; /* - 1 because originally
+ * we allocated one space
+ * for the query */
+ new_list->qtrees = realloc(new_list->qtrees,
+ new_list->len * sizeof(Query *));
+ for (k = 0; k < len; k++)
+ new_list->qtrees[j++] = (Query *) nth(k, rewritten);
+ }
+ }
+ }
+
+ /* we're done with the original lists, free it */
+ free(querytree_list->qtrees);
+ free(querytree_list);
+
+ querytree_list = new_list;
+
+ /* ----------------
+ * Fix time range quals
+ * this _must_ go here, because it must take place after rewrites
+ * ( if they take place ) so that time quals are usable by the executor
+ *
+ * Also, need to frob the range table entries here to plan union
+ * queries for archived relations.
+ * ----------------
+ */
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ List *l;
+ List *rt = NULL;
+
+ querytree = querytree_list->qtrees[i];
+
+ /* ----------------
+ * utilities don't have time ranges
+ * ----------------
+ */
+ if (querytree->commandType == CMD_UTILITY)
+ continue;
+
+ rt = querytree->rtable;
+
+ foreach(l, rt)
+ {
+ RangeTblEntry *rte = lfirst(l);
+ TimeRange *timequal = rte->timeRange;
+
+ if (timequal)
+ {
+ int timecode = (rte->timeRange->endDate == NULL) ? 0 : 1;
+
+ rte->timeQual = makeTimeRange(rte->timeRange->startDate,
+ rte->timeRange->endDate,
+ timecode);
+ }
+ else
+ {
+ rte->timeQual = NULL;
+ }
+ }
+
+ /* check for archived relations */
+ plan_archive(rt);
+ }
+
+ if (DebugPrintRewrittenParsetree == true)
+ {
+ printf("\n---- \tafter rewriting:\n");
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ print(querytree_list->qtrees[i]);
+ printf("\n");
+ }
+ }
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
+ /*
+ * For each query that isn't a utility invocation, generate a
+ * plan.
+ */
+
+ if (querytree->commandType != CMD_UTILITY)
+ {
+
+ if (IsAbortedTransactionBlockState())
+ {
+ /* ----------------
+ * the EndCommand() stuff is to tell the frontend
+ * that the command ended. -cim 6/1/90
+ * ----------------
+ */
+ char *tag = "*ABORT STATE*";
+
+ EndCommand(tag, dest);
+
+ elog(NOTICE, "(transaction aborted): %s",
+ "queries ignored until END");
+
+ *queryListP = (QueryTreeList *) NULL;
+ return (List *) NULL;
+ }
+
+ if (ShowPlannerStats)
+ ResetUsage();
+ plan = planner(querytree);
+ if (ShowPlannerStats)
+ {
+ fprintf(stderr, "! Planner Stats:\n");
+ ShowUsage();
+ }
+ plan_list = lappend(plan_list, plan);
#ifdef INDEXSCAN_PATCH
- /* ----------------
- * Print plan if debugging.
- * This has been moved here to get debugging output
- * also for queries in functions. DZ - 27-8-1996
- * ----------------
- */
- if ( DebugPrintPlan == true ) {
- printf("\n---- \tplan is :\n");
- nodeDisplay(plan);
- printf("\n");
- }
+ /* ----------------
+ * Print plan if debugging.
+ * This has been moved here to get debugging output
+ * also for queries in functions. DZ - 27-8-1996
+ * ----------------
+ */
+ if (DebugPrintPlan == true)
+ {
+ printf("\n---- \tplan is :\n");
+ nodeDisplay(plan);
+ printf("\n");
+ }
#endif
- }
+ }
#ifdef FUNC_UTIL_PATCH
- /*
- * If the command is an utility append a null plan. This is
- * needed to keep the plan_list aligned with the querytree_list
- * or the function executor will crash. DZ - 30-8-1996
- */
- else {
- plan_list = lappend(plan_list, NULL);
- }
+
+ /*
+ * If the command is an utility append a null plan. This is needed
+ * to keep the plan_list aligned with the querytree_list or the
+ * function executor will crash. DZ - 30-8-1996
+ */
+ else
+ {
+ plan_list = lappend(plan_list, NULL);
+ }
#endif
- }
-
- if (queryListP)
- *queryListP = querytree_list;
-
- return (plan_list);
+ }
+
+ if (queryListP)
+ *queryListP = querytree_list;
+
+ return (plan_list);
}
/* ----------------------------------------------------------------
- * pg_eval()
- *
- * Takes a querystring, runs the parser/utilities or
- * parser/planner/executor over it as necessary
- * Begin Transaction Should have been called before this
- * and CommitTransaction After this is called
- * This is strictly because we do not allow for nested xactions.
+ * pg_eval()
+ *
+ * Takes a querystring, runs the parser/utilities or
+ * parser/planner/executor over it as necessary
+ * Begin Transaction Should have been called before this
+ * and CommitTransaction After this is called
+ * This is strictly because we do not allow for nested xactions.
*
- * NON-OBVIOUS-RESTRICTIONS
- * this function _MUST_ allocate a new "parsetree" each time,
- * since it may be stored in a named portal and should not
- * change its value.
+ * NON-OBVIOUS-RESTRICTIONS
+ * this function _MUST_ allocate a new "parsetree" each time,
+ * since it may be stored in a named portal and should not
+ * change its value.
*
* ----------------------------------------------------------------
*/
void
-pg_eval(char *query_string, char **argv, Oid *typev, int nargs)
+pg_eval(char *query_string, char **argv, Oid * typev, int nargs)
{
- pg_eval_dest(query_string, argv, typev, nargs, whereToSendOutput);
+ pg_eval_dest(query_string, argv, typev, nargs, whereToSendOutput);
}
void
-pg_eval_dest(char *query_string, /* string to execute */
- char **argv, /* arguments */
- Oid *typev, /* argument types */
- int nargs, /* number of arguments */
- CommandDest dest) /* where results should go */
+pg_eval_dest(char *query_string,/* string to execute */
+ char **argv, /* arguments */
+ Oid * typev, /* argument types */
+ int nargs, /* number of arguments */
+ CommandDest dest) /* where results should go */
{
- List *plan_list;
- Plan *plan;
- Query *querytree;
- int i,j;
- QueryTreeList *querytree_list;
-
- /* plan the queries */
- plan_list = pg_plan(query_string, typev, nargs, &querytree_list, dest);
-
- /* pg_plan could have failed */
- if (querytree_list == NULL)
- return;
-
- for (i=0;i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
+ List *plan_list;
+ Plan *plan;
+ Query *querytree;
+ int i,
+ j;
+ QueryTreeList *querytree_list;
+
+ /* plan the queries */
+ plan_list = pg_plan(query_string, typev, nargs, &querytree_list, dest);
+
+ /* pg_plan could have failed */
+ if (querytree_list == NULL)
+ return;
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
#ifdef FUNC_UTIL_PATCH
- /*
- * Advance on the plan_list in every case. Now the plan_list
- * has the same length of the querytree_list. DZ - 30-8-1996
- */
- plan = (Plan *) lfirst(plan_list);
- plan_list = lnext(plan_list);
+
+ /*
+ * Advance on the plan_list in every case. Now the plan_list has
+ * the same length of the querytree_list. DZ - 30-8-1996
+ */
+ plan = (Plan *) lfirst(plan_list);
+ plan_list = lnext(plan_list);
#endif
- if (querytree->commandType == CMD_UTILITY) {
- /* ----------------
- * process utility functions (create, destroy, etc..)
- *
- * Note: we do not check for the transaction aborted state
- * because that is done in ProcessUtility.
- * ----------------
- */
- if (! Quiet) {
- time(&tim);
- printf("\tProcessUtility() at %s\n", ctime(&tim));
- }
-
- ProcessUtility(querytree->utilityStmt, dest);
-
- } else {
+ if (querytree->commandType == CMD_UTILITY)
+ {
+ /* ----------------
+ * process utility functions (create, destroy, etc..)
+ *
+ * Note: we do not check for the transaction aborted state
+ * because that is done in ProcessUtility.
+ * ----------------
+ */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tProcessUtility() at %s\n", ctime(&tim));
+ }
+
+ ProcessUtility(querytree->utilityStmt, dest);
+
+ }
+ else
+ {
#ifndef FUNC_UTIL_PATCH
- /*
- * Moved before the if. DZ - 30-8-1996
- */
- plan = (Plan *) lfirst(plan_list);
- plan_list = lnext(plan_list);
+
+ /*
+ * Moved before the if. DZ - 30-8-1996
+ */
+ plan = (Plan *) lfirst(plan_list);
+ plan_list = lnext(plan_list);
#endif
-
+
#ifdef INDEXSCAN_PATCH
- /*
- * Print moved in pg_plan. DZ - 27-8-1996
- */
+
+ /*
+ * Print moved in pg_plan. DZ - 27-8-1996
+ */
#else
- /* ----------------
- * print plan if debugging
- * ----------------
- */
- if ( DebugPrintPlan == true ) {
- printf("\n---- plan is :\n");
- nodeDisplay(plan);
- printf("\n");
- }
+ /* ----------------
+ * print plan if debugging
+ * ----------------
+ */
+ if (DebugPrintPlan == true)
+ {
+ printf("\n---- plan is :\n");
+ nodeDisplay(plan);
+ printf("\n");
+ }
#endif
-
- /* ----------------
- * execute the plan
- *
- */
- if (ShowExecutorStats)
- ResetUsage();
-
- for (j = 0; j < _exec_repeat_; j++) {
- if (! Quiet) {
- time(&tim);
- printf("\tProcessQuery() at %s\n", ctime(&tim));
- }
- ProcessQuery(querytree, plan, argv, typev, nargs, dest);
- }
-
- if (ShowExecutorStats) {
- fprintf(stderr, "! Executor Stats:\n");
- ShowUsage();
- }
- }
- /*
- * In a query block, we want to increment the command counter
- * between queries so that the effects of early queries are
- * visible to subsequent ones.
- */
-
- if (querytree_list)
- CommandCounterIncrement();
- }
-
- free(querytree_list->qtrees);
- free(querytree_list);
+
+ /* ----------------
+ * execute the plan
+ *
+ */
+ if (ShowExecutorStats)
+ ResetUsage();
+
+ for (j = 0; j < _exec_repeat_; j++)
+ {
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tProcessQuery() at %s\n", ctime(&tim));
+ }
+ ProcessQuery(querytree, plan, argv, typev, nargs, dest);
+ }
+
+ if (ShowExecutorStats)
+ {
+ fprintf(stderr, "! Executor Stats:\n");
+ ShowUsage();
+ }
+ }
+
+ /*
+ * In a query block, we want to increment the command counter
+ * between queries so that the effects of early queries are
+ * visible to subsequent ones.
+ */
+
+ if (querytree_list)
+ CommandCounterIncrement();
+ }
+
+ free(querytree_list->qtrees);
+ free(querytree_list);
}
/* --------------------------------
- * signal handler routines used in PostgresMain()
+ * signal handler routines used in PostgresMain()
*
- * handle_warn() is used to catch kill(getpid(),1) which
- * occurs when elog(WARN) is called.
+ * handle_warn() is used to catch kill(getpid(),1) which
+ * occurs when elog(WARN) is called.
*
- * quickdie() occurs when signalled by the postmaster, some backend
- * has bought the farm we need to stop what we're doing and exit.
+ * quickdie() occurs when signalled by the postmaster, some backend
+ * has bought the farm we need to stop what we're doing and exit.
*
- * die() preforms an orderly cleanup via ExitPostgres()
+ * die() preforms an orderly cleanup via ExitPostgres()
* --------------------------------
*/
void
handle_warn(SIGNAL_ARGS)
{
- siglongjmp(Warn_restart, 1);
+ siglongjmp(Warn_restart, 1);
}
static void
quickdie(SIGNAL_ARGS)
{
- elog(NOTICE, "I have been signalled by the postmaster.");
- elog(NOTICE, "Some backend process has died unexpectedly and possibly");
- elog(NOTICE, "corrupted shared memory. The current transaction was");
- elog(NOTICE, "aborted, and I am going to exit. Please resend the");
- elog(NOTICE, "last query. -- The postgres backend");
-
- /*
- * DO NOT ExitPostgres(0) -- we're here because shared memory may be
- * corrupted, so we don't want to flush any shared state to stable
- * storage. Just nail the windows shut and get out of town.
- */
-
- exit (0);
+ elog(NOTICE, "I have been signalled by the postmaster.");
+ elog(NOTICE, "Some backend process has died unexpectedly and possibly");
+ elog(NOTICE, "corrupted shared memory. The current transaction was");
+ elog(NOTICE, "aborted, and I am going to exit. Please resend the");
+ elog(NOTICE, "last query. -- The postgres backend");
+
+ /*
+ * DO NOT ExitPostgres(0) -- we're here because shared memory may be
+ * corrupted, so we don't want to flush any shared state to stable
+ * storage. Just nail the windows shut and get out of town.
+ */
+
+ exit(0);
}
void
die(SIGNAL_ARGS)
{
- ExitPostgres(0);
+ ExitPostgres(0);
}
/* signal handler for floating point exception */
static void
FloatExceptionHandler(SIGNAL_ARGS)
{
- elog(WARN, "floating point exception! the last floating point operation eit\
+ elog(WARN, "floating point exception! the last floating point operation eit\
her exceeded legal ranges or was a divide by zero");
}
-static void usage(char* progname)
+static void
+usage(char *progname)
{
- fprintf(stderr,
- "Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
- progname);
- fprintf(stderr,"\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
- fprintf(stderr, " b: consider bushy plan trees during optimization\n");
- fprintf(stderr, " B: set number of buffers in buffer pool\n");
- fprintf(stderr, " C: supress version info\n");
- fprintf(stderr, " d: set debug level\n");
- fprintf(stderr, " E: echo query before execution\n");
- fprintf(stderr, " e turn on European date format\n");
- fprintf(stderr, " F: turn off fsync\n");
- fprintf(stderr, " f: forbid plantype generation\n");
- fprintf(stderr, " i: don't execute the query, just show the plan tree\n");
+ fprintf(stderr,
+ "Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
+ progname);
+ fprintf(stderr, "\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
+ fprintf(stderr, " b: consider bushy plan trees during optimization\n");
+ fprintf(stderr, " B: set number of buffers in buffer pool\n");
+ fprintf(stderr, " C: supress version info\n");
+ fprintf(stderr, " d: set debug level\n");
+ fprintf(stderr, " E: echo query before execution\n");
+ fprintf(stderr, " e turn on European date format\n");
+ fprintf(stderr, " F: turn off fsync\n");
+ fprintf(stderr, " f: forbid plantype generation\n");
+ fprintf(stderr, " i: don't execute the query, just show the plan tree\n");
#ifdef LOCK_MGR_DEBUG
- fprintf(stderr, " K: set locking debug level [0|1|2]\n");
+ fprintf(stderr, " K: set locking debug level [0|1|2]\n");
#endif
- fprintf(stderr, " L: turn off locking\n");
- fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
- fprintf(stderr, " M: start as postmaster\n");
- fprintf(stderr, " N: don't use newline as query delimiter\n");
- fprintf(stderr, " o: send stdout and stderr to given filename \n");
- fprintf(stderr, " p: backend started by postmaster\n");
- fprintf(stderr, " P: set port file descriptor\n");
- fprintf(stderr, " Q: suppress informational messages\n");
- fprintf(stderr, " S: set amount of sort memory available\n");
- fprintf(stderr, " s: show stats after each query\n");
- fprintf(stderr, " t: trace component execution times\n");
- fprintf(stderr, " T: execute all possible plans for each query\n");
- fprintf(stderr, " x: control expensive function optimization\n");
+ fprintf(stderr, " L: turn off locking\n");
+ fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
+ fprintf(stderr, " M: start as postmaster\n");
+ fprintf(stderr, " N: don't use newline as query delimiter\n");
+ fprintf(stderr, " o: send stdout and stderr to given filename \n");
+ fprintf(stderr, " p: backend started by postmaster\n");
+ fprintf(stderr, " P: set port file descriptor\n");
+ fprintf(stderr, " Q: suppress informational messages\n");
+ fprintf(stderr, " S: set amount of sort memory available\n");
+ fprintf(stderr, " s: show stats after each query\n");
+ fprintf(stderr, " t: trace component execution times\n");
+ fprintf(stderr, " T: execute all possible plans for each query\n");
+ fprintf(stderr, " x: control expensive function optimization\n");
}
/* ----------------------------------------------------------------
- * PostgresMain
- * postgres main loop
- * all backends, interactive or otherwise start here
+ * PostgresMain
+ * postgres main loop
+ * all backends, interactive or otherwise start here
* ----------------------------------------------------------------
*/
int
PostgresMain(int argc, char *argv[])
{
- int flagC;
- int flagQ;
- int flagE;
- int flagEu;
- int flag;
-
- char *DBName = NULL;
- int errs = 0;
-
- char firstchar;
- char parser_input[MAX_PARSE_BUFFER];
- char *userName;
-
- bool multiplexedBackend;
- char* hostName; /* the host name of the backend server */
- char hostbuf[MAXHOSTNAMELEN];
- int serverSock;
- int serverPortnum = 0;
- int nSelected; /* number of descriptors ready from select(); */
- int maxFd = 0; /* max file descriptor + 1 */
- fd_set rmask, basemask;
- FrontEnd *newFE, *currentFE = NULL;
- int numFE = 0; /* keep track of number of active frontends */
- Port *newPort;
- int newFd;
- Dlelem *curr;
- int status;
-
- extern int optind;
- extern char *optarg;
- extern short DebugLvl;
-
- /* ----------------
- * register signal handlers.
- * ----------------
- */
- pqsignal(SIGINT, die);
-
- pqsignal(SIGHUP, die);
- pqsignal(SIGTERM, die);
- pqsignal(SIGPIPE, die);
- pqsignal(SIGUSR1, quickdie);
- pqsignal(SIGUSR2, Async_NotifyHandler);
- pqsignal(SIGFPE, FloatExceptionHandler);
-
- /* --------------------
- * initialize globals
- * -------------------
- */
-
- MasterPid = getpid();
-
- /* ----------------
- * parse command line arguments
- * ----------------
- */
- flagC = flagQ = flagE = flagEu = ShowStats = 0;
- ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
+ int flagC;
+ int flagQ;
+ int flagE;
+ int flagEu;
+ int flag;
+
+ char *DBName = NULL;
+ int errs = 0;
+
+ char firstchar;
+ char parser_input[MAX_PARSE_BUFFER];
+ char *userName;
+
+ bool multiplexedBackend;
+ char *hostName; /* the host name of the backend server */
+ char hostbuf[MAXHOSTNAMELEN];
+ int serverSock;
+ int serverPortnum = 0;
+ int nSelected; /* number of descriptors ready from
+ * select(); */
+ int maxFd = 0; /* max file descriptor + 1 */
+ fd_set rmask,
+ basemask;
+ FrontEnd *newFE,
+ *currentFE = NULL;
+ int numFE = 0; /* keep track of number of active
+ * frontends */
+ Port *newPort;
+ int newFd;
+ Dlelem *curr;
+ int status;
+
+ extern int optind;
+ extern char *optarg;
+ extern short DebugLvl;
+
+ /* ----------------
+ * register signal handlers.
+ * ----------------
+ */
+ pqsignal(SIGINT, die);
+
+ pqsignal(SIGHUP, die);
+ pqsignal(SIGTERM, die);
+ pqsignal(SIGPIPE, die);
+ pqsignal(SIGUSR1, quickdie);
+ pqsignal(SIGUSR2, Async_NotifyHandler);
+ pqsignal(SIGFPE, FloatExceptionHandler);
+
+ /* --------------------
+ * initialize globals
+ * -------------------
+ */
+
+ MasterPid = getpid();
+
+ /* ----------------
+ * parse command line arguments
+ * ----------------
+ */
+ flagC = flagQ = flagE = flagEu = ShowStats = 0;
+ ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
#ifdef LOCK_MGR_DEBUG
- lockDebug = 0;
+ lockDebug = 0;
#endif
- /* get hostname is either the environment variable PGHOST
- or 'localhost' */
- if (!(hostName = getenv("PGHOST"))) {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
- DataDir = getenv("PGDATA"); /* default */
- multiplexedBackend = false; /* default */
-
- while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQSst:x:F"))
- != EOF)
- switch (flag) {
-
- case 'b':
- /* ----------------
- * set BushyPlanFlag to true.
- * ----------------
- */
- BushyPlanFlag = 1;
- break;
- case 'B':
- /* ----------------
- * specify the size of buffer pool
- * ----------------
- */
- NBuffers = atoi(optarg);
- break;
-
- case 'C':
- /* ----------------
- * don't print version string (don't know why this is 'C' --mao)
- * ----------------
- */
- flagC = 1;
- break;
-
- case 'D': /* PGDATA directory */
- DataDir = optarg;
-
- case 'd': /* debug level */
- flagQ = 0;
- DebugLvl = (short)atoi(optarg);
- if (DebugLvl > 1)
- DebugPrintQuery = true;
- if (DebugLvl > 2)
- {
- DebugPrintParse = true;
- DebugPrintPlan = true;
- DebugPrintRewrittenParsetree = true;
- }
- break;
-
- case 'E':
- /* ----------------
- * E - echo the query the user entered
- * ----------------
- */
- flagE = 1;
- break;
-
- case 'e':
- /* --------------------------
- * Use european date formats.
- * --------------------------
- */
- flagEu = 1;
- break;
-
- case 'F':
- /* --------------------
- * turn off fsync
- * --------------------
- */
- fsyncOff = 1;
- break;
-
- case 'f':
- /* -----------------
- * f - forbid generation of certain plans
- * -----------------
- */
- switch (optarg[0]) {
- case 's': /* seqscan */
- _enable_seqscan_ = false;
- break;
- case 'i': /* indexscan */
- _enable_indexscan_ = false;
- break;
- case 'n': /* nestloop */
- _enable_nestloop_ = false;
- break;
- case 'm': /* mergejoin */
- _enable_mergesort_ = false;
- break;
- case 'h': /* hashjoin */
- _enable_hashjoin_ = false;
- break;
- default:
- errs++;
- }
- break;
-
- case 'i':
- dontExecute = 1;
- break;
-
- case 'K':
+ /*
+ * get hostname is either the environment variable PGHOST or
+ * 'localhost'
+ */
+ if (!(hostName = getenv("PGHOST")))
+ {
+ if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
+ strcpy(hostbuf, "localhost");
+ hostName = hostbuf;
+ }
+
+ DataDir = getenv("PGDATA"); /* default */
+ multiplexedBackend = false; /* default */
+
+ while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQSst:x:F"))
+ != EOF)
+ switch (flag)
+ {
+
+ case 'b':
+ /* ----------------
+ * set BushyPlanFlag to true.
+ * ----------------
+ */
+ BushyPlanFlag = 1;
+ break;
+ case 'B':
+ /* ----------------
+ * specify the size of buffer pool
+ * ----------------
+ */
+ NBuffers = atoi(optarg);
+ break;
+
+ case 'C':
+ /* ----------------
+ * don't print version string (don't know why this is 'C' --mao)
+ * ----------------
+ */
+ flagC = 1;
+ break;
+
+ case 'D': /* PGDATA directory */
+ DataDir = optarg;
+
+ case 'd': /* debug level */
+ flagQ = 0;
+ DebugLvl = (short) atoi(optarg);
+ if (DebugLvl > 1)
+ DebugPrintQuery = true;
+ if (DebugLvl > 2)
+ {
+ DebugPrintParse = true;
+ DebugPrintPlan = true;
+ DebugPrintRewrittenParsetree = true;
+ }
+ break;
+
+ case 'E':
+ /* ----------------
+ * E - echo the query the user entered
+ * ----------------
+ */
+ flagE = 1;
+ break;
+
+ case 'e':
+ /* --------------------------
+ * Use european date formats.
+ * --------------------------
+ */
+ flagEu = 1;
+ break;
+
+ case 'F':
+ /* --------------------
+ * turn off fsync
+ * --------------------
+ */
+ fsyncOff = 1;
+ break;
+
+ case 'f':
+ /* -----------------
+ * f - forbid generation of certain plans
+ * -----------------
+ */
+ switch (optarg[0])
+ {
+ case 's': /* seqscan */
+ _enable_seqscan_ = false;
+ break;
+ case 'i': /* indexscan */
+ _enable_indexscan_ = false;
+ break;
+ case 'n': /* nestloop */
+ _enable_nestloop_ = false;
+ break;
+ case 'm': /* mergejoin */
+ _enable_mergesort_ = false;
+ break;
+ case 'h': /* hashjoin */
+ _enable_hashjoin_ = false;
+ break;
+ default:
+ errs++;
+ }
+ break;
+
+ case 'i':
+ dontExecute = 1;
+ break;
+
+ case 'K':
#ifdef LOCK_MGR_DEBUG
- lockDebug = atoi(optarg);
+ lockDebug = atoi(optarg);
#else
- fprintf(stderr, "Lock debug not compiled in\n");
+ fprintf(stderr, "Lock debug not compiled in\n");
#endif
- break;
-
- case 'L':
- /* --------------------
- * turn off locking
- * --------------------
- */
- lockingOff = 1;
- break;
-
- case 'm':
- /* start up a listening backend that can respond to
- multiple front-ends. (Note: all the front-end connections
- are still connected to a single-threaded backend. Requests
- are FCFS. Everything is in one transaction
- */
- multiplexedBackend = true;
- serverPortnum = atoi(optarg);
- break;
- case 'M':
- exit(PostmasterMain(argc, argv));
- break;
- case 'N':
- /* ----------------
- * N - Don't use newline as a query delimiter
- * ----------------
- */
- UseNewLine = 0;
- break;
-
- case 'o':
- /* ----------------
- * o - send output (stdout and stderr) to the given file
- * ----------------
- */
- strNcpy(OutputFileName, optarg, MAXPGPATH);
- break;
-
- case 'p': /* started by postmaster */
- /* ----------------
- * p - special flag passed if backend was forked
- * by a postmaster.
- * ----------------
- */
- IsUnderPostmaster = true;
- break;
-
- case 'P':
- /* ----------------
- * P - Use the passed file descriptor number as the port
- * on which to communicate with the user. This is ONLY
- * useful for debugging when fired up by the postmaster.
- * ----------------
- */
- Portfd = atoi(optarg);
- break;
-
- case 'Q':
- /* ----------------
- * Q - set Quiet mode (reduce debugging output)
- * ----------------
- */
- flagQ = 1;
- break;
-
- case 'S':
- /* ----------------
- * S - amount of sort memory to use in 1k bytes
- * ----------------
- */
- SortMem = atoi(optarg);
- break;
-
- case 's':
- /* ----------------
- * s - report usage statistics (timings) after each query
- * ----------------
- */
- ShowStats = 1;
- StatFp = stderr;
- break;
-
- case 't':
- /* ----------------
- * tell postgres to report usage statistics (timings) for
- * each query
- *
- * -tpa[rser] = print stats for parser time of each query
- * -tpl[anner] = print stats for planner time of each query
- * -te[xecutor] = print stats for executor time of each query
- * caution: -s can not be used together with -t.
- * ----------------
- */
- StatFp = stderr;
- switch (optarg[0]) {
- case 'p': if (optarg[1] == 'a')
- ShowParserStats = 1;
- else if (optarg[1] == 'l')
- ShowPlannerStats = 1;
- else
- errs++;
- break;
- case 'e': ShowExecutorStats = 1; break;
- default: errs++; break;
- }
- break;
-
- case 'x':
-#if 0 /* planner/xfunc.h */
- /* control joey hellerstein's expensive function optimization */
- if (XfuncMode != 0)
- {
- fprintf(stderr, "only one -x flag is allowed\n");
- errs++;
- break;
- }
- if (strcmp(optarg, "off") == 0)
- XfuncMode = XFUNC_OFF;
- else if (strcmp(optarg, "nor") == 0)
- XfuncMode = XFUNC_NOR;
- else if (strcmp(optarg, "nopull") == 0)
- XfuncMode = XFUNC_NOPULL;
- else if (strcmp(optarg, "nopm") == 0)
- XfuncMode = XFUNC_NOPM;
- else if (strcmp(optarg, "pullall") == 0)
- XfuncMode = XFUNC_PULLALL;
- else if (strcmp(optarg, "wait") == 0)
- XfuncMode = XFUNC_WAIT;
- else {
- fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
- errs++;
- }
+ break;
+
+ case 'L':
+ /* --------------------
+ * turn off locking
+ * --------------------
+ */
+ lockingOff = 1;
+ break;
+
+ case 'm':
+
+ /*
+ * start up a listening backend that can respond to multiple
+ * front-ends. (Note: all the front-end connections are
+ * still connected to a single-threaded backend. Requests are
+ * FCFS. Everything is in one transaction
+ */
+ multiplexedBackend = true;
+ serverPortnum = atoi(optarg);
+ break;
+ case 'M':
+ exit(PostmasterMain(argc, argv));
+ break;
+ case 'N':
+ /* ----------------
+ * N - Don't use newline as a query delimiter
+ * ----------------
+ */
+ UseNewLine = 0;
+ break;
+
+ case 'o':
+ /* ----------------
+ * o - send output (stdout and stderr) to the given file
+ * ----------------
+ */
+ strNcpy(OutputFileName, optarg, MAXPGPATH);
+ break;
+
+ case 'p': /* started by postmaster */
+ /* ----------------
+ * p - special flag passed if backend was forked
+ * by a postmaster.
+ * ----------------
+ */
+ IsUnderPostmaster = true;
+ break;
+
+ case 'P':
+ /* ----------------
+ * P - Use the passed file descriptor number as the port
+ * on which to communicate with the user. This is ONLY
+ * useful for debugging when fired up by the postmaster.
+ * ----------------
+ */
+ Portfd = atoi(optarg);
+ break;
+
+ case 'Q':
+ /* ----------------
+ * Q - set Quiet mode (reduce debugging output)
+ * ----------------
+ */
+ flagQ = 1;
+ break;
+
+ case 'S':
+ /* ----------------
+ * S - amount of sort memory to use in 1k bytes
+ * ----------------
+ */
+ SortMem = atoi(optarg);
+ break;
+
+ case 's':
+ /* ----------------
+ * s - report usage statistics (timings) after each query
+ * ----------------
+ */
+ ShowStats = 1;
+ StatFp = stderr;
+ break;
+
+ case 't':
+ /* ----------------
+ * tell postgres to report usage statistics (timings) for
+ * each query
+ *
+ * -tpa[rser] = print stats for parser time of each query
+ * -tpl[anner] = print stats for planner time of each query
+ * -te[xecutor] = print stats for executor time of each query
+ * caution: -s can not be used together with -t.
+ * ----------------
+ */
+ StatFp = stderr;
+ switch (optarg[0])
+ {
+ case 'p':
+ if (optarg[1] == 'a')
+ ShowParserStats = 1;
+ else if (optarg[1] == 'l')
+ ShowPlannerStats = 1;
+ else
+ errs++;
+ break;
+ case 'e':
+ ShowExecutorStats = 1;
+ break;
+ default:
+ errs++;
+ break;
+ }
+ break;
+
+ case 'x':
+#if 0 /* planner/xfunc.h */
+ /* control joey hellerstein's expensive function optimization */
+ if (XfuncMode != 0)
+ {
+ fprintf(stderr, "only one -x flag is allowed\n");
+ errs++;
+ break;
+ }
+ if (strcmp(optarg, "off") == 0)
+ XfuncMode = XFUNC_OFF;
+ else if (strcmp(optarg, "nor") == 0)
+ XfuncMode = XFUNC_NOR;
+ else if (strcmp(optarg, "nopull") == 0)
+ XfuncMode = XFUNC_NOPULL;
+ else if (strcmp(optarg, "nopm") == 0)
+ XfuncMode = XFUNC_NOPM;
+ else if (strcmp(optarg, "pullall") == 0)
+ XfuncMode = XFUNC_PULLALL;
+ else if (strcmp(optarg, "wait") == 0)
+ XfuncMode = XFUNC_WAIT;
+ else
+ {
+ fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
+ errs++;
+ }
#endif
- break;
-
- default:
- /* ----------------
- * default: bad command line option
- * ----------------
- */
- errs++;
- }
-
- /* ----------------
- * get user name and pathname and check command line validity
- * ----------------
- */
- SetPgUserName();
- userName = GetPgUserName();
-
- if (FindBackend(pg_pathname, argv[0]) < 0)
- elog(FATAL, "%s: could not locate executable, bailing out...",
- argv[0]);
-
- if (errs || argc - optind > 1) {
- usage (argv[0]);
- exitpg(1);
- } else if (argc - optind == 1) {
- DBName = argv[optind];
- } else if ((DBName = userName) == NULL) {
- fprintf(stderr, "%s: USER undefined and no database specified\n",
- argv[0]);
- exitpg(1);
- }
-
- if (ShowStats &&
- (ShowParserStats || ShowPlannerStats || ShowExecutorStats)) {
- fprintf(stderr, "-s can not be used together with -t.\n");
- exitpg(1);
- }
-
- 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);
- }
-
- Noversion = flagC;
- Quiet = flagQ;
- EchoQuery = flagE;
- EuroDates = flagEu;
-
- /* ----------------
- * print flags
- * ----------------
- */
- if (! Quiet) {
- puts("\t---debug info---");
- printf("\tQuiet = %c\n", Quiet ? 't' : 'f');
- printf("\tNoversion = %c\n", Noversion ? 't' : 'f');
- printf("\ttimings = %c\n", ShowStats ? 't' : 'f');
- printf("\tdates = %s\n", EuroDates ? "European" : "Normal");
- printf("\tbufsize = %d\n", NBuffers);
- printf("\tsortmem = %d\n", SortMem);
-
- printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
- printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
- printf("\tDatabaseName = [%s]\n", DBName);
- puts("\t----------------\n");
- }
-
- /* ----------------
- * initialize portal file descriptors
- * ----------------
- */
- if (IsUnderPostmaster == true) {
- if (Portfd < 0) {
- fprintf(stderr,
- "Postmaster flag set: no port number specified, use /dev/null\n");
- Portfd = open(NULL_DEV, O_RDWR, 0666);
- }
- pq_init(Portfd);
- }
-
- if (multiplexedBackend) {
- if (serverPortnum == 0 ||
- StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
- {
- fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
- exit(1);
- }
+ break;
+
+ default:
+ /* ----------------
+ * default: bad command line option
+ * ----------------
+ */
+ errs++;
+ }
+
+ /* ----------------
+ * get user name and pathname and check command line validity
+ * ----------------
+ */
+ SetPgUserName();
+ userName = GetPgUserName();
+
+ if (FindBackend(pg_pathname, argv[0]) < 0)
+ elog(FATAL, "%s: could not locate executable, bailing out...",
+ argv[0]);
+
+ if (errs || argc - optind > 1)
+ {
+ usage(argv[0]);
+ exitpg(1);
+ }
+ else if (argc - optind == 1)
+ {
+ DBName = argv[optind];
+ }
+ else if ((DBName = userName) == NULL)
+ {
+ fprintf(stderr, "%s: USER undefined and no database specified\n",
+ argv[0]);
+ exitpg(1);
+ }
+
+ if (ShowStats &&
+ (ShowParserStats || ShowPlannerStats || ShowExecutorStats))
+ {
+ fprintf(stderr, "-s can not be used together with -t.\n");
+ exitpg(1);
+ }
+
+ 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);
+ }
+
+ Noversion = flagC;
+ Quiet = flagQ;
+ EchoQuery = flagE;
+ EuroDates = flagEu;
+
+ /* ----------------
+ * print flags
+ * ----------------
+ */
+ if (!Quiet)
+ {
+ puts("\t---debug info---");
+ printf("\tQuiet = %c\n", Quiet ? 't' : 'f');
+ printf("\tNoversion = %c\n", Noversion ? 't' : 'f');
+ printf("\ttimings = %c\n", ShowStats ? 't' : 'f');
+ printf("\tdates = %s\n", EuroDates ? "European" : "Normal");
+ printf("\tbufsize = %d\n", NBuffers);
+ printf("\tsortmem = %d\n", SortMem);
+
+ printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
+ printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
+ printf("\tDatabaseName = [%s]\n", DBName);
+ puts("\t----------------\n");
+ }
+
+ /* ----------------
+ * initialize portal file descriptors
+ * ----------------
+ */
+ if (IsUnderPostmaster == true)
+ {
+ if (Portfd < 0)
+ {
+ fprintf(stderr,
+ "Postmaster flag set: no port number specified, use /dev/null\n");
+ Portfd = open(NULL_DEV, O_RDWR, 0666);
+ }
+ pq_init(Portfd);
+ }
+
+ if (multiplexedBackend)
+ {
+ if (serverPortnum == 0 ||
+ StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
+ {
+ fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
+ exit(1);
+ }
/*
{
- char buf[100];
- sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
- puts(buf);
+ char buf[100];
+ sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
+ puts(buf);
}
*/
- FD_ZERO(&rmask);
- FD_ZERO(&basemask);
- FD_SET(serverSock, &basemask);
-
- frontendList = DLNewList();
- /* add the original FrontEnd to the list */
- if (IsUnderPostmaster == true) {
- FrontEnd *fe = malloc(sizeof(FrontEnd));
-
- FD_SET(Portfd, &basemask);
- maxFd = Max(serverSock,Portfd) + 1;
-
- fe->fn_connected = true;
- fe->fn_Pfin = Pfin;
- fe->fn_Pfout = Pfout;
- fe->fn_done = false;
- (fe->fn_port).sock = Portfd;
- DLAddHead(frontendList, DLNewElem(fe));
- numFE++;
- } else {
- numFE = 1;
- maxFd = serverSock + 1;
- }
- }
-
- if (IsUnderPostmaster || multiplexedBackend)
- whereToSendOutput = Remote;
- else
- whereToSendOutput = Debug;
-
- SetProcessingMode(InitProcessing);
-
- /* initialize */
- if (! Quiet) {
- puts("\tInitPostgres()..");
- }
-
- InitPostgres(DBName);
-
- /* ----------------
- * if an exception is encountered, processing resumes here
- * so we abort the current transaction and start a new one.
- * This must be done after we initialize the slave backends
- * so that the slaves signal the master to abort the transaction
- * rather than calling AbortCurrentTransaction() themselves.
- *
- * Note: elog(WARN) causes a kill(getpid(),1) to occur sending
- * us back here.
- * ----------------
- */
-
- pqsignal(SIGHUP, handle_warn);
-
- if (sigsetjmp(Warn_restart, 1) != 0) {
- InWarn = 1;
-
- time(&tim);
-
- if (! Quiet)
- printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
-
- memset(parser_input, 0, MAX_PARSE_BUFFER);
-
- AbortCurrentTransaction();
- }
- InWarn = 0;
-
- /* ----------------
- * POSTGRES main processing loop begins here
- * ----------------
- */
- if (IsUnderPostmaster == false) {
- puts("\nPOSTGRES backend interactive interface");
- puts("$Revision: 1.42 $ $Date: 1997/08/19 21:34:04 $");
- }
-
- /* ----------------
- * if stable main memory is assumed (-S(old) flag is set), it is necessary
- * to flush all dirty shared buffers before exit
- * plai 8/7/90
- * ----------------
- */
- if (!TransactionFlushEnabled())
- on_exitpg(FlushBufferPool, (caddr_t) 0);
-
- for (;;) {
-
- if (multiplexedBackend) {
- if (numFE == 0)
- break;
-
- memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
- nSelected = select(maxFd, &rmask,0,0,0);
-
- if (nSelected < 0) {
-
- if (errno == EINTR) continue;
- fprintf(stderr,"postgres: multiplexed backend select failed\n");
- exitpg(1);
- }
- if (FD_ISSET(serverSock, &rmask)) {
- /* new connection pending on our well-known port's socket */
- newFE = (FrontEnd*) malloc (sizeof(FrontEnd));
- memset(newFE, 0, sizeof(FrontEnd));
- newFE->fn_connected = false;
- newFE->fn_done = false;
- newPort = &(newFE->fn_port);
- if (StreamConnection(serverSock,newPort) != STATUS_OK) {
- StreamClose(newPort->sock);
- newFd = -1;
- }
- else {
- DLAddHead(frontendList, DLNewElem(newFE));
- numFE++;
- newFd = newPort->sock;
- if (newFd >= maxFd) maxFd = newFd + 1;
- FD_SET(newFd, &rmask);
- FD_SET(newFd, &basemask);
- --nSelected;
- FD_CLR(serverSock, &rmask);
- }
- continue;
- } /* if FD_ISSET(serverSock) */
-
- /* if we get here, it means that the serverSocket was not the one
- selected. Instead, one of the front ends was selected.
- find which one */
- curr = DLGetHead(frontendList);
- while (curr) {
- FrontEnd *fe = (FrontEnd*)DLE_VAL(curr);
- Port *port = &(fe->fn_port);
-
- /* this is lifted from postmaster.c */
- if (FD_ISSET(port->sock, &rmask)) {
- if (fe->fn_connected == false) {
- /* we have a message from a new frontEnd */
- status = PacketReceive(port, &port->buf, NON_BLOCKING);
- if (status == STATUS_OK) {
- fe->fn_connected = true;
- pq_init(port->sock);
- fe->fn_Pfin = Pfin;
- fe->fn_Pfout = Pfout;
- }
- else
- fprintf(stderr,"Multiplexed backend: error in reading packets from %d\n", port->sock);
- }
- else /* we have a query from an existing, active FrontEnd */
- {
- Pfin = fe->fn_Pfin;
- Pfout = fe->fn_Pfout;
- currentFE = fe;
- }
- if (fe->fn_done)
- {
- Dlelem *c = curr;
- curr = DLGetSucc(curr);
- DLRemove(c);
- }
- break;
- }
- else
- curr = DLGetSucc(curr);
- }
- }
- /* ----------------
- * (1) read a command.
- * ----------------
- */
- memset(parser_input, 0, MAX_PARSE_BUFFER);
-
- firstchar = ReadCommand(parser_input, multiplexedBackend);
- /* process the command */
- switch (firstchar) {
- /* ----------------
- * 'F' indicates a fastpath call.
- * XXX HandleFunctionRequest
- * ----------------
- */
- case 'F':
- IsEmptyQuery = false;
-
- /* start an xact for this function invocation */
- if (! Quiet) {
- time(&tim);
- printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
- }
-
- StartTransactionCommand();
- HandleFunctionRequest();
- break;
-
- /* ----------------
- * 'Q' indicates a user query
- * ----------------
- */
- case 'Q':
- fflush(stdout);
-
- if ( strspn(parser_input," \t\n") == strlen(parser_input)) {
- /* ----------------
- * if there is nothing in the input buffer, don't bother
- * trying to parse and execute anything..
- * ----------------
- */
- IsEmptyQuery = true;
- } else {
- /* ----------------
- * otherwise, process the input string.
- * ----------------
- */
- IsEmptyQuery = false;
- if (ShowStats)
- ResetUsage();
-
- /* start an xact for this query */
- if (! Quiet) {
- time(&tim);
- printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
- }
- StartTransactionCommand();
-
- pg_eval(parser_input, (char **) NULL, (Oid *) NULL, 0);
-
- if (ShowStats)
- ShowUsage();
- }
- break;
-
- /* ----------------
- * 'X' means that the frontend is closing down the socket
- * ----------------
- */
- case 'X':
- IsEmptyQuery = true;
- if (multiplexedBackend) {
- FD_CLR(currentFE->fn_port.sock, &basemask);
- currentFE->fn_done = true;
- numFE--;
- }
- pq_close();
- break;
-
- default:
- elog(WARN,"unknown frontend message was recieved");
- }
-
- /* ----------------
- * (3) commit the current transaction
- *
- * Note: if we had an empty input buffer, then we didn't
- * call pg_eval, so we don't bother to commit this transaction.
- * ----------------
- */
- if (! IsEmptyQuery) {
- if (! Quiet) {
- time(&tim);
- printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
- }
- CommitTransactionCommand();
-
- } else {
- if (IsUnderPostmaster || multiplexedBackend)
- NullCommand(Remote);
- }
-
-} /* infinite for-loop */
- exitpg(0);
- return 1;
+ FD_ZERO(&rmask);
+ FD_ZERO(&basemask);
+ FD_SET(serverSock, &basemask);
+
+ frontendList = DLNewList();
+ /* add the original FrontEnd to the list */
+ if (IsUnderPostmaster == true)
+ {
+ FrontEnd *fe = malloc(sizeof(FrontEnd));
+
+ FD_SET(Portfd, &basemask);
+ maxFd = Max(serverSock, Portfd) + 1;
+
+ fe->fn_connected = true;
+ fe->fn_Pfin = Pfin;
+ fe->fn_Pfout = Pfout;
+ fe->fn_done = false;
+ (fe->fn_port).sock = Portfd;
+ DLAddHead(frontendList, DLNewElem(fe));
+ numFE++;
+ }
+ else
+ {
+ numFE = 1;
+ maxFd = serverSock + 1;
+ }
+ }
+
+ if (IsUnderPostmaster || multiplexedBackend)
+ whereToSendOutput = Remote;
+ else
+ whereToSendOutput = Debug;
+
+ SetProcessingMode(InitProcessing);
+
+ /* initialize */
+ if (!Quiet)
+ {
+ puts("\tInitPostgres()..");
+ }
+
+ InitPostgres(DBName);
+
+ /* ----------------
+ * if an exception is encountered, processing resumes here
+ * so we abort the current transaction and start a new one.
+ * This must be done after we initialize the slave backends
+ * so that the slaves signal the master to abort the transaction
+ * rather than calling AbortCurrentTransaction() themselves.
+ *
+ * Note: elog(WARN) causes a kill(getpid(),1) to occur sending
+ * us back here.
+ * ----------------
+ */
+
+ pqsignal(SIGHUP, handle_warn);
+
+ if (sigsetjmp(Warn_restart, 1) != 0)
+ {
+ InWarn = 1;
+
+ time(&tim);
+
+ if (!Quiet)
+ printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
+
+ memset(parser_input, 0, MAX_PARSE_BUFFER);
+
+ AbortCurrentTransaction();
+ }
+ InWarn = 0;
+
+ /* ----------------
+ * POSTGRES main processing loop begins here
+ * ----------------
+ */
+ if (IsUnderPostmaster == false)
+ {
+ puts("\nPOSTGRES backend interactive interface");
+ puts("$Revision: 1.43 $ $Date: 1997/09/07 04:49:33 $");
+ }
+
+ /* ----------------
+ * if stable main memory is assumed (-S(old) flag is set), it is necessary
+ * to flush all dirty shared buffers before exit
+ * plai 8/7/90
+ * ----------------
+ */
+ if (!TransactionFlushEnabled())
+ on_exitpg(FlushBufferPool, (caddr_t) 0);
+
+ for (;;)
+ {
+
+ if (multiplexedBackend)
+ {
+ if (numFE == 0)
+ break;
+
+ memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
+ nSelected = select(maxFd, &rmask, 0, 0, 0);
+
+ if (nSelected < 0)
+ {
+
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "postgres: multiplexed backend select failed\n");
+ exitpg(1);
+ }
+ if (FD_ISSET(serverSock, &rmask))
+ {
+ /* new connection pending on our well-known port's socket */
+ newFE = (FrontEnd *) malloc(sizeof(FrontEnd));
+ memset(newFE, 0, sizeof(FrontEnd));
+ newFE->fn_connected = false;
+ newFE->fn_done = false;
+ newPort = &(newFE->fn_port);
+ if (StreamConnection(serverSock, newPort) != STATUS_OK)
+ {
+ StreamClose(newPort->sock);
+ newFd = -1;
+ }
+ else
+ {
+ DLAddHead(frontendList, DLNewElem(newFE));
+ numFE++;
+ newFd = newPort->sock;
+ if (newFd >= maxFd)
+ maxFd = newFd + 1;
+ FD_SET(newFd, &rmask);
+ FD_SET(newFd, &basemask);
+ --nSelected;
+ FD_CLR(serverSock, &rmask);
+ }
+ continue;
+ } /* if FD_ISSET(serverSock) */
+
+ /*
+ * if we get here, it means that the serverSocket was not the
+ * one selected. Instead, one of the front ends was selected.
+ * find which one
+ */
+ curr = DLGetHead(frontendList);
+ while (curr)
+ {
+ FrontEnd *fe = (FrontEnd *) DLE_VAL(curr);
+ Port *port = &(fe->fn_port);
+
+ /* this is lifted from postmaster.c */
+ if (FD_ISSET(port->sock, &rmask))
+ {
+ if (fe->fn_connected == false)
+ {
+ /* we have a message from a new frontEnd */
+ status = PacketReceive(port, &port->buf, NON_BLOCKING);
+ if (status == STATUS_OK)
+ {
+ fe->fn_connected = true;
+ pq_init(port->sock);
+ fe->fn_Pfin = Pfin;
+ fe->fn_Pfout = Pfout;
+ }
+ else
+ fprintf(stderr, "Multiplexed backend: error in reading packets from %d\n", port->sock);
+ }
+ else
+/* we have a query from an existing, active FrontEnd */
+ {
+ Pfin = fe->fn_Pfin;
+ Pfout = fe->fn_Pfout;
+ currentFE = fe;
+ }
+ if (fe->fn_done)
+ {
+ Dlelem *c = curr;
+
+ curr = DLGetSucc(curr);
+ DLRemove(c);
+ }
+ break;
+ }
+ else
+ curr = DLGetSucc(curr);
+ }
+ }
+ /* ----------------
+ * (1) read a command.
+ * ----------------
+ */
+ memset(parser_input, 0, MAX_PARSE_BUFFER);
+
+ firstchar = ReadCommand(parser_input, multiplexedBackend);
+ /* process the command */
+ switch (firstchar)
+ {
+ /* ----------------
+ * 'F' indicates a fastpath call.
+ * XXX HandleFunctionRequest
+ * ----------------
+ */
+ case 'F':
+ IsEmptyQuery = false;
+
+ /* start an xact for this function invocation */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
+ }
+
+ StartTransactionCommand();
+ HandleFunctionRequest();
+ break;
+
+ /* ----------------
+ * 'Q' indicates a user query
+ * ----------------
+ */
+ case 'Q':
+ fflush(stdout);
+
+ if (strspn(parser_input, " \t\n") == strlen(parser_input))
+ {
+ /* ----------------
+ * if there is nothing in the input buffer, don't bother
+ * trying to parse and execute anything..
+ * ----------------
+ */
+ IsEmptyQuery = true;
+ }
+ else
+ {
+ /* ----------------
+ * otherwise, process the input string.
+ * ----------------
+ */
+ IsEmptyQuery = false;
+ if (ShowStats)
+ ResetUsage();
+
+ /* start an xact for this query */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
+ }
+ StartTransactionCommand();
+
+ pg_eval(parser_input, (char **) NULL, (Oid *) NULL, 0);
+
+ if (ShowStats)
+ ShowUsage();
+ }
+ break;
+
+ /* ----------------
+ * 'X' means that the frontend is closing down the socket
+ * ----------------
+ */
+ case 'X':
+ IsEmptyQuery = true;
+ if (multiplexedBackend)
+ {
+ FD_CLR(currentFE->fn_port.sock, &basemask);
+ currentFE->fn_done = true;
+ numFE--;
+ }
+ pq_close();
+ break;
+
+ default:
+ elog(WARN, "unknown frontend message was recieved");
+ }
+
+ /* ----------------
+ * (3) commit the current transaction
+ *
+ * Note: if we had an empty input buffer, then we didn't
+ * call pg_eval, so we don't bother to commit this transaction.
+ * ----------------
+ */
+ if (!IsEmptyQuery)
+ {
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
+ }
+ CommitTransactionCommand();
+
+ }
+ else
+ {
+ if (IsUnderPostmaster || multiplexedBackend)
+ NullCommand(Remote);
+ }
+
+ } /* infinite for-loop */
+ exitpg(0);
+ return 1;
}
#ifndef HAVE_GETRUSAGE
#include "rusagestub.h"
-#else /* HAVE_GETRUSAGE */
+#else /* HAVE_GETRUSAGE */
#include <sys/resource.h>
-#endif /* HAVE_GETRUSAGE */
+#endif /* HAVE_GETRUSAGE */
-struct rusage Save_r;
-struct timeval Save_t;
+struct rusage Save_r;
+struct timeval Save_t;
void
ResetUsage(void)
{
- struct timezone tz;
- getrusage(RUSAGE_SELF, &Save_r);
- gettimeofday(&Save_t, &tz);
- ResetBufferUsage();
-/* ResetTupleCount(); */
+ struct timezone tz;
+
+ getrusage(RUSAGE_SELF, &Save_r);
+ gettimeofday(&Save_t, &tz);
+ ResetBufferUsage();
+/* ResetTupleCount(); */
}
void
ShowUsage(void)
{
- struct timeval user, sys;
- struct timeval elapse_t;
- struct timezone tz;
- struct rusage r;
-
- getrusage(RUSAGE_SELF, &r);
- gettimeofday(&elapse_t, &tz);
- memmove((char *)&user, (char *)&r.ru_utime, sizeof(user));
- memmove((char *)&sys, (char *)&r.ru_stime,sizeof(sys));
- if (elapse_t.tv_usec < Save_t.tv_usec) {
- elapse_t.tv_sec--;
- elapse_t.tv_usec += 1000000;
- }
- if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec) {
- r.ru_utime.tv_sec--;
- r.ru_utime.tv_usec += 1000000;
- }
- if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec) {
- r.ru_stime.tv_sec--;
- r.ru_stime.tv_usec += 1000000;
- }
-
- /*
- * the only stats we don't show here are for memory usage -- i can't
- * figure out how to interpret the relevant fields in the rusage
- * struct, and they change names across o/s platforms, anyway.
- * if you can figure out what the entries mean, you can somehow
- * extract resident set size, shared text size, and unshared data
- * and stack sizes.
- */
-
- fprintf(StatFp, "! system usage stats:\n");
- fprintf(StatFp,
- "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
- (long int) elapse_t.tv_sec - Save_t.tv_sec,
- (long int) elapse_t.tv_usec - Save_t.tv_usec,
- (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
- (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
- (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
- (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
- fprintf(StatFp,
- "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
- (long int) user.tv_sec,
- (long int) user.tv_usec,
- (long int) sys.tv_sec,
- (long int) sys.tv_usec);
+ struct timeval user,
+ sys;
+ struct timeval elapse_t;
+ struct timezone tz;
+ struct rusage r;
+
+ getrusage(RUSAGE_SELF, &r);
+ gettimeofday(&elapse_t, &tz);
+ memmove((char *) &user, (char *) &r.ru_utime, sizeof(user));
+ memmove((char *) &sys, (char *) &r.ru_stime, sizeof(sys));
+ if (elapse_t.tv_usec < Save_t.tv_usec)
+ {
+ elapse_t.tv_sec--;
+ elapse_t.tv_usec += 1000000;
+ }
+ if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec)
+ {
+ r.ru_utime.tv_sec--;
+ r.ru_utime.tv_usec += 1000000;
+ }
+ if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec)
+ {
+ r.ru_stime.tv_sec--;
+ r.ru_stime.tv_usec += 1000000;
+ }
+
+ /*
+ * the only stats we don't show here are for memory usage -- i can't
+ * figure out how to interpret the relevant fields in the rusage
+ * struct, and they change names across o/s platforms, anyway. if you
+ * can figure out what the entries mean, you can somehow extract
+ * resident set size, shared text size, and unshared data and stack
+ * sizes.
+ */
+
+ fprintf(StatFp, "! system usage stats:\n");
+ fprintf(StatFp,
+ "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
+ (long int) elapse_t.tv_sec - Save_t.tv_sec,
+ (long int) elapse_t.tv_usec - Save_t.tv_usec,
+ (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
+ (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
+ (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
+ (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
+ fprintf(StatFp,
+ "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
+ (long int) user.tv_sec,
+ (long int) user.tv_usec,
+ (long int) sys.tv_sec,
+ (long int) sys.tv_usec);
#ifdef HAVE_GETRUSAGE
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
- r.ru_inblock - Save_r.ru_inblock,
- /* they only drink coffee at dec */
- r.ru_oublock - Save_r.ru_oublock,
- r.ru_inblock, r.ru_oublock);
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
- r.ru_majflt - Save_r.ru_majflt,
- r.ru_minflt - Save_r.ru_minflt,
- r.ru_majflt, r.ru_minflt,
- r.ru_nswap - Save_r.ru_nswap,
- r.ru_nswap);
- fprintf(StatFp,
- "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
- r.ru_nsignals - Save_r.ru_nsignals,
- r.ru_nsignals,
- r.ru_msgrcv - Save_r.ru_msgrcv,
- r.ru_msgsnd - Save_r.ru_msgsnd,
- r.ru_msgrcv, r.ru_msgsnd);
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
- r.ru_nvcsw - Save_r.ru_nvcsw,
- r.ru_nivcsw - Save_r.ru_nivcsw,
- r.ru_nvcsw, r.ru_nivcsw);
-#endif /* HAVE_GETRUSAGE */
- fprintf(StatFp, "! postgres usage stats:\n");
- PrintBufferUsage(StatFp);
-/* DisplayTupleCount(StatFp); */
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
+ r.ru_inblock - Save_r.ru_inblock,
+ /* they only drink coffee at dec */
+ r.ru_oublock - Save_r.ru_oublock,
+ r.ru_inblock, r.ru_oublock);
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
+ r.ru_majflt - Save_r.ru_majflt,
+ r.ru_minflt - Save_r.ru_minflt,
+ r.ru_majflt, r.ru_minflt,
+ r.ru_nswap - Save_r.ru_nswap,
+ r.ru_nswap);
+ fprintf(StatFp,
+ "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
+ r.ru_nsignals - Save_r.ru_nsignals,
+ r.ru_nsignals,
+ r.ru_msgrcv - Save_r.ru_msgrcv,
+ r.ru_msgsnd - Save_r.ru_msgsnd,
+ r.ru_msgrcv, r.ru_msgsnd);
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
+ r.ru_nvcsw - Save_r.ru_nvcsw,
+ r.ru_nivcsw - Save_r.ru_nivcsw,
+ r.ru_nvcsw, r.ru_nivcsw);
+#endif /* HAVE_GETRUSAGE */
+ fprintf(StatFp, "! postgres usage stats:\n");
+ PrintBufferUsage(StatFp);
+/* DisplayTupleCount(StatFp); */
}
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 1d11cbeae49..ca649291355 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* pquery.c--
- * POSTGRES process query command code
+ * POSTGRES process query command code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.7 1997/08/27 09:03:15 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.8 1997/09/07 04:49:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,332 +38,341 @@
#include "commands/command.h"
-static char* CreateOperationTag(int operationType);
-static void ProcessQueryDesc(QueryDesc *queryDesc);
+static char *CreateOperationTag(int operationType);
+static void ProcessQueryDesc(QueryDesc * queryDesc);
/* ----------------------------------------------------------------
- * CreateQueryDesc
+ * CreateQueryDesc
* ----------------------------------------------------------------
*/
-QueryDesc *
-CreateQueryDesc(Query *parsetree,
- Plan *plantree,
- CommandDest dest)
+QueryDesc *
+CreateQueryDesc(Query * parsetree,
+ Plan * plantree,
+ CommandDest dest)
{
- QueryDesc *qd = (QueryDesc *)palloc(sizeof(QueryDesc));
-
- qd->operation = parsetree->commandType; /* operation */
- qd->parsetree = parsetree; /* parse tree */
- qd->plantree = plantree; /* plan */
- qd->dest = dest; /* output dest */
- return qd;
+ QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
+
+ qd->operation = parsetree->commandType; /* operation */
+ qd->parsetree = parsetree; /* parse tree */
+ qd->plantree = plantree; /* plan */
+ qd->dest = dest; /* output dest */
+ return qd;
}
/* ----------------------------------------------------------------
- * CreateExecutorState
+ * CreateExecutorState
*
- * Note: this may someday take parameters -cim 9/18/89
+ * Note: this may someday take parameters -cim 9/18/89
* ----------------------------------------------------------------
*/
-EState *
+EState *
CreateExecutorState(void)
{
- EState *state;
- extern int NBuffers;
- long *refcount;
-
- /* ----------------
- * create a new executor state
- * ----------------
- */
- state = makeNode(EState);
-
- /* ----------------
- * initialize the Executor State structure
- * ----------------
- */
- state->es_direction = ForwardScanDirection;
- state->es_range_table = NIL;
-
- state->es_into_relation_descriptor = NULL;
- state->es_result_relation_info = NULL;
-
- state->es_param_list_info = NULL;
-
- state->es_BaseId = 0;
- state->es_tupleTable = NULL;
-
- state->es_junkFilter = NULL;
-
- refcount = (long *) palloc(NBuffers * sizeof(long));
- memset((char *) refcount, 0, NBuffers * sizeof(long));
- state->es_refcount = (int *) refcount;
-
- /* ----------------
- * return the executor state structure
- * ----------------
- */
- return state;
+ EState *state;
+ extern int NBuffers;
+ long *refcount;
+
+ /* ----------------
+ * create a new executor state
+ * ----------------
+ */
+ state = makeNode(EState);
+
+ /* ----------------
+ * initialize the Executor State structure
+ * ----------------
+ */
+ state->es_direction = ForwardScanDirection;
+ state->es_range_table = NIL;
+
+ state->es_into_relation_descriptor = NULL;
+ state->es_result_relation_info = NULL;
+
+ state->es_param_list_info = NULL;
+
+ state->es_BaseId = 0;
+ state->es_tupleTable = NULL;
+
+ state->es_junkFilter = NULL;
+
+ refcount = (long *) palloc(NBuffers * sizeof(long));
+ memset((char *) refcount, 0, NBuffers * sizeof(long));
+ state->es_refcount = (int *) refcount;
+
+ /* ----------------
+ * return the executor state structure
+ * ----------------
+ */
+ return state;
}
/* ----------------------------------------------------------------
- * CreateOperationTag
+ * CreateOperationTag
*
- * utility to get a string representation of the
- * query operation.
+ * utility to get a string representation of the
+ * query operation.
* ----------------------------------------------------------------
*/
-static char*
+static char *
CreateOperationTag(int operationType)
{
- char* tag;
-
- switch (operationType) {
- case CMD_SELECT:
- tag = "SELECT";
- break;
- case CMD_INSERT:
- tag = "INSERT";
- break;
- case CMD_DELETE:
- tag = "DELETE";
- break;
- case CMD_UPDATE:
- tag = "UPDATE";
- break;
- default:
- elog(DEBUG, "CreateOperationTag: unknown operation type %d",
- operationType);
- tag = NULL;
- break;
- }
-
- return tag;
+ char *tag;
+
+ switch (operationType)
+ {
+ case CMD_SELECT:
+ tag = "SELECT";
+ break;
+ case CMD_INSERT:
+ tag = "INSERT";
+ break;
+ case CMD_DELETE:
+ tag = "DELETE";
+ break;
+ case CMD_UPDATE:
+ tag = "UPDATE";
+ break;
+ default:
+ elog(DEBUG, "CreateOperationTag: unknown operation type %d",
+ operationType);
+ tag = NULL;
+ break;
+ }
+
+ return tag;
}
/* ----------------
- * ProcessPortal
+ * ProcessPortal
* ----------------
*/
void
-ProcessPortal(char* portalName,
- Query *parseTree,
- Plan *plan,
- EState *state,
- TupleDesc attinfo,
- CommandDest dest)
+ProcessPortal(char *portalName,
+ Query * parseTree,
+ Plan * plan,
+ EState * state,
+ TupleDesc attinfo,
+ CommandDest dest)
{
- Portal portal;
- MemoryContext portalContext;
-
- /* ----------------
- * convert the current blank portal into the user-specified
- * portal and initialize the state and query descriptor.
- * ----------------
- */
-
- if (PortalNameIsSpecial(portalName))
- elog(WARN,
- "The portal name %s is reserved for internal use",
- portalName);
-
- portal = BlankPortalAssignName(portalName);
-
- PortalSetQuery(portal,
- CreateQueryDesc(parseTree, plan, dest),
- attinfo,
- state,
- PortalCleanup);
-
- /* ----------------
- * now create a new blank portal and switch to it.
- * Otherwise, the new 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. -hirohama
- * ----------------
- */
- portalContext = (MemoryContext)
- PortalGetHeapMemory(GetPortalByName(NULL));
-
- MemoryContextSwitchTo(portalContext);
-
- StartPortalAllocMode(DefaultAllocMode, 0);
+ Portal portal;
+ MemoryContext portalContext;
+
+ /* ----------------
+ * convert the current blank portal into the user-specified
+ * portal and initialize the state and query descriptor.
+ * ----------------
+ */
+
+ if (PortalNameIsSpecial(portalName))
+ elog(WARN,
+ "The portal name %s is reserved for internal use",
+ portalName);
+
+ portal = BlankPortalAssignName(portalName);
+
+ PortalSetQuery(portal,
+ CreateQueryDesc(parseTree, plan, dest),
+ attinfo,
+ state,
+ PortalCleanup);
+
+ /* ----------------
+ * now create a new blank portal and switch to it.
+ * Otherwise, the new 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. -hirohama
+ * ----------------
+ */
+ portalContext = (MemoryContext)
+ PortalGetHeapMemory(GetPortalByName(NULL));
+
+ MemoryContextSwitchTo(portalContext);
+
+ StartPortalAllocMode(DefaultAllocMode, 0);
}
/* ----------------------------------------------------------------
- * ProcessQueryDesc
+ * ProcessQueryDesc
*
- * Read the comments for ProcessQuery() below...
+ * Read the comments for ProcessQuery() below...
* ----------------------------------------------------------------
*/
static void
-ProcessQueryDesc(QueryDesc *queryDesc)
+ProcessQueryDesc(QueryDesc * queryDesc)
{
- Query *parseTree;
- Plan *plan;
- int operation;
- char* tag;
- EState *state;
- TupleDesc attinfo;
-
- bool isRetrieveIntoPortal;
- bool isRetrieveIntoRelation;
- char* intoName = NULL;
- CommandDest dest;
-
- /* ----------------
- * get info from the query desc
- * ----------------
- */
- parseTree = queryDesc->parsetree;
- plan = queryDesc->plantree;
-
- operation = queryDesc->operation;
- tag = CreateOperationTag(operation);
- dest = queryDesc->dest;
-
- /* ----------------
- * initialize portal/into relation status
- * ----------------
- */
- isRetrieveIntoPortal = false;
- isRetrieveIntoRelation = false;
-
- if (operation == CMD_SELECT) {
- if (parseTree->isPortal) {
- isRetrieveIntoPortal = true;
- intoName = parseTree->into;
- if (parseTree->isBinary) {
- /*
- * For internal format portals, we change Remote
- * (externalized form) to RemoteInternal (internalized
- * form)
- */
- dest = queryDesc->dest = RemoteInternal;
- }
- } else if (parseTree->into != NULL) {
- /* select into table */
- isRetrieveIntoRelation = true;
+ Query *parseTree;
+ Plan *plan;
+ int operation;
+ char *tag;
+ EState *state;
+ TupleDesc attinfo;
+
+ bool isRetrieveIntoPortal;
+ bool isRetrieveIntoRelation;
+ char *intoName = NULL;
+ CommandDest dest;
+
+ /* ----------------
+ * get info from the query desc
+ * ----------------
+ */
+ parseTree = queryDesc->parsetree;
+ plan = queryDesc->plantree;
+
+ operation = queryDesc->operation;
+ tag = CreateOperationTag(operation);
+ dest = queryDesc->dest;
+
+ /* ----------------
+ * initialize portal/into relation status
+ * ----------------
+ */
+ isRetrieveIntoPortal = false;
+ isRetrieveIntoRelation = false;
+
+ if (operation == CMD_SELECT)
+ {
+ if (parseTree->isPortal)
+ {
+ isRetrieveIntoPortal = true;
+ intoName = parseTree->into;
+ if (parseTree->isBinary)
+ {
+
+ /*
+ * For internal format portals, we change Remote
+ * (externalized form) to RemoteInternal (internalized
+ * form)
+ */
+ dest = queryDesc->dest = RemoteInternal;
+ }
+ }
+ else if (parseTree->into != NULL)
+ {
+ /* select into table */
+ isRetrieveIntoRelation = true;
+ }
+
}
- }
-
- /* ----------------
- * when performing a retrieve into, we override the normal
- * communication destination during the processing of the
- * the query. This only affects the tuple-output function
- * - the correct destination will still see BeginCommand()
- * and EndCommand() messages.
- * ----------------
- */
- if (isRetrieveIntoRelation)
- queryDesc->dest = (int) None;
-
- /* ----------------
- * create a default executor state..
- * ----------------
- */
- state = CreateExecutorState();
-
- /* ----------------
- * call ExecStart to prepare the plan for execution
- * ----------------
- */
- attinfo = ExecutorStart(queryDesc, state);
-
- /* ----------------
- * report the query's result type information
- * back to the front end or to whatever destination
- * we're dealing with.
- * ----------------
- */
- BeginCommand(NULL,
- operation,
- attinfo,
- isRetrieveIntoRelation,
- isRetrieveIntoPortal,
- tag,
- dest);
-
- /* ----------------
- * Named portals do not do a "fetch all" initially, so now
- * we return since ExecMain has been called with EXEC_START
- * to initialize the query plan.
- *
- * Note: ProcessPortal transforms the current "blank" portal
- * into a named portal and creates a new blank portal so
- * everything we allocated in the current "blank" memory
- * context will be preserved across queries. -cim 2/22/91
- * ----------------
- */
- if (isRetrieveIntoPortal) {
- PortalExecutorHeapMemory = NULL;
-
- ProcessPortal(intoName,
- parseTree,
- plan,
- state,
- attinfo,
- dest);
-
+ /* ----------------
+ * when performing a retrieve into, we override the normal
+ * communication destination during the processing of the
+ * the query. This only affects the tuple-output function
+ * - the correct destination will still see BeginCommand()
+ * and EndCommand() messages.
+ * ----------------
+ */
+ if (isRetrieveIntoRelation)
+ queryDesc->dest = (int) None;
+
+ /* ----------------
+ * create a default executor state..
+ * ----------------
+ */
+ state = CreateExecutorState();
+
+ /* ----------------
+ * call ExecStart to prepare the plan for execution
+ * ----------------
+ */
+ attinfo = ExecutorStart(queryDesc, state);
+
+ /* ----------------
+ * report the query's result type information
+ * back to the front end or to whatever destination
+ * we're dealing with.
+ * ----------------
+ */
+ BeginCommand(NULL,
+ operation,
+ attinfo,
+ isRetrieveIntoRelation,
+ isRetrieveIntoPortal,
+ tag,
+ dest);
+
+ /* ----------------
+ * Named portals do not do a "fetch all" initially, so now
+ * we return since ExecMain has been called with EXEC_START
+ * to initialize the query plan.
+ *
+ * Note: ProcessPortal transforms the current "blank" portal
+ * into a named portal and creates a new blank portal so
+ * everything we allocated in the current "blank" memory
+ * context will be preserved across queries. -cim 2/22/91
+ * ----------------
+ */
+ if (isRetrieveIntoPortal)
+ {
+ PortalExecutorHeapMemory = NULL;
+
+ ProcessPortal(intoName,
+ parseTree,
+ plan,
+ state,
+ attinfo,
+ dest);
+
+ EndCommand(tag, dest);
+ return;
+ }
+
+ /* ----------------
+ * Now we get to the important call to ExecutorRun() where we
+ * actually run the plan..
+ * ----------------
+ */
+ ExecutorRun(queryDesc, state, EXEC_RUN, 0);
+
+ /* save infos for EndCommand */
+ UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
+
+ /* ----------------
+ * now, we close down all the scans and free allocated resources...
+ * with ExecutorEnd()
+ * ----------------
+ */
+ ExecutorEnd(queryDesc, state);
+
+ /* ----------------
+ * Notify the destination of end of processing.
+ * ----------------
+ */
EndCommand(tag, dest);
- return;
- }
-
- /* ----------------
- * Now we get to the important call to ExecutorRun() where we
- * actually run the plan..
- * ----------------
- */
- ExecutorRun(queryDesc, state, EXEC_RUN, 0);
-
- /* save infos for EndCommand */
- UpdateCommandInfo (operation, state->es_lastoid, state->es_processed);
-
- /* ----------------
- * now, we close down all the scans and free allocated resources...
- * with ExecutorEnd()
- * ----------------
- */
- ExecutorEnd(queryDesc, state);
-
- /* ----------------
- * Notify the destination of end of processing.
- * ----------------
- */
- EndCommand(tag, dest);
}
/* ----------------------------------------------------------------
- * ProcessQuery
+ * ProcessQuery
*
- * Execute a plan, the non-parallel version
+ * Execute a plan, the non-parallel version
* ----------------------------------------------------------------
*/
void
-ProcessQuery(Query *parsetree,
- Plan *plan,
- char *argv[],
- Oid *typev,
- int nargs,
- CommandDest dest)
+ProcessQuery(Query * parsetree,
+ Plan * plan,
+ char *argv[],
+ Oid * typev,
+ int nargs,
+ CommandDest dest)
{
- QueryDesc *queryDesc;
- extern int dontExecute; /* from postgres.c */
- extern void print_plan (Plan* p, Query* parsetree); /* from print.c */
+ QueryDesc *queryDesc;
+ extern int dontExecute;/* from postgres.c */
+ extern void print_plan(Plan * p, Query * parsetree); /* from print.c */
- queryDesc = CreateQueryDesc(parsetree, plan, dest);
+ queryDesc = CreateQueryDesc(parsetree, plan, dest);
- if (dontExecute) {
- /* don't execute it, just show the query plan */
- print_plan(plan, parsetree);
- } else
- ProcessQueryDesc(queryDesc);
+ if (dontExecute)
+ {
+ /* don't execute it, just show the query plan */
+ print_plan(plan, parsetree);
+ }
+ else
+ ProcessQueryDesc(queryDesc);
}
-
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 1edb41b46e0..d309ac69a27 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1,15 +1,15 @@
/*-------------------------------------------------------------------------
*
* utility.c--
- * Contains functions which control the execution of the POSTGRES utility
- * commands. At one time acted as an interface between the Lisp and C
- * systems.
+ * Contains functions which control the execution of the POSTGRES utility
+ * commands. At one time acted as an interface between the Lisp and C
+ * systems.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.21 1997/08/31 11:41:55 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.22 1997/09/07 04:49:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,7 +47,7 @@
#include "tcop/dest.h"
#include "tcop/variable.h"
#include "tcop/utility.h"
-#include "fmgr.h" /* For load_file() */
+#include "fmgr.h" /* For load_file() */
#include "storage/fd.h"
#ifndef NO_SECURITY
@@ -58,649 +58,673 @@
/* ----------------
- * CHECK_IF_ABORTED() is used to avoid doing unnecessary
- * processing within an aborted transaction block.
+ * CHECK_IF_ABORTED() is used to avoid doing unnecessary
+ * processing within an aborted transaction block.
* ----------------
*/
#define CHECK_IF_ABORTED() \
- if (IsAbortedTransactionBlockState()) { \
- elog(NOTICE, "(transaction aborted): %s", \
- "queries ignored until END"); \
- commandTag = "*ABORT STATE*"; \
- break; \
- } \
-
+ if (IsAbortedTransactionBlockState()) { \
+ elog(NOTICE, "(transaction aborted): %s", \
+ "queries ignored until END"); \
+ commandTag = "*ABORT STATE*"; \
+ break; \
+ } \
+
/* ----------------
- * general utility function invoker
+ * general utility function invoker
* ----------------
*/
void
-ProcessUtility(Node *parsetree,
- CommandDest dest)
+ProcessUtility(Node * parsetree,
+ CommandDest dest)
{
- char *commandTag = NULL;
- char *relname;
- char *relationName;
- char *userName;
-
- userName = GetPgUserName();
-
- switch (nodeTag(parsetree)) {
- /* ********************************
- * transactions
- * ********************************
- */
- case T_TransactionStmt:
- {
- TransactionStmt *stmt = (TransactionStmt *)parsetree;
- switch (stmt->command) {
- case BEGIN_TRANS:
- commandTag = "BEGIN";
- CHECK_IF_ABORTED();
- BeginTransactionBlock();
- break;
-
- case END_TRANS:
- commandTag = "END";
- EndTransactionBlock();
- break;
-
- case ABORT_TRANS:
- commandTag = "ABORT";
- UserAbortTransactionBlock();
- break;
- }
- }
- break;
-
- /* ********************************
- * portal manipulation
- * ********************************
- */
- case T_ClosePortalStmt:
- {
- ClosePortalStmt *stmt = (ClosePortalStmt *)parsetree;
-
- commandTag = "CLOSE";
- CHECK_IF_ABORTED();
-
- PerformPortalClose(stmt->portalname, dest);
- }
- break;
-
- case T_FetchStmt:
- {
- FetchStmt *stmt = (FetchStmt *)parsetree;
- char *portalName = stmt->portalname;
- bool forward;
- int count;
-
- commandTag = "FETCH";
- CHECK_IF_ABORTED();
-
- forward = (bool)(stmt->direction == FORWARD);
-
- /* parser ensures that count is >= 0 and
- 'fetch ALL' -> 0 */
-
- count = stmt->howMany;
- PerformPortalFetch(portalName, forward, count, commandTag, dest);
- }
- break;
-
- /* ********************************
- * relation and attribute manipulation
- * ********************************
- */
- case T_CreateStmt:
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
-
- DefineRelation((CreateStmt *)parsetree);
- break;
-
- case T_DestroyStmt:
- {
- DestroyStmt *stmt = (DestroyStmt *)parsetree;
- List *arg;
- List *args = stmt->relNames;
- Relation rel;
-
- commandTag = "DROP";
- CHECK_IF_ABORTED();
-
- foreach (arg, args) {
- relname = strVal(lfirst(arg));
- if (IsSystemRelationName(relname))
- elog(WARN, "class \"%s\" is a system catalog",
- relname);
- rel = heap_openr (relname);
- if ( RelationIsValid (rel) )
- {
- if ( stmt->sequence &&
- rel->rd_rel->relkind != RELKIND_SEQUENCE )
- elog (WARN, "Use DROP TABLE to drop table '%s'",
- relname);
- if ( !(stmt->sequence) &&
- rel->rd_rel->relkind == RELKIND_SEQUENCE )
- elog (WARN, "Use DROP SEQUENCE to drop sequence '%s'",
- relname);
- heap_close (rel);
- }
-#ifndef NO_SECURITY
- if (!pg_ownercheck(userName, relname, RELNAME))
- elog(WARN, "you do not own class \"%s\"",
- relname);
-#endif
- }
- foreach (arg, args) {
- relname = strVal(lfirst(arg));
- RemoveRelation(relname);
- }
- }
- break;
-
- case T_PurgeStmt:
- {
- PurgeStmt *stmt = (PurgeStmt *)parsetree;
-
- commandTag = "PURGE";
- CHECK_IF_ABORTED();
-
- RelationPurge(stmt->relname,
- stmt->beforeDate, /* absolute time string */
- stmt->afterDate); /* relative time string */
- }
- break;
-
- case T_CopyStmt:
- {
- CopyStmt *stmt = (CopyStmt *)parsetree;
-
- commandTag = "COPY";
- CHECK_IF_ABORTED();
-
- DoCopy(stmt->relname,
- stmt->binary,
- stmt->oids,
- (bool)(stmt->direction == FROM),
- (bool)(stmt->filename == NULL),
- /* null filename means copy to/from stdout/stdin,
- rather than to/from a file.
- */
- stmt->filename,
- stmt->delimiter);
- }
- break;
-
- case T_AddAttrStmt:
- {
- AddAttrStmt *stmt = (AddAttrStmt *)parsetree;
-
- commandTag = "ADD";
- CHECK_IF_ABORTED();
-
- /* owner checking done in PerformAddAttribute (now recursive) */
- PerformAddAttribute(stmt->relname,
- userName,
- stmt->inh,
- stmt->colDef);
- }
- break;
-
- /*
- * schema
- */
- case T_RenameStmt:
+ char *commandTag = NULL;
+ char *relname;
+ char *relationName;
+ char *userName;
+
+ userName = GetPgUserName();
+
+ switch (nodeTag(parsetree))
{
- RenameStmt *stmt = (RenameStmt *)parsetree;
-
- commandTag = "RENAME";
- CHECK_IF_ABORTED();
-
- relname = stmt->relname;
- if (IsSystemRelationName(relname))
- elog(WARN, "class \"%s\" is a system catalog",
- relname);
-#ifndef NO_SECURITY
- if (!pg_ownercheck(userName, relname, RELNAME))
- elog(WARN, "you do not own class \"%s\"",
- relname);
-#endif
-
- /* ----------------
- * XXX using len == 3 to tell the difference
- * between "rename rel to newrel" and
- * "rename att in rel to newatt" will not
- * work soon because "rename type/operator/rule"
- * stuff is being added. - cim 10/24/90
- * ----------------
- * [another piece of amuzing but useless anecdote -- ay]
- */
- if (stmt->column == NULL) {
- /* ----------------
- * rename relation
+
+ /*
+ * ******************************** transactions ********************************
*
- * Note: we also rename the "type" tuple
- * corresponding to the relation.
- * ----------------
*/
- renamerel(relname, /* old name */
- stmt->newname); /* new name */
- TypeRename(relname, /* old name */
- stmt->newname); /* new name */
- } else {
- /* ----------------
- * rename attribute
- * ----------------
+ case T_TransactionStmt:
+ {
+ TransactionStmt *stmt = (TransactionStmt *) parsetree;
+
+ switch (stmt->command)
+ {
+ case BEGIN_TRANS:
+ commandTag = "BEGIN";
+ CHECK_IF_ABORTED();
+ BeginTransactionBlock();
+ break;
+
+ case END_TRANS:
+ commandTag = "END";
+ EndTransactionBlock();
+ break;
+
+ case ABORT_TRANS:
+ commandTag = "ABORT";
+ UserAbortTransactionBlock();
+ break;
+ }
+ }
+ break;
+
+ /*
+ * ******************************** portal manipulation ********************************
+ *
*/
- renameatt(relname, /* relname */
- stmt->column, /* old att name */
- stmt->newname, /* new att name */
- userName,
- stmt->inh); /* recursive? */
- }
- }
- break;
-
- case T_ChangeACLStmt:
- {
- ChangeACLStmt *stmt = (ChangeACLStmt *)parsetree;
- List *i;
- AclItem *aip;
- unsigned modechg;
-
- commandTag = "CHANGE";
- CHECK_IF_ABORTED();
-
- aip = stmt->aclitem;
- modechg = stmt->modechg;
+ case T_ClosePortalStmt:
+ {
+ ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
+
+ commandTag = "CLOSE";
+ CHECK_IF_ABORTED();
+
+ PerformPortalClose(stmt->portalname, dest);
+ }
+ break;
+
+ case T_FetchStmt:
+ {
+ FetchStmt *stmt = (FetchStmt *) parsetree;
+ char *portalName = stmt->portalname;
+ bool forward;
+ int count;
+
+ commandTag = "FETCH";
+ CHECK_IF_ABORTED();
+
+ forward = (bool) (stmt->direction == FORWARD);
+
+ /*
+ * parser ensures that count is >= 0 and 'fetch ALL' -> 0
+ */
+
+ count = stmt->howMany;
+ PerformPortalFetch(portalName, forward, count, commandTag, dest);
+ }
+ break;
+
+ /*
+ * ******************************** relation and attribute
+ * manipulation ********************************
+ *
+ */
+ case T_CreateStmt:
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+
+ DefineRelation((CreateStmt *) parsetree);
+ break;
+
+ case T_DestroyStmt:
+ {
+ DestroyStmt *stmt = (DestroyStmt *) parsetree;
+ List *arg;
+ List *args = stmt->relNames;
+ Relation rel;
+
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ foreach(arg, args)
+ {
+ relname = strVal(lfirst(arg));
+ if (IsSystemRelationName(relname))
+ elog(WARN, "class \"%s\" is a system catalog",
+ relname);
+ rel = heap_openr(relname);
+ if (RelationIsValid(rel))
+ {
+ if (stmt->sequence &&
+ rel->rd_rel->relkind != RELKIND_SEQUENCE)
+ elog(WARN, "Use DROP TABLE to drop table '%s'",
+ relname);
+ if (!(stmt->sequence) &&
+ rel->rd_rel->relkind == RELKIND_SEQUENCE)
+ elog(WARN, "Use DROP SEQUENCE to drop sequence '%s'",
+ relname);
+ heap_close(rel);
+ }
#ifndef NO_SECURITY
- foreach (i, stmt->relNames) {
- relname = strVal(lfirst(i));
- if (!pg_ownercheck(userName, relname, RELNAME))
- elog(WARN, "you do not own class \"%s\"",
- relname);
- }
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%s\"",
+ relname);
#endif
- foreach (i, stmt->relNames) {
- relname = strVal(lfirst(i));
- ChangeAcl(relname, aip, modechg);
- }
+ }
+ foreach(arg, args)
+ {
+ relname = strVal(lfirst(arg));
+ RemoveRelation(relname);
+ }
+ }
+ break;
- }
- break;
-
- /* ********************************
- * object creation / destruction
- * ********************************
- */
- case T_DefineStmt:
- {
- DefineStmt *stmt = (DefineStmt *)parsetree;
+ case T_PurgeStmt:
+ {
+ PurgeStmt *stmt = (PurgeStmt *) parsetree;
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
+ commandTag = "PURGE";
+ CHECK_IF_ABORTED();
- switch(stmt->defType) {
- case OPERATOR:
- DefineOperator(stmt->defname, /* operator name */
- stmt->definition); /* rest */
+ RelationPurge(stmt->relname,
+ stmt->beforeDate, /* absolute time string */
+ stmt->afterDate); /* relative time string */
+ }
break;
- case P_TYPE:
+
+ case T_CopyStmt:
{
- DefineType (stmt->defname, stmt->definition);
+ CopyStmt *stmt = (CopyStmt *) parsetree;
+
+ commandTag = "COPY";
+ CHECK_IF_ABORTED();
+
+ DoCopy(stmt->relname,
+ stmt->binary,
+ stmt->oids,
+ (bool) (stmt->direction == FROM),
+ (bool) (stmt->filename == NULL),
+
+ /*
+ * null filename means copy to/from stdout/stdin, rather than
+ * to/from a file.
+ */
+ stmt->filename,
+ stmt->delimiter);
}
break;
- case AGGREGATE:
- DefineAggregate(stmt->defname, /*aggregate name */
- stmt->definition); /* rest */
+
+ case T_AddAttrStmt:
+ {
+ AddAttrStmt *stmt = (AddAttrStmt *) parsetree;
+
+ commandTag = "ADD";
+ CHECK_IF_ABORTED();
+
+ /* owner checking done in PerformAddAttribute (now recursive) */
+ PerformAddAttribute(stmt->relname,
+ userName,
+ stmt->inh,
+ stmt->colDef);
+ }
break;
- }
- }
- break;
-
- case T_ViewStmt: /* CREATE VIEW */
- {
- ViewStmt *stmt = (ViewStmt *)parsetree;
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
- DefineView (stmt->viewname, stmt->query); /* retrieve parsetree */
- }
- break;
-
- case T_ProcedureStmt: /* CREATE FUNCTION */
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
- CreateFunction((ProcedureStmt *)parsetree, dest); /* everything */
- break;
-
- case T_IndexStmt: /* CREATE INDEX */
- {
- IndexStmt *stmt = (IndexStmt *)parsetree;
-
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
- /* XXX no support for ARCHIVE indices, yet */
- DefineIndex(stmt->relname, /* relation name */
- stmt->idxname, /* index name */
- stmt->accessMethod, /* am name */
- stmt->indexParams, /* parameters */
- stmt->withClause,
- stmt->unique,
- (Expr*)stmt->whereClause,
- stmt->rangetable);
- }
- break;
-
- case T_RuleStmt: /* CREATE RULE */
- {
- RuleStmt *stmt = (RuleStmt *)parsetree;
- int aclcheck_result;
+ /*
+ * schema
+ */
+ case T_RenameStmt:
+ {
+ RenameStmt *stmt = (RenameStmt *) parsetree;
+ commandTag = "RENAME";
+ CHECK_IF_ABORTED();
+
+ relname = stmt->relname;
+ if (IsSystemRelationName(relname))
+ elog(WARN, "class \"%s\" is a system catalog",
+ relname);
#ifndef NO_SECURITY
- relname = stmt->object->relname;
- aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
- if(aclcheck_result != ACLCHECK_OK)
- elog(WARN, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
-#endif
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
- DefineQueryRewrite(stmt);
- }
- break;
-
- case T_CreateSeqStmt:
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
-
- DefineSequence((CreateSeqStmt *)parsetree);
- break;
-
- case T_ExtendStmt:
- {
- ExtendStmt *stmt = (ExtendStmt *)parsetree;
-
- commandTag = "EXTEND";
- CHECK_IF_ABORTED();
-
- ExtendIndex(stmt->idxname, /* index name */
- (Expr*)stmt->whereClause, /* where */
- stmt->rangetable);
- }
- break;
-
- case T_RemoveStmt:
- {
- RemoveStmt *stmt = (RemoveStmt *)parsetree;
-
- commandTag = "DROP";
- CHECK_IF_ABORTED();
-
- switch(stmt->removeType) {
- case INDEX:
- relname = stmt->name;
- if (IsSystemRelationName(relname))
- elog(WARN, "class \"%s\" is a system catalog index",
- relname);
-#ifndef NO_SECURITY
- if (!pg_ownercheck(userName, relname, RELNAME))
- elog(WARN, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%s\"",
+ relname);
#endif
- RemoveIndex(relname);
+
+ /* ----------------
+ * XXX using len == 3 to tell the difference
+ * between "rename rel to newrel" and
+ * "rename att in rel to newatt" will not
+ * work soon because "rename type/operator/rule"
+ * stuff is being added. - cim 10/24/90
+ * ----------------
+ * [another piece of amuzing but useless anecdote -- ay]
+ */
+ if (stmt->column == NULL)
+ {
+ /* ----------------
+ * rename relation
+ *
+ * Note: we also rename the "type" tuple
+ * corresponding to the relation.
+ * ----------------
+ */
+ renamerel(relname, /* old name */
+ stmt->newname); /* new name */
+ TypeRename(relname, /* old name */
+ stmt->newname); /* new name */
+ }
+ else
+ {
+ /* ----------------
+ * rename attribute
+ * ----------------
+ */
+ renameatt(relname, /* relname */
+ stmt->column, /* old att name */
+ stmt->newname, /* new att name */
+ userName,
+ stmt->inh); /* recursive? */
+ }
+ }
break;
- case RULE:
+
+ case T_ChangeACLStmt:
{
- char *rulename = stmt->name;
- int aclcheck_result;
+ ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
+ List *i;
+ AclItem *aip;
+ unsigned modechg;
+
+ commandTag = "CHANGE";
+ CHECK_IF_ABORTED();
+
+ aip = stmt->aclitem;
+ modechg = stmt->modechg;
#ifndef NO_SECURITY
-
- relationName = RewriteGetRuleEventRel(rulename);
- aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
- if(aclcheck_result != ACLCHECK_OK) {
- elog(WARN, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
- }
+ foreach(i, stmt->relNames)
+ {
+ relname = strVal(lfirst(i));
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "you do not own class \"%s\"",
+ relname);
+ }
#endif
- RemoveRewriteRule(rulename);
+ foreach(i, stmt->relNames)
+ {
+ relname = strVal(lfirst(i));
+ ChangeAcl(relname, aip, modechg);
+ }
+
+ }
+ break;
+
+ /*
+ * ******************************** object creation / destruction ********************************
+ *
+ */
+ case T_DefineStmt:
+ {
+ DefineStmt *stmt = (DefineStmt *) parsetree;
+
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+
+ switch (stmt->defType)
+ {
+ case OPERATOR:
+ DefineOperator(stmt->defname, /* operator name */
+ stmt->definition); /* rest */
+ break;
+ case P_TYPE:
+ {
+ DefineType(stmt->defname, stmt->definition);
+ }
+ break;
+ case AGGREGATE:
+ DefineAggregate(stmt->defname, /* aggregate name */
+ stmt->definition); /* rest */
+ break;
+ }
+ }
+ break;
+
+ case T_ViewStmt: /* CREATE VIEW */
+ {
+ ViewStmt *stmt = (ViewStmt *) parsetree;
+
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
+ }
+ break;
+
+ case T_ProcedureStmt: /* CREATE FUNCTION */
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
+ break;
+
+ case T_IndexStmt: /* CREATE INDEX */
+ {
+ IndexStmt *stmt = (IndexStmt *) parsetree;
+
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ /* XXX no support for ARCHIVE indices, yet */
+ DefineIndex(stmt->relname, /* relation name */
+ stmt->idxname, /* index name */
+ stmt->accessMethod, /* am name */
+ stmt->indexParams, /* parameters */
+ stmt->withClause,
+ stmt->unique,
+ (Expr *) stmt->whereClause,
+ stmt->rangetable);
}
break;
- case P_TYPE:
+
+ case T_RuleStmt: /* CREATE RULE */
+ {
+ RuleStmt *stmt = (RuleStmt *) parsetree;
+ int aclcheck_result;
+
#ifndef NO_SECURITY
- /* XXX moved to remove.c */
+ relname = stmt->object->relname;
+ aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
+ if (aclcheck_result != ACLCHECK_OK)
+ elog(WARN, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
#endif
- RemoveType(stmt->name);
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+ DefineQueryRewrite(stmt);
+ }
+ break;
+
+ case T_CreateSeqStmt:
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+
+ DefineSequence((CreateSeqStmt *) parsetree);
+ break;
+
+ case T_ExtendStmt:
+ {
+ ExtendStmt *stmt = (ExtendStmt *) parsetree;
+
+ commandTag = "EXTEND";
+ CHECK_IF_ABORTED();
+
+ ExtendIndex(stmt->idxname, /* index name */
+ (Expr *) stmt->whereClause, /* where */
+ stmt->rangetable);
+ }
break;
- case VIEW:
+
+ case T_RemoveStmt:
{
- char *viewName = stmt->name;
- char *ruleName;
+ RemoveStmt *stmt = (RemoveStmt *) parsetree;
+
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ switch (stmt->removeType)
+ {
+ case INDEX:
+ relname = stmt->name;
+ if (IsSystemRelationName(relname))
+ elog(WARN, "class \"%s\" is a system catalog index",
+ relname);
+#ifndef NO_SECURITY
+ if (!pg_ownercheck(userName, relname, RELNAME))
+ elog(WARN, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+#endif
+ RemoveIndex(relname);
+ break;
+ case RULE:
+ {
+ char *rulename = stmt->name;
+ int aclcheck_result;
#ifndef NO_SECURITY
-
- ruleName = MakeRetrieveViewRuleName(viewName);
- relationName = RewriteGetRuleEventRel(ruleName);
- if (!pg_ownercheck(userName, relationName, RELNAME))
- elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
- pfree(ruleName);
+
+ relationName = RewriteGetRuleEventRel(rulename);
+ aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
+ if (aclcheck_result != ACLCHECK_OK)
+ {
+ elog(WARN, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
+ }
+#endif
+ RemoveRewriteRule(rulename);
+ }
+ break;
+ case P_TYPE:
+#ifndef NO_SECURITY
+ /* XXX moved to remove.c */
+#endif
+ RemoveType(stmt->name);
+ break;
+ case VIEW:
+ {
+ char *viewName = stmt->name;
+ char *ruleName;
+
+#ifndef NO_SECURITY
+
+ ruleName = MakeRetrieveViewRuleName(viewName);
+ relationName = RewriteGetRuleEventRel(ruleName);
+ if (!pg_ownercheck(userName, relationName, RELNAME))
+ elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+ pfree(ruleName);
#endif
- RemoveView(viewName);
+ RemoveView(viewName);
+ }
+ break;
+ }
+ break;
}
break;
- }
- break;
- }
- break;
- case T_RemoveAggrStmt:
- {
- RemoveAggrStmt *stmt = (RemoveAggrStmt *)parsetree;
- commandTag = "DROP";
- CHECK_IF_ABORTED();
- RemoveAggregate(stmt->aggname, stmt->aggtype);
- }
- break;
-
- case T_RemoveFuncStmt:
- {
- RemoveFuncStmt *stmt = (RemoveFuncStmt *)parsetree;
- commandTag = "DROP";
- CHECK_IF_ABORTED();
- RemoveFunction(stmt->funcname,
- length(stmt->args),
- stmt->args);
- }
- break;
-
- case T_RemoveOperStmt:
- {
- RemoveOperStmt *stmt = (RemoveOperStmt *)parsetree;
- char* type1 = (char*) NULL;
- char *type2 = (char*) NULL;
-
- commandTag = "DROP";
- CHECK_IF_ABORTED();
-
- if (lfirst(stmt->args)!=NULL)
- type1 = strVal(lfirst(stmt->args));
- if (lsecond(stmt->args)!=NULL)
- type2 = strVal(lsecond(stmt->args));
- RemoveOperator(stmt->opname, type1, type2);
- }
- break;
-
- case T_VersionStmt:
- {
- elog(WARN, "CREATE VERSION is not currently implemented");
- }
- break;
-
- case T_CreatedbStmt:
- {
- CreatedbStmt *stmt = (CreatedbStmt *)parsetree;
+ case T_RemoveAggrStmt:
+ {
+ RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
- commandTag = "CREATEDB";
- CHECK_IF_ABORTED();
- createdb(stmt->dbname);
- }
- break;
-
- case T_DestroydbStmt:
- {
- DestroydbStmt *stmt = (DestroydbStmt *)parsetree;
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+ RemoveAggregate(stmt->aggname, stmt->aggtype);
+ }
+ break;
- commandTag = "DESTROYDB";
- CHECK_IF_ABORTED();
- destroydb(stmt->dbname);
- }
- break;
-
- /* Query-level asynchronous notification */
- case T_NotifyStmt:
- {
- NotifyStmt *stmt = (NotifyStmt *)parsetree;
+ case T_RemoveFuncStmt:
+ {
+ RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
- commandTag = "NOTIFY";
- CHECK_IF_ABORTED();
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+ RemoveFunction(stmt->funcname,
+ length(stmt->args),
+ stmt->args);
+ }
+ break;
- Async_Notify(stmt->relname);
- }
- break;
-
- case T_ListenStmt:
- {
- ListenStmt *stmt = (ListenStmt *)parsetree;
+ case T_RemoveOperStmt:
+ {
+ RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
+ char *type1 = (char *) NULL;
+ char *type2 = (char *) NULL;
+
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ if (lfirst(stmt->args) != NULL)
+ type1 = strVal(lfirst(stmt->args));
+ if (lsecond(stmt->args) != NULL)
+ type2 = strVal(lsecond(stmt->args));
+ RemoveOperator(stmt->opname, type1, type2);
+ }
+ break;
- commandTag = "LISTEN";
- CHECK_IF_ABORTED();
+ case T_VersionStmt:
+ {
+ elog(WARN, "CREATE VERSION is not currently implemented");
+ }
+ break;
- Async_Listen(stmt->relname,MasterPid);
- }
- break;
-
- /* ********************************
- * dynamic loader
- * ********************************
- */
- case T_LoadStmt:
- {
- LoadStmt *stmt = (LoadStmt *)parsetree;
- FILE *fp;
- char *filename;
-
- commandTag = "LOAD";
- CHECK_IF_ABORTED();
-
- filename = stmt->filename;
- closeAllVfds();
- if ((fp = AllocateFile(filename, "r")) == NULL)
- elog(WARN, "LOAD: could not open file %s", filename);
- FreeFile(fp);
- load_file(filename);
- }
- break;
+ case T_CreatedbStmt:
+ {
+ CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
- case T_ClusterStmt:
- {
- ClusterStmt *stmt = (ClusterStmt *)parsetree;
+ commandTag = "CREATEDB";
+ CHECK_IF_ABORTED();
+ createdb(stmt->dbname);
+ }
+ break;
- commandTag = "CLUSTER";
- CHECK_IF_ABORTED();
+ case T_DestroydbStmt:
+ {
+ DestroydbStmt *stmt = (DestroydbStmt *) parsetree;
- cluster(stmt->relname, stmt->indexname);
- }
- break;
-
- case T_VacuumStmt:
- commandTag = "VACUUM";
- CHECK_IF_ABORTED();
- vacuum( ((VacuumStmt *) parsetree)->vacrel,
- ((VacuumStmt *) parsetree)->verbose,
- ((VacuumStmt *) parsetree)->analyze,
- ((VacuumStmt *) parsetree)->va_spec);
- break;
-
- case T_ExplainStmt:
- {
- ExplainStmt *stmt = (ExplainStmt *)parsetree;
+ commandTag = "DESTROYDB";
+ CHECK_IF_ABORTED();
+ destroydb(stmt->dbname);
+ }
+ break;
- commandTag = "EXPLAIN";
- CHECK_IF_ABORTED();
+ /* Query-level asynchronous notification */
+ case T_NotifyStmt:
+ {
+ NotifyStmt *stmt = (NotifyStmt *) parsetree;
- ExplainQuery(stmt->query, stmt->verbose, dest);
- }
- break;
-
- /* ********************************
- Tioga-related statements
- *********************************/
- case T_RecipeStmt:
- {
- RecipeStmt* stmt = (RecipeStmt*)parsetree;
- commandTag="EXECUTE RECIPE";
- CHECK_IF_ABORTED();
- beginRecipe(stmt);
- }
- break;
+ commandTag = "NOTIFY";
+ CHECK_IF_ABORTED();
- /* ********************************
- * set variable statements
- *********************************/
- case T_VariableSetStmt:
- {
- VariableSetStmt *n = (VariableSetStmt *) parsetree;
- SetPGVariable(n->name, n->value);
- commandTag = "SET VARIABLE";
- }
- break;
-
- case T_VariableShowStmt:
- {
- VariableShowStmt *n = (VariableShowStmt *) parsetree;
- GetPGVariable(n->name);
- commandTag = "SHOW VARIABLE";
- }
- break;
-
- case T_VariableResetStmt:
- {
- VariableResetStmt *n = (VariableResetStmt *) parsetree;
- ResetPGVariable(n->name);
- commandTag = "RESET VARIABLE";
+ Async_Notify(stmt->relname);
+ }
+ break;
+
+ case T_ListenStmt:
+ {
+ ListenStmt *stmt = (ListenStmt *) parsetree;
+
+ commandTag = "LISTEN";
+ CHECK_IF_ABORTED();
+
+ Async_Listen(stmt->relname, MasterPid);
+ }
+ break;
+
+ /*
+ * ******************************** dynamic loader ********************************
+ *
+ */
+ case T_LoadStmt:
+ {
+ LoadStmt *stmt = (LoadStmt *) parsetree;
+ FILE *fp;
+ char *filename;
+
+ commandTag = "LOAD";
+ CHECK_IF_ABORTED();
+
+ filename = stmt->filename;
+ closeAllVfds();
+ if ((fp = AllocateFile(filename, "r")) == NULL)
+ elog(WARN, "LOAD: could not open file %s", filename);
+ FreeFile(fp);
+ load_file(filename);
+ }
+ break;
+
+ case T_ClusterStmt:
+ {
+ ClusterStmt *stmt = (ClusterStmt *) parsetree;
+
+ commandTag = "CLUSTER";
+ CHECK_IF_ABORTED();
+
+ cluster(stmt->relname, stmt->indexname);
+ }
+ break;
+
+ case T_VacuumStmt:
+ commandTag = "VACUUM";
+ CHECK_IF_ABORTED();
+ vacuum(((VacuumStmt *) parsetree)->vacrel,
+ ((VacuumStmt *) parsetree)->verbose,
+ ((VacuumStmt *) parsetree)->analyze,
+ ((VacuumStmt *) parsetree)->va_spec);
+ break;
+
+ case T_ExplainStmt:
+ {
+ ExplainStmt *stmt = (ExplainStmt *) parsetree;
+
+ commandTag = "EXPLAIN";
+ CHECK_IF_ABORTED();
+
+ ExplainQuery(stmt->query, stmt->verbose, dest);
+ }
+ break;
+
+ /*
+ * ******************************** Tioga-related statements *******************************
+ */
+ case T_RecipeStmt:
+ {
+ RecipeStmt *stmt = (RecipeStmt *) parsetree;
+
+ commandTag = "EXECUTE RECIPE";
+ CHECK_IF_ABORTED();
+ beginRecipe(stmt);
+ }
+ break;
+
+ /*
+ * ******************************** set variable statements *******************************
+ */
+ case T_VariableSetStmt:
+ {
+ VariableSetStmt *n = (VariableSetStmt *) parsetree;
+
+ SetPGVariable(n->name, n->value);
+ commandTag = "SET VARIABLE";
+ }
+ break;
+
+ case T_VariableShowStmt:
+ {
+ VariableShowStmt *n = (VariableShowStmt *) parsetree;
+
+ GetPGVariable(n->name);
+ commandTag = "SHOW VARIABLE";
+ }
+ break;
+
+ case T_VariableResetStmt:
+ {
+ VariableResetStmt *n = (VariableResetStmt *) parsetree;
+
+ ResetPGVariable(n->name);
+ commandTag = "RESET VARIABLE";
+ }
+ break;
+
+ /*
+ * ******************************** TRIGGER statements *******************************
+ */
+ case T_CreateTrigStmt:
+ commandTag = "CREATE";
+ CHECK_IF_ABORTED();
+
+ CreateTrigger((CreateTrigStmt *) parsetree);
+ break;
+
+ case T_DropTrigStmt:
+ commandTag = "DROP";
+ CHECK_IF_ABORTED();
+
+ DropTrigger((DropTrigStmt *) parsetree);
+ break;
+
+ /*
+ * ******************************** default ********************************
+ *
+ */
+ default:
+ elog(WARN, "ProcessUtility: command #%d unsupported",
+ nodeTag(parsetree));
+ break;
}
- break;
-
- /* ********************************
- * TRIGGER statements
- *********************************/
- case T_CreateTrigStmt:
- commandTag = "CREATE";
- CHECK_IF_ABORTED();
-
- CreateTrigger((CreateTrigStmt *)parsetree);
- break;
-
- case T_DropTrigStmt:
- commandTag = "DROP";
- CHECK_IF_ABORTED();
-
- DropTrigger((DropTrigStmt *)parsetree);
- break;
-
- /* ********************************
- * default
- * ********************************
+
+ /* ----------------
+ * tell fe/be or whatever that we're done.
+ * ----------------
*/
- default:
- elog(WARN, "ProcessUtility: command #%d unsupported",
- nodeTag(parsetree));
- break;
- }
-
- /* ----------------
- * tell fe/be or whatever that we're done.
- * ----------------
- */
- EndCommand(commandTag, dest);
+ EndCommand(commandTag, dest);
}
-
diff --git a/src/backend/tcop/variable.c b/src/backend/tcop/variable.c
index c2a2a754e95..d394881ab3a 100644
--- a/src/backend/tcop/variable.c
+++ b/src/backend/tcop/variable.c
@@ -2,7 +2,7 @@
* Routines for handling of 'SET var TO', 'SHOW var' and 'RESET var'
* statements.
*
- * $Id: variable.c,v 1.13 1997/08/12 20:15:50 momjian Exp $
+ * $Id: variable.c,v 1.14 1997/09/07 04:49:37 momjian Exp $
*
*/
@@ -15,421 +15,471 @@
#include "utils/builtins.h"
#include "optimizer/internal.h"
-extern Cost _cpu_page_wight_;
-extern Cost _cpu_index_page_wight_;
-extern bool _use_geqo_;
-extern int32 _use_geqo_rels_;
-extern bool _use_right_sided_plans_;
+extern Cost _cpu_page_wight_;
+extern Cost _cpu_index_page_wight_;
+extern bool _use_geqo_;
+extern int32 _use_geqo_rels_;
+extern bool _use_right_sided_plans_;
/*-----------------------------------------------------------------------*/
#if USE_EURODATES
-#define DATE_EURO TRUE
+#define DATE_EURO TRUE
#else
#define DATE_EURO FALSE
#endif
/*-----------------------------------------------------------------------*/
struct PGVariables PGVariables =
- {
- { DATE_EURO, Date_Postgres }
- };
+{
+ {DATE_EURO, Date_Postgres}
+};
/*-----------------------------------------------------------------------*/
-static const char *get_token(char **tok, char **val, const char *str)
+static const char *
+get_token(char **tok, char **val, const char *str)
{
- const char *start;
- int len = 0;
-
- *tok = NULL;
- if (val != NULL) *val = NULL;
-
- if ( !(*str) )
- return NULL;
-
- /* skip white spaces */
- while (isspace(*str)) str++;
- if ( *str == ',' || *str == '=' )
- elog(WARN, "Syntax error near (%s): empty setting", str);
-
- /* end of string? then return NULL */
- if ( !(*str) )
- return NULL;
-
- /* OK, at beginning of non-NULL string... */
- start = str;
-
- /*
- * count chars in token until we hit white space or comma
- * or '=' or end of string
- */
- while ( *str && (! isspace(*str))
- && *str != ',' && *str != '=' )
- {
- str++;
- len++;
- }
-
- *tok = (char*) PALLOC(len + 1);
- strNcpy (*tok, start, len);
-
- /* skip white spaces */
- while ( isspace(*str)) str++;
-
- /* end of string? */
- if ( !(*str) ) {
- return(str);
-
- /* delimiter? */
- } else if ( *str == ',' ) {
- return (++str);
-
- } else if ((val == NULL) || ( *str != '=' )) {
+ const char *start;
+ int len = 0;
+
+ *tok = NULL;
+ if (val != NULL)
+ *val = NULL;
+
+ if (!(*str))
+ return NULL;
+
+ /* skip white spaces */
+ while (isspace(*str))
+ str++;
+ if (*str == ',' || *str == '=')
+ elog(WARN, "Syntax error near (%s): empty setting", str);
+
+ /* end of string? then return NULL */
+ if (!(*str))
+ return NULL;
+
+ /* OK, at beginning of non-NULL string... */
+ start = str;
+
+ /*
+ * count chars in token until we hit white space or comma or '=' or
+ * end of string
+ */
+ while (*str && (!isspace(*str))
+ && *str != ',' && *str != '=')
+ {
+ str++;
+ len++;
+ }
+
+ *tok = (char *) PALLOC(len + 1);
+ strNcpy(*tok, start, len);
+
+ /* skip white spaces */
+ while (isspace(*str))
+ str++;
+
+ /* end of string? */
+ if (!(*str))
+ {
+ return (str);
+
+ /* delimiter? */
+ }
+ else if (*str == ',')
+ {
+ return (++str);
+
+ }
+ else if ((val == NULL) || (*str != '='))
+ {
+ elog(WARN, "Syntax error near (%s)", str);
+ };
+
+ str++; /* '=': get value */
+ len = 0;
+
+ /* skip white spaces */
+ while (isspace(*str))
+ str++;
+
+ if (*str == ',' || !(*str))
+ elog(WARN, "Syntax error near (=%s)", str);
+
+ start = str;
+
+ /*
+ * count chars in token's value until we hit white space or comma or
+ * end of string
+ */
+ while (*str && (!isspace(*str)) && *str != ',')
+ {
+ str++;
+ len++;
+ }
+
+ *val = (char *) PALLOC(len + 1);
+ strNcpy(*val, start, len);
+
+ /* skip white spaces */
+ while (isspace(*str))
+ str++;
+
+ if (!(*str))
+ return (NULL);
+ if (*str == ',')
+ return (++str);
+
elog(WARN, "Syntax error near (%s)", str);
- };
-
- str++; /* '=': get value */
- len = 0;
-
- /* skip white spaces */
- while ( isspace(*str)) str++;
-
- if ( *str == ',' || !(*str) )
- elog(WARN, "Syntax error near (=%s)", str);
-
- start = str;
-
- /*
- * count chars in token's value until we hit white space or comma
- * or end of string
- */
- while ( *str && (! isspace(*str)) && *str != ',' )
- {
- str++;
- len++;
- }
-
- *val = (char*) PALLOC(len + 1);
- strNcpy (*val, start, len);
-
- /* skip white spaces */
- while ( isspace(*str)) str++;
-
- if ( !(*str) )
- return (NULL);
- if ( *str == ',' )
- return (++str);
-
- elog(WARN, "Syntax error near (%s)", str);
-
- return str;
+
+ return str;
}
/*-----------------------------------------------------------------------*/
-static bool parse_null(const char *value)
- {
+static bool
+parse_null(const char *value)
+{
return TRUE;
- }
+}
-static bool show_null(const char *value)
- {
+static bool
+show_null(const char *value)
+{
return TRUE;
- }
+}
-static bool reset_null(const char *value)
- {
+static bool
+reset_null(const char *value)
+{
return TRUE;
- }
+}
-static bool parse_geqo (const char *value)
+static bool
+parse_geqo(const char *value)
{
- const char *rest;
- char *tok, *val;
-
- rest = get_token (&tok, &val, value);
- if ( tok == NULL )
- elog(WARN, "Value undefined");
-
- if (( rest ) && ( *rest != '\0' ))
- elog(WARN, "Unable to parse '%s'", value);
-
- if ( strcasecmp (tok, "on") == 0 )
- {
- int32 geqo_rels = GEQO_RELS;
-
- if ( val != NULL )
- {
- geqo_rels = pg_atoi (val, sizeof(int32), '\0');
- if ( geqo_rels <= 1 )
- elog(WARN, "Bad value for # of relations (%s)", val);
- PFREE(val);
- }
- _use_geqo_ = true;
- _use_geqo_rels_ = geqo_rels;
- }
- else if ( strcasecmp (tok, "off") == 0 )
- {
- if (( val != NULL ) && ( *val != '\0' ))
- elog(WARN, "%s does not allow a parameter",tok);
- _use_geqo_ = false;
- }
- else
- elog(WARN, "Bad value for GEQO (%s)", value);
-
- PFREE(tok);
- return TRUE;
+ const char *rest;
+ char *tok,
+ *val;
+
+ rest = get_token(&tok, &val, value);
+ if (tok == NULL)
+ elog(WARN, "Value undefined");
+
+ if ((rest) && (*rest != '\0'))
+ elog(WARN, "Unable to parse '%s'", value);
+
+ if (strcasecmp(tok, "on") == 0)
+ {
+ int32 geqo_rels = GEQO_RELS;
+
+ if (val != NULL)
+ {
+ geqo_rels = pg_atoi(val, sizeof(int32), '\0');
+ if (geqo_rels <= 1)
+ elog(WARN, "Bad value for # of relations (%s)", val);
+ PFREE(val);
+ }
+ _use_geqo_ = true;
+ _use_geqo_rels_ = geqo_rels;
+ }
+ else if (strcasecmp(tok, "off") == 0)
+ {
+ if ((val != NULL) && (*val != '\0'))
+ elog(WARN, "%s does not allow a parameter", tok);
+ _use_geqo_ = false;
+ }
+ else
+ elog(WARN, "Bad value for GEQO (%s)", value);
+
+ PFREE(tok);
+ return TRUE;
}
-static bool show_geqo ()
+static bool
+show_geqo()
{
- if ( _use_geqo_ )
- elog (NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_);
- else
- elog (NOTICE, "GEQO is OFF");
- return TRUE;
+ if (_use_geqo_)
+ elog(NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_);
+ else
+ elog(NOTICE, "GEQO is OFF");
+ return TRUE;
}
-static bool reset_geqo ()
+static bool
+reset_geqo()
{
#ifdef GEQO
- _use_geqo_ = true;
+ _use_geqo_ = true;
#else
- _use_geqo_ = false;
+ _use_geqo_ = false;
#endif
- _use_geqo_rels_ = GEQO_RELS;
- return TRUE;
+ _use_geqo_rels_ = GEQO_RELS;
+ return TRUE;
}
-static bool parse_r_plans (const char *value)
+static bool
+parse_r_plans(const char *value)
{
- if ( strcasecmp (value, "on") == 0 )
- _use_right_sided_plans_ = true;
- else if ( strcasecmp (value, "off") == 0 )
- _use_right_sided_plans_ = false;
- else
- elog(WARN, "Bad value for Right-sided Plans (%s)", value);
-
- return TRUE;
+ if (strcasecmp(value, "on") == 0)
+ _use_right_sided_plans_ = true;
+ else if (strcasecmp(value, "off") == 0)
+ _use_right_sided_plans_ = false;
+ else
+ elog(WARN, "Bad value for Right-sided Plans (%s)", value);
+
+ return TRUE;
}
-static bool show_r_plans ()
+static bool
+show_r_plans()
{
- if ( _use_right_sided_plans_ )
- elog (NOTICE, "Right-sided Plans are ON");
- else
- elog (NOTICE, "Right-sided Plans are OFF");
- return TRUE;
+ if (_use_right_sided_plans_)
+ elog(NOTICE, "Right-sided Plans are ON");
+ else
+ elog(NOTICE, "Right-sided Plans are OFF");
+ return TRUE;
}
-static bool reset_r_plans ()
+static bool
+reset_r_plans()
{
#ifdef USE_RIGHT_SIDED_PLANS
- _use_right_sided_plans_ = true;
+ _use_right_sided_plans_ = true;
#else
- _use_right_sided_plans_ = false;
+ _use_right_sided_plans_ = false;
#endif
- return TRUE;
+ return TRUE;
}
-static bool parse_cost_heap (const char *value)
+static bool
+parse_cost_heap(const char *value)
{
- float32 res = float4in ((char*)value);
-
- _cpu_page_wight_ = *res;
-
- return TRUE;
+ float32 res = float4in((char *) value);
+
+ _cpu_page_wight_ = *res;
+
+ return TRUE;
}
-static bool show_cost_heap ()
+static bool
+show_cost_heap()
{
- elog (NOTICE, "COST_HEAP is %f", _cpu_page_wight_);
- return TRUE;
+ elog(NOTICE, "COST_HEAP is %f", _cpu_page_wight_);
+ return TRUE;
}
-static bool reset_cost_heap ()
+static bool
+reset_cost_heap()
{
- _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
- return TRUE;
+ _cpu_page_wight_ = _CPU_PAGE_WEIGHT_;
+ return TRUE;
}
-static bool parse_cost_index (const char *value)
+static bool
+parse_cost_index(const char *value)
{
- float32 res = float4in ((char*)value);
-
- _cpu_index_page_wight_ = *res;
-
- return TRUE;
+ float32 res = float4in((char *) value);
+
+ _cpu_index_page_wight_ = *res;
+
+ return TRUE;
}
-static bool show_cost_index ()
+static bool
+show_cost_index()
{
- elog (NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_);
- return TRUE;
+ elog(NOTICE, "COST_INDEX is %f", _cpu_index_page_wight_);
+ return TRUE;
}
-static bool reset_cost_index ()
+static bool
+reset_cost_index()
{
- _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
- return TRUE;
+ _cpu_index_page_wight_ = _CPU_INDEX_PAGE_WEIGHT_;
+ return TRUE;
}
-static bool parse_date(const char *value)
+static bool
+parse_date(const char *value)
{
- char *tok;
- int dcnt = 0, ecnt = 0;
+ char *tok;
+ int dcnt = 0,
+ ecnt = 0;
- while((value = get_token(&tok, NULL, value)) != 0)
+ while ((value = get_token(&tok, NULL, value)) != 0)
{
/* Ugh. Somebody ought to write a table driven version -- mjl */
- if(!strcasecmp(tok, "iso"))
- {
+ if (!strcasecmp(tok, "iso"))
+ {
DateStyle = USE_ISO_DATES;
dcnt++;
- }
- else if(!strcasecmp(tok, "sql"))
- {
+ }
+ else if (!strcasecmp(tok, "sql"))
+ {
DateStyle = USE_SQL_DATES;
dcnt++;
- }
- else if(!strcasecmp(tok, "postgres"))
- {
+ }
+ else if (!strcasecmp(tok, "postgres"))
+ {
DateStyle = USE_POSTGRES_DATES;
dcnt++;
- }
- else if(!strncasecmp(tok, "euro", 4))
- {
+ }
+ else if (!strncasecmp(tok, "euro", 4))
+ {
EuroDates = TRUE;
ecnt++;
- }
- else if((!strcasecmp(tok, "us"))
- || (!strncasecmp(tok, "noneuro", 7)))
- {
+ }
+ else if ((!strcasecmp(tok, "us"))
+ || (!strncasecmp(tok, "noneuro", 7)))
+ {
EuroDates = FALSE;
ecnt++;
- }
- else if(!strcasecmp(tok, "default"))
- {
+ }
+ else if (!strcasecmp(tok, "default"))
+ {
DateStyle = USE_POSTGRES_DATES;
EuroDates = FALSE;
ecnt++;
- }
+ }
else
- {
+ {
elog(WARN, "Bad value for date style (%s)", tok);
- }
+ }
PFREE(tok);
}
- if(dcnt > 1 || ecnt > 1)
+ if (dcnt > 1 || ecnt > 1)
elog(NOTICE, "Conflicting settings for date");
return TRUE;
}
-static bool show_date()
- {
- char buf[64];
+static bool
+show_date()
+{
+ char buf[64];
- strcpy( buf, "DateStyle is ");
- switch (DateStyle) {
+ strcpy(buf, "DateStyle is ");
+ switch (DateStyle)
+ {
case USE_ISO_DATES:
- strcat( buf, "ISO");
+ strcat(buf, "ISO");
break;
case USE_SQL_DATES:
- strcat( buf, "SQL");
+ strcat(buf, "SQL");
break;
default:
- strcat( buf, "Postgres");
+ strcat(buf, "Postgres");
break;
};
- strcat( buf, " with ");
- strcat( buf, ((EuroDates)? "European": "US (NonEuropean)"));
- strcat( buf, " conventions");
+ strcat(buf, " with ");
+ strcat(buf, ((EuroDates) ? "European" : "US (NonEuropean)"));
+ strcat(buf, " conventions");
elog(NOTICE, buf, NULL);
return TRUE;
- }
+}
-static bool reset_date()
- {
+static bool
+reset_date()
+{
DateStyle = USE_POSTGRES_DATES;
EuroDates = FALSE;
return TRUE;
- }
+}
/*-----------------------------------------------------------------------*/
struct VariableParsers
+{
+ const char *name;
+ bool(*parser) (const char *);
+ bool(*show) ();
+ bool(*reset) ();
+} VariableParsers[] =
+
+{
{
- const char *name;
- bool (*parser)(const char *);
- bool (*show)();
- bool (*reset)();
- } VariableParsers[] =
+ "datestyle", parse_date, show_date, reset_date
+ },
{
- { "datestyle", parse_date, show_date, reset_date },
- { "timezone", parse_null, show_null, reset_null },
- { "cost_heap", parse_cost_heap,
- show_cost_heap, reset_cost_heap },
- { "cost_index", parse_cost_index,
- show_cost_index, reset_cost_index },
- { "geqo", parse_geqo, show_geqo, reset_geqo },
- { "r_plans", parse_r_plans, show_r_plans, reset_r_plans },
- { NULL, NULL, NULL }
- };
+ "timezone", parse_null, show_null, reset_null
+ },
+ {
+ "cost_heap", parse_cost_heap,
+ show_cost_heap, reset_cost_heap
+ },
+ {
+ "cost_index", parse_cost_index,
+ show_cost_index, reset_cost_index
+ },
+ {
+ "geqo", parse_geqo, show_geqo, reset_geqo
+ },
+ {
+ "r_plans", parse_r_plans, show_r_plans, reset_r_plans
+ },
+ {
+ NULL, NULL, NULL
+ }
+};
/*-----------------------------------------------------------------------*/
-bool SetPGVariable(const char *name, const char *value)
- {
+bool
+SetPGVariable(const char *name, const char *value)
+{
struct VariableParsers *vp;
- for(vp = VariableParsers; vp->name; vp++)
- {
- if(!strcasecmp(vp->name, name))
- return (vp->parser)(value);
- }
+ for (vp = VariableParsers; vp->name; vp++)
+ {
+ if (!strcasecmp(vp->name, name))
+ return (vp->parser) (value);
+ }
elog(NOTICE, "Unrecognized variable %s", name);
return TRUE;
- }
+}
/*-----------------------------------------------------------------------*/
-bool GetPGVariable(const char *name)
- {
+bool
+GetPGVariable(const char *name)
+{
struct VariableParsers *vp;
- for(vp = VariableParsers; vp->name; vp++)
- {
- if(!strcasecmp(vp->name, name))
- return (vp->show)();
- }
+ for (vp = VariableParsers; vp->name; vp++)
+ {
+ if (!strcasecmp(vp->name, name))
+ return (vp->show) ();
+ }
elog(NOTICE, "Unrecognized variable %s", name);
return TRUE;
- }
+}
/*-----------------------------------------------------------------------*/
-bool ResetPGVariable(const char *name)
- {
+bool
+ResetPGVariable(const char *name)
+{
struct VariableParsers *vp;
- for(vp = VariableParsers; vp->name; vp++)
- {
- if(!strcasecmp(vp->name, name))
- return (vp->reset)();
- }
+ for (vp = VariableParsers; vp->name; vp++)
+ {
+ if (!strcasecmp(vp->name, name))
+ return (vp->reset) ();
+ }
elog(NOTICE, "Unrecognized variable %s", name);
return TRUE;
- }
+}
diff --git a/src/backend/tioga/Arr_TgRecipe.h b/src/backend/tioga/Arr_TgRecipe.h
index 365f4647d6e..c6992732c7f 100644
--- a/src/backend/tioga/Arr_TgRecipe.h
+++ b/src/backend/tioga/Arr_TgRecipe.h
@@ -14,7 +14,7 @@
#define Arr_TgNodePtr_INITIAL_SIZE 32
#endif
/***************************************************************/
-/* Do not modify anything below this line. */
+/* Do not modify anything below this line. */
/***************************************************************/
/* -- Defining types and function for Arr_TgString type -- */
@@ -27,15 +27,17 @@
#define _ARR_TgString_
#ifndef ARR_TgString_INITIAL_SIZE
-#define ARR_TgString_INITIAL_SIZE 32 /* change this size to suit your need */
-#endif /* ARR_TgString_INITIAL_SIZE */
-
-typedef struct Arr_TgString {
- size_t num;
- size_t size;
- size_t valSize;
- TgString *val;
-} Arr_TgString;
+#define ARR_TgString_INITIAL_SIZE 32 /* change this size to suit your
+ * need */
+#endif /* ARR_TgString_INITIAL_SIZE */
+
+typedef struct Arr_TgString
+{
+ size_t num;
+ size_t size;
+ size_t valSize;
+ TgString *val;
+} Arr_TgString;
#define newArr_TgString() \
(Arr_TgString *) NewVarray(ARR_TgString_INITIAL_SIZE, sizeof(TgString))
@@ -49,7 +51,7 @@ typedef struct Arr_TgString {
#define deleteArr_TgString(A) FreeVarray(A)
-#endif /* _ARR_TgString_ */
+#endif /* _ARR_TgString_ */
/* -- Defining types and function for Arr_TgElementPtr type -- */
/* -- the following must be supplied by the user:
@@ -61,15 +63,17 @@ typedef struct Arr_TgString {
#define _ARR_TgElementPtr_
#ifndef ARR_TgElementPtr_INITIAL_SIZE
-#define ARR_TgElementPtr_INITIAL_SIZE 32 /* change this size to suit your need */
-#endif /* ARR_TgElementPtr_INITIAL_SIZE */
-
-typedef struct Arr_TgElementPtr {
- size_t num;
- size_t size;
- size_t valSize;
- TgElementPtr *val;
-} Arr_TgElementPtr;
+#define ARR_TgElementPtr_INITIAL_SIZE 32 /* change this size to
+ * suit your need */
+#endif /* ARR_TgElementPtr_INITIAL_SIZE */
+
+typedef struct Arr_TgElementPtr
+{
+ size_t num;
+ size_t size;
+ size_t valSize;
+ TgElementPtr *val;
+} Arr_TgElementPtr;
#define newArr_TgElementPtr() \
(Arr_TgElementPtr *) NewVarray(ARR_TgElementPtr_INITIAL_SIZE, sizeof(TgElementPtr))
@@ -83,7 +87,7 @@ typedef struct Arr_TgElementPtr {
#define deleteArr_TgElementPtr(A) FreeVarray(A)
-#endif /* _ARR_TgElementPtr_ */
+#endif /* _ARR_TgElementPtr_ */
/* -- Defining types and function for Arr_TgNodePtr type -- */
/* -- the following must be supplied by the user:
@@ -95,15 +99,17 @@ typedef struct Arr_TgElementPtr {
#define _ARR_TgNodePtr_
#ifndef ARR_TgNodePtr_INITIAL_SIZE
-#define ARR_TgNodePtr_INITIAL_SIZE 32 /* change this size to suit your need */
-#endif /* ARR_TgNodePtr_INITIAL_SIZE */
-
-typedef struct Arr_TgNodePtr {
- size_t num;
- size_t size;
- size_t valSize;
- TgNodePtr *val;
-} Arr_TgNodePtr;
+#define ARR_TgNodePtr_INITIAL_SIZE 32 /* change this size to suit your
+ * need */
+#endif /* ARR_TgNodePtr_INITIAL_SIZE */
+
+typedef struct Arr_TgNodePtr
+{
+ size_t num;
+ size_t size;
+ size_t valSize;
+ TgNodePtr *val;
+} Arr_TgNodePtr;
#define newArr_TgNodePtr() \
(Arr_TgNodePtr *) NewVarray(ARR_TgNodePtr_INITIAL_SIZE, sizeof(TgNodePtr))
@@ -117,4 +123,4 @@ typedef struct Arr_TgNodePtr {
#define deleteArr_TgNodePtr(A) FreeVarray(A)
-#endif /* _ARR_TgNodePtr_ */
+#endif /* _ARR_TgNodePtr_ */
diff --git a/src/backend/tioga/Varray.c b/src/backend/tioga/Varray.c
index 3ed45c66561..6279616f7ba 100644
--- a/src/backend/tioga/Varray.c
+++ b/src/backend/tioga/Varray.c
@@ -2,47 +2,49 @@
*
* Varray.c --
*
- * routines to provide a generic set of functions to handle variable sized
- * arrays. originally by Jiang Wu
+ * routines to provide a generic set of functions to handle variable sized
+ * arrays. originally by Jiang Wu
* ************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "Varray.h"
-Varray *NewVarray(size_t nobj, size_t size)
+Varray *
+NewVarray(size_t nobj, size_t size)
/*
* NewVarray -- allocate a Varray to contain an array of val each of which
- * is size valSize. Returns the Varray if successful,
- * returns NULL otherwise.
+ * is size valSize. Returns the Varray if successful,
+ * returns NULL otherwise.
*/
{
- Varray *result;
+ Varray *result;
- if (nobj == 0)
- nobj = VARRAY_INITIAL_SIZE;
- result = (Varray *) malloc(sizeof(Varray));
- result->val = (void *) calloc(nobj, size);
- if (result == NULL)
- return NULL;
- result->size = size;
- result->nobj = 0;
- result->maxObj = nobj;
- return result;
+ if (nobj == 0)
+ nobj = VARRAY_INITIAL_SIZE;
+ result = (Varray *) malloc(sizeof(Varray));
+ result->val = (void *) calloc(nobj, size);
+ if (result == NULL)
+ return NULL;
+ result->size = size;
+ result->nobj = 0;
+ result->maxObj = nobj;
+ return result;
}
-int AppendVarray(Varray *array, void *value, CopyingFunct copy)
+int
+AppendVarray(Varray * array, void *value, CopyingFunct copy)
/*
* AppendVarray -- append value to the end of array. This function
- * returns the size of the array after the addition of
- * the new element.
+ * returns the size of the array after the addition of
+ * the new element.
*/
{
- copy(value, VARRAY_NTH(array->val, array->size, array->nobj));
- array->nobj++;
- if (array->nobj >= array->maxObj) {
- ENLARGE_VARRAY(array, array->maxObj / 2);
- }
- return array->nobj;
+ copy(value, VARRAY_NTH(array->val, array->size, array->nobj));
+ array->nobj++;
+ if (array->nobj >= array->maxObj)
+ {
+ ENLARGE_VARRAY(array, array->maxObj / 2);
+ }
+ return array->nobj;
}
-
diff --git a/src/backend/tioga/Varray.h b/src/backend/tioga/Varray.h
index f6d01c23db4..82251d78b3f 100644
--- a/src/backend/tioga/Varray.h
+++ b/src/backend/tioga/Varray.h
@@ -1,45 +1,46 @@
/* ********************************************************************
*
* Varray.h -- header file for varray.c which provides a generic
- * set of functions to handle variable sized arrays.
+ * set of functions to handle variable sized arrays.
*
- * originally by Jiang Wu
+ * originally by Jiang Wu
* ********************************************************************/
#ifndef _VARRAY_H_
#define _VARRAY_H_
-typedef struct _varray {
- size_t nobj; /* number of objects in this array */
- size_t maxObj; /* max. number of objects in this array */
- size_t size; /* size of each element in the array */
- void *val; /* array of elements */
-} Varray;
+typedef struct _varray
+{
+ size_t nobj; /* number of objects in this array */
+ size_t maxObj; /* max. number of objects in this array */
+ size_t size; /* size of each element in the array */
+ void *val; /* array of elements */
+} Varray;
/* type for custom copying function */
-typedef void (*CopyingFunct) (void *from, void *to);
+typedef void (*CopyingFunct) (void *from, void *to);
#define VARRAY_INITIAL_SIZE 32
#define ENLARGE_VARRAY(ARRAY, INC) \
(ARRAY)->maxObj += (INC); \
(ARRAY)->val = (void *) realloc((ARRAY)->val, \
- (ARRAY)->size * (ARRAY)->maxObj)
+ (ARRAY)->size * (ARRAY)->maxObj)
#define VARRAY_NTH(VAL, SIZE, N) (((char *) (VAL)) + (SIZE) * (N))
#define FreeVarray(ARRAY) \
if ((ARRAY) != NULL) { free((ARRAY)->val); free((ARRAY)); (ARRAY) = NULL ; }
-
+
#define ModifyVarray(ARRAY, N, NEW, COPY) \
if ((N) < (ARRAY)->nobj) \
- (COPY)(VARRAY_NTH((ARRAY)->val, (ARRAY)->size, (N)), (NEW))
+ (COPY)(VARRAY_NTH((ARRAY)->val, (ARRAY)->size, (N)), (NEW))
#define GetVarray(ARRAY, N) \
((N) < (ARRAY)->nobj ? VARRAY_NTH((ARRAY)->val, (ARRAY)->size, (N)) \
- : NULL)
+ : NULL)
-extern Varray *NewVarray(size_t nobj, size_t size);
-extern int AppendVarray(Varray *array, void *value, CopyingFunct copy);
+extern Varray *NewVarray(size_t nobj, size_t size);
+extern int AppendVarray(Varray * array, void *value, CopyingFunct copy);
-#endif /* _VARRAY_H_ */
+#endif /* _VARRAY_H_ */
diff --git a/src/backend/tioga/tgRecipe.c b/src/backend/tioga/tgRecipe.c
index ef08f8e3f58..effc221610e 100644
--- a/src/backend/tioga/tgRecipe.c
+++ b/src/backend/tioga/tgRecipe.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* tgRecipe.c--
- * Tioga recipe-related definitions
- * these functions can be used in both the frontend and the
- * backend
- *
- * this file must be kept current with recipe-schema.sql
+ * Tioga recipe-related definitions
+ * these functions can be used in both the frontend and the
+ * backend
+ *
+ * this file must be kept current with recipe-schema.sql
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tioga/Attic/tgRecipe.c,v 1.3 1997/08/12 20:15:52 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tioga/Attic/tgRecipe.c,v 1.4 1997/09/07 04:49:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,7 +20,7 @@
#include "postgres.h"
#include "tioga/tgRecipe.h"
-#include "catalog/catalog.h" /*for newoid() */
+#include "catalog/catalog.h" /* for newoid() */
static Arr_TgString *TextArray2ArrTgString(char *str);
@@ -31,81 +31,89 @@ static Arr_TgString *TextArray2ArrTgString(char *str);
#define ARRAY_ELEM_SEPARATOR ','
/* maximum length of query string */
-#define MAX_QBUF_LENGTH 2048
+#define MAX_QBUF_LENGTH 2048
/**** the queries being used ********/
#define Q_RETRIEVE_RECIPE_BYNAME \
- "select * from Recipes where Recipes.elemName = '%s';"
+ "select * from Recipes where Recipes.elemName = '%s';"
#define Q_RETRIEVE_ELEMENTS_IN_RECIPE \
- "select e.* from Element e, Node n where n.belongsTo = '%s' and n.nodeElem = e.elemName;"
+ "select e.* from Element e, Node n where n.belongsTo = '%s' and n.nodeElem = e.elemName;"
#define Q_RETRIEVE_NODES_IN_RECIPE \
- "select * from Node n where n.belongsTo = '%s'"
+ "select * from Node n where n.belongsTo = '%s'"
#define Q_LOOKUP_EDGES_IN_RECIPE \
- "select * from Edge e where e.belongsTo = '%s'"
+ "select * from Edge e where e.belongsTo = '%s'"
/* static functions only used here */
-static void fillTgElement(TgElement *elem, PortalBuffer *pbuf, int tupno);
-static void fillTgNode(TgRecipe *r, TgNode *node, PortalBuffer *pbuf, int tupno);
-static TgRecipe* fillTgRecipe(PortalBuffer* pbuf, int tupno);
-static void lookupEdges(TgRecipe *r, char* name);
-static void fillAllNodes(TgRecipe *r, char* name);
-static void fillAllElements(TgRecipe *r, char* name);
-static TgNode* connectTee(TgRecipe *r, TgNodePtr fromNode, TgNodePtr toNode,
- int fromPort, int toPort);
+static void fillTgElement(TgElement * elem, PortalBuffer * pbuf, int tupno);
+static void fillTgNode(TgRecipe * r, TgNode * node, PortalBuffer * pbuf, int tupno);
+static TgRecipe *fillTgRecipe(PortalBuffer * pbuf, int tupno);
+static void lookupEdges(TgRecipe * r, char *name);
+static void fillAllNodes(TgRecipe * r, char *name);
+static void fillAllElements(TgRecipe * r, char *name);
+static TgNode *
+connectTee(TgRecipe * r, TgNodePtr fromNode, TgNodePtr toNode,
+ int fromPort, int toPort);
/*
* TextArray2ArrTgString -- take a string of the form:
- * {"fooo", "bar", "xxxxx"} (for postgres)
- * and parse it into a Array of TgString's
+ * {"fooo", "bar", "xxxxx"} (for postgres)
+ * and parse it into a Array of TgString's
*
* always returns a valid Arr_TgString. It could be a newly initialized one with
* zero elements
*/
-Arr_TgString*
+Arr_TgString *
TextArray2ArrTgString(char *str)
{
- Arr_TgString *result;
-
- char* beginQuote;
- char* endQuote;
- int nextlen;
- char* word;
-
- result = newArr_TgString();
-
- if ((str == NULL) || (str[0] == '\0'))
- return result;
-
- if (*str != ARRAY_LEFT_DELIM) {
- elog(NOTICE,"TextArray2ArrTgString: badly formed string, must have %c as \
+ Arr_TgString *result;
+
+ char *beginQuote;
+ char *endQuote;
+ int nextlen;
+ char *word;
+
+ result = newArr_TgString();
+
+ if ((str == NULL) || (str[0] == '\0'))
+ return result;
+
+ if (*str != ARRAY_LEFT_DELIM)
+ {
+ elog(NOTICE, "TextArray2ArrTgString: badly formed string, must have %c as \
first character\n", ARRAY_LEFT_DELIM);
- return result;
- }
-
- str++; /* skip the first { */
- while ( *str != '}' ) {
- if (*str == '\0') {
- elog(NOTICE,"TextArray2ArrTgString: text string ended prematurely\n");
- return result;
- }
-
- if ((beginQuote = index(str, ARRAY_ELEM_LEFT)) == NULL) {
- elog(NOTICE,"textArray2ArrTgString: missing a begin quote\n");
- return result;
- }
- if ( (endQuote = index(beginQuote+1,'"')) == NULL) {
- elog(NOTICE,"textArray2ArrTgString: missing an end quote\n");
- return result;
- }
- nextlen = endQuote - beginQuote; /* don't subtract one here because we
- need the extra character for \0 anyway */
- word = (char*) malloc(nextlen);
- strNcpy(word, beginQuote+1, nextlen-1);
- addArr_TgString(result, (TgString*)&word);
- free (word);
- str = endQuote + 1;
- }
- return result;
+ return result;
+ }
+
+ str++; /* skip the first { */
+ while (*str != '}')
+ {
+ if (*str == '\0')
+ {
+ elog(NOTICE, "TextArray2ArrTgString: text string ended prematurely\n");
+ return result;
+ }
+
+ if ((beginQuote = index(str, ARRAY_ELEM_LEFT)) == NULL)
+ {
+ elog(NOTICE, "textArray2ArrTgString: missing a begin quote\n");
+ return result;
+ }
+ if ((endQuote = index(beginQuote + 1, '"')) == NULL)
+ {
+ elog(NOTICE, "textArray2ArrTgString: missing an end quote\n");
+ return result;
+ }
+ nextlen = endQuote - beginQuote; /* don't subtract one here
+ * because we need the
+ * extra character for \0
+ * anyway */
+ word = (char *) malloc(nextlen);
+ strNcpy(word, beginQuote + 1, nextlen - 1);
+ addArr_TgString(result, (TgString *) & word);
+ free(word);
+ str = endQuote + 1;
+ }
+ return result;
}
/* -------------------------------------
@@ -115,20 +123,21 @@ findElemInRecipe()
XXX Currently, this is done by linear search. Change to using a hash table.
-------------------------------------- */
-TgElement*
-findElemInRecipe(TgRecipe *r, char* elemName)
+TgElement *
+findElemInRecipe(TgRecipe * r, char *elemName)
{
- int i;
- Arr_TgElementPtr* arr = r->elements;
- TgElement* e;
-
- for (i=0;i<arr->num;i++) {
- e = (TgElement*)arr->val[i];
- if (strcmp(e->elemName, elemName) == 0)
- return e;
- }
- elog (NOTICE, "Element named %s not found in recipe named %s", elemName, r->elmValue.elemName);
- return NULL;
+ int i;
+ Arr_TgElementPtr *arr = r->elements;
+ TgElement *e;
+
+ for (i = 0; i < arr->num; i++)
+ {
+ e = (TgElement *) arr->val[i];
+ if (strcmp(e->elemName, elemName) == 0)
+ return e;
+ }
+ elog(NOTICE, "Element named %s not found in recipe named %s", elemName, r->elmValue.elemName);
+ return NULL;
}
/* -------------------------------------
@@ -138,271 +147,306 @@ findNodeInRecipe()
XXX Currently, this is done by linear search. Change to using a hash table.
-------------------------------------- */
-TgNode*
-findNodeInRecipe(TgRecipe *r, char* nodeName)
+TgNode *
+findNodeInRecipe(TgRecipe * r, char *nodeName)
{
- int i;
- Arr_TgNodePtr* arr = r->allNodes;
- TgNode *n;
-
- for (i=0;i<arr->num;i++) {
- n = (TgNode*)arr->val[i];
- if (strcmp(n->nodeName, nodeName) == 0)
- return n;
- }
- elog (NOTICE, "Node named %s not found in recipe named %s", nodeName, r->elmValue.elemName);
- return NULL;
+ int i;
+ Arr_TgNodePtr *arr = r->allNodes;
+ TgNode *n;
+
+ for (i = 0; i < arr->num; i++)
+ {
+ n = (TgNode *) arr->val[i];
+ if (strcmp(n->nodeName, nodeName) == 0)
+ return n;
+ }
+ elog(NOTICE, "Node named %s not found in recipe named %s", nodeName, r->elmValue.elemName);
+ return NULL;
}
/* -------------------------------------
fillTgNode
- takes a query result in the PortalBuffer containing a Node
- and converts it to a C Node strcture.
- The Node structure passed in is 'filled' appropriately
+ takes a query result in the PortalBuffer containing a Node
+ and converts it to a C Node strcture.
+ The Node structure passed in is 'filled' appropriately
-------------------------------------- */
void
-fillTgNode(TgRecipe* r, TgNode *node, PortalBuffer *pbuf, int tupno)
+fillTgNode(TgRecipe * r, TgNode * node, PortalBuffer * pbuf, int tupno)
{
- char* nodeType;
- char* nodeElem;
- char* locString; /* ascii string rep of the point */
- static int attnums_initialized = 0;
- static int nodeName_attnum;
- static int nodeElem_attnum;
- static int nodeType_attnum;
- static int loc_attnum;
- TgNodePtr BlankNodePtr;
- int i;
-
- if (!attnums_initialized) {
- /* the first time fillTgNode is called,
- we find out all the relevant attribute numbers in a TgNode
- so subsequent calls are speeded up,
- the assumption is that the schema won't change between calls*/
- nodeName_attnum = PQfnumber(pbuf, tupno, "nodeName");
- nodeElem_attnum = PQfnumber(pbuf, tupno, "nodeElem");
- nodeType_attnum = PQfnumber(pbuf, tupno, "nodeType");
- loc_attnum = PQfnumber(pbuf, tupno, "loc");
- attnums_initialized = 1;
- }
- node->nodeName = PQgetAttr(pbuf, tupno, nodeName_attnum);
- locString = PQgetvalue(pbuf, tupno, loc_attnum);
- if (locString == NULL || locString[0] == '\0') {
- node->loc.x = 0; node->loc.y = 0; /* assign to zero for default */
- }
- else
- {
- float x,y;
- sscanf(locString, "(%f, %f)", &x, &y);
- node->loc.x = x;
- node->loc.y = y;
- }
- nodeElem = PQgetvalue(pbuf, tupno, nodeElem_attnum);
- node->nodeElem = findElemInRecipe(r,nodeElem);
- node->inNodes = newArr_TgNodePtr();
- node->outNodes = newArr_TgNodePtr();
-
- /* fill the inNodes array with as many NULL's are there are inPorts in
- * the underlying element */
- BlankNodePtr = (TgNodePtr)NULL;
- for (i = 0 ; i < node->nodeElem->inPorts->num ; i++)
- addArr_TgNodePtr(node->inNodes, &BlankNodePtr);
-
- /* fill the outNodes array with as many NULL's are there are inPorts in
- * the underlying element */
- for (i = 0 ; i < node->nodeElem->outPorts->num ; i++)
- addArr_TgNodePtr(node->outNodes, &BlankNodePtr);
-
- nodeType = PQgetvalue(pbuf, tupno, nodeType_attnum);
-
- if (strcmp(nodeType, "Ingred") == 0)
- node->nodeType = TG_INGRED_NODE;
- else if (strcmp(nodeType, "Eye") == 0)
- node->nodeType = TG_EYE_NODE;
- else if (strcmp(nodeType, "Recipe") == 0)
- node->nodeType = TG_RECIPE_NODE;
- else
- elog(NOTICE, "fillTgNode: unknown nodeType field value : %s\n", nodeType);
-
+ char *nodeType;
+ char *nodeElem;
+ char *locString; /* ascii string rep of the point */
+ static int attnums_initialized = 0;
+ static int nodeName_attnum;
+ static int nodeElem_attnum;
+ static int nodeType_attnum;
+ static int loc_attnum;
+ TgNodePtr BlankNodePtr;
+ int i;
+
+ if (!attnums_initialized)
+ {
+
+ /*
+ * the first time fillTgNode is called, we find out all the
+ * relevant attribute numbers in a TgNode so subsequent calls are
+ * speeded up, the assumption is that the schema won't change
+ * between calls
+ */
+ nodeName_attnum = PQfnumber(pbuf, tupno, "nodeName");
+ nodeElem_attnum = PQfnumber(pbuf, tupno, "nodeElem");
+ nodeType_attnum = PQfnumber(pbuf, tupno, "nodeType");
+ loc_attnum = PQfnumber(pbuf, tupno, "loc");
+ attnums_initialized = 1;
+ }
+ node->nodeName = PQgetAttr(pbuf, tupno, nodeName_attnum);
+ locString = PQgetvalue(pbuf, tupno, loc_attnum);
+ if (locString == NULL || locString[0] == '\0')
+ {
+ node->loc.x = 0;
+ node->loc.y = 0; /* assign to zero for default */
+ }
+ else
+ {
+ float x,
+ y;
+
+ sscanf(locString, "(%f, %f)", &x, &y);
+ node->loc.x = x;
+ node->loc.y = y;
+ }
+ nodeElem = PQgetvalue(pbuf, tupno, nodeElem_attnum);
+ node->nodeElem = findElemInRecipe(r, nodeElem);
+ node->inNodes = newArr_TgNodePtr();
+ node->outNodes = newArr_TgNodePtr();
+
+ /*
+ * fill the inNodes array with as many NULL's are there are inPorts in
+ * the underlying element
+ */
+ BlankNodePtr = (TgNodePtr) NULL;
+ for (i = 0; i < node->nodeElem->inPorts->num; i++)
+ addArr_TgNodePtr(node->inNodes, &BlankNodePtr);
+
+ /*
+ * fill the outNodes array with as many NULL's are there are inPorts
+ * in the underlying element
+ */
+ for (i = 0; i < node->nodeElem->outPorts->num; i++)
+ addArr_TgNodePtr(node->outNodes, &BlankNodePtr);
+
+ nodeType = PQgetvalue(pbuf, tupno, nodeType_attnum);
+
+ if (strcmp(nodeType, "Ingred") == 0)
+ node->nodeType = TG_INGRED_NODE;
+ else if (strcmp(nodeType, "Eye") == 0)
+ node->nodeType = TG_EYE_NODE;
+ else if (strcmp(nodeType, "Recipe") == 0)
+ node->nodeType = TG_RECIPE_NODE;
+ else
+ elog(NOTICE, "fillTgNode: unknown nodeType field value : %s\n", nodeType);
+
}
/* -------------------------------------
fillTgElement
- takes a query result in the PortalBuffer containing a Element
- and converts it to a C TgElement strcture.
- The TgElement structure passed in is 'filled' appropriately
+ takes a query result in the PortalBuffer containing a Element
+ and converts it to a C TgElement strcture.
+ The TgElement structure passed in is 'filled' appropriately
------------------------------------ */
void
-fillTgElement(TgElement *elem, PortalBuffer *pbuf, int tupno)
+fillTgElement(TgElement * elem, PortalBuffer * pbuf, int tupno)
{
- char* srcLang, *elemType;
- static int attnums_initialized = 0;
- static int elemName_attnum;
- static int elemType_attnum;
- static int inPorts_attnum;
- static int inTypes_attnum;
- static int outPorts_attnum;
- static int outTypes_attnum;
- static int doc_attnum;
- static int keywords_attnum;
- static int icon_attnum;
- static int srcLang_attnum;
- static int src_attnum;
- static int owner_attnum;
-
- if (!attnums_initialized) {
- /* the first time fillTgElement is called,
- we find out all the relevant attribute numbers in a TgElement
- so subsequent calls are speeded up,
- the assumption is that the schema won't change between calls*/
- elemName_attnum = PQfnumber(pbuf, tupno, "elemName");
- elemType_attnum = PQfnumber(pbuf, tupno, "elemType");
- inPorts_attnum = PQfnumber(pbuf, tupno, "inPorts");
- inTypes_attnum = PQfnumber(pbuf, tupno, "inTypes");
- outPorts_attnum = PQfnumber(pbuf, tupno, "outPorts");
- outTypes_attnum = PQfnumber(pbuf, tupno, "outTypes");
- doc_attnum = PQfnumber(pbuf, tupno, "doc");
- keywords_attnum = PQfnumber(pbuf, tupno, "keywords");
- icon_attnum = PQfnumber(pbuf, tupno, "icon");
- srcLang_attnum = PQfnumber(pbuf, tupno, "srcLang");
- src_attnum = PQfnumber(pbuf, tupno, "src");
- attnums_initialized = 1;
- }
-
- elem->elemName = PQgetAttr(pbuf, tupno, elemName_attnum);
- elem->inPorts = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, inPorts_attnum));
- elem->inTypes = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, inTypes_attnum));
- elem->outPorts = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, outPorts_attnum));
- elem->outTypes = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, outTypes_attnum));
- elem->doc = PQgetAttr(pbuf, tupno, doc_attnum);
- elem->keywords = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, keywords_attnum));
- elem->icon = PQgetAttr(pbuf,tupno, icon_attnum);
- elem->src = PQgetAttr(pbuf,tupno, src_attnum);
- elem->owner = PQgetAttr(pbuf,tupno, owner_attnum);
-
- /* we don't need to keep the value returned so use PQgetvalue()
- instead of PQgetAttr() */
- srcLang = PQgetvalue(pbuf,tupno, srcLang_attnum);
-
- if (strcmp(srcLang, "SQL") == 0)
- elem->srcLang = TG_SQL;
- else
- if (strcmp(srcLang, "C") == 0)
- elem->srcLang = TG_C;
- else
- if (strcmp(srcLang, "RecipeGraph") == 0)
- elem->srcLang = TG_RECIPE_GRAPH;
- else
- if (strcmp(srcLang, "Compiled") == 0)
- elem->srcLang = TG_COMPILED;
- else
- elog(NOTICE, "fillTgElement(): unknown srcLang field value : %s\n", srcLang);
-
- elemType = PQgetvalue(pbuf, tupno, elemType_attnum);
- if (strcmp(elemType, "Ingred") == 0)
- elem->elemType = TG_INGRED;
- else if (strcmp(elemType, "Eye") == 0)
- elem->elemType = TG_EYE;
- else if (strcmp(elemType, "Recipe") == 0)
- elem->elemType = TG_RECIPE;
- else
- elog(NOTICE, "fillTgElement(): unknown elemType field value : %s\n", elemType);
+ char *srcLang,
+ *elemType;
+ static int attnums_initialized = 0;
+ static int elemName_attnum;
+ static int elemType_attnum;
+ static int inPorts_attnum;
+ static int inTypes_attnum;
+ static int outPorts_attnum;
+ static int outTypes_attnum;
+ static int doc_attnum;
+ static int keywords_attnum;
+ static int icon_attnum;
+ static int srcLang_attnum;
+ static int src_attnum;
+ static int owner_attnum;
+
+ if (!attnums_initialized)
+ {
+
+ /*
+ * the first time fillTgElement is called, we find out all the
+ * relevant attribute numbers in a TgElement so subsequent calls
+ * are speeded up, the assumption is that the schema won't change
+ * between calls
+ */
+ elemName_attnum = PQfnumber(pbuf, tupno, "elemName");
+ elemType_attnum = PQfnumber(pbuf, tupno, "elemType");
+ inPorts_attnum = PQfnumber(pbuf, tupno, "inPorts");
+ inTypes_attnum = PQfnumber(pbuf, tupno, "inTypes");
+ outPorts_attnum = PQfnumber(pbuf, tupno, "outPorts");
+ outTypes_attnum = PQfnumber(pbuf, tupno, "outTypes");
+ doc_attnum = PQfnumber(pbuf, tupno, "doc");
+ keywords_attnum = PQfnumber(pbuf, tupno, "keywords");
+ icon_attnum = PQfnumber(pbuf, tupno, "icon");
+ srcLang_attnum = PQfnumber(pbuf, tupno, "srcLang");
+ src_attnum = PQfnumber(pbuf, tupno, "src");
+ attnums_initialized = 1;
+ }
+
+ elem->elemName = PQgetAttr(pbuf, tupno, elemName_attnum);
+ elem->inPorts = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, inPorts_attnum));
+ elem->inTypes = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, inTypes_attnum));
+ elem->outPorts = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, outPorts_attnum));
+ elem->outTypes = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, outTypes_attnum));
+ elem->doc = PQgetAttr(pbuf, tupno, doc_attnum);
+ elem->keywords = TextArray2ArrTgString(PQgetvalue(pbuf, tupno, keywords_attnum));
+ elem->icon = PQgetAttr(pbuf, tupno, icon_attnum);
+ elem->src = PQgetAttr(pbuf, tupno, src_attnum);
+ elem->owner = PQgetAttr(pbuf, tupno, owner_attnum);
+
+ /*
+ * we don't need to keep the value returned so use PQgetvalue()
+ * instead of PQgetAttr()
+ */
+ srcLang = PQgetvalue(pbuf, tupno, srcLang_attnum);
+
+ if (strcmp(srcLang, "SQL") == 0)
+ elem->srcLang = TG_SQL;
+ else if (strcmp(srcLang, "C") == 0)
+ elem->srcLang = TG_C;
+ else if (strcmp(srcLang, "RecipeGraph") == 0)
+ elem->srcLang = TG_RECIPE_GRAPH;
+ else if (strcmp(srcLang, "Compiled") == 0)
+ elem->srcLang = TG_COMPILED;
+ else
+ elog(NOTICE, "fillTgElement(): unknown srcLang field value : %s\n", srcLang);
+
+ elemType = PQgetvalue(pbuf, tupno, elemType_attnum);
+ if (strcmp(elemType, "Ingred") == 0)
+ elem->elemType = TG_INGRED;
+ else if (strcmp(elemType, "Eye") == 0)
+ elem->elemType = TG_EYE;
+ else if (strcmp(elemType, "Recipe") == 0)
+ elem->elemType = TG_RECIPE;
+ else
+ elog(NOTICE, "fillTgElement(): unknown elemType field value : %s\n", elemType);
}
+
/* -------------------------------------
-lookupEdges -
- look up the edges of a recipe and fill in the inNodes
- and outNodes of each node.
- In the process of connecting edges, we detect tee's and create
- teeNodes. We add the teeNodes to the allNodes field of r as well
+lookupEdges -
+ look up the edges of a recipe and fill in the inNodes
+ and outNodes of each node.
+ In the process of connecting edges, we detect tee's and create
+ teeNodes. We add the teeNodes to the allNodes field of r as well
------------------------------------ */
-void
-lookupEdges(TgRecipe *r, char* name)
+void
+lookupEdges(TgRecipe * r, char *name)
{
- char qbuf[MAX_QBUF_LENGTH];
- int i;
- char *pqres;
- char *pbufname;
- PortalBuffer *pbuf;
- int ntups;
- int fromNode_attnum;
- int fromPort_attnum;
- int toPort_attnum;
- int toNode_attnum;
- char *toNode, *fromNode;
- char *toPortStr, *fromPortStr;
- int toPort, fromPort;
-
- TgNodePtr fromNodePtr, toNodePtr;
-
- sprintf(qbuf, Q_LOOKUP_EDGES_IN_RECIPE, name);
- pqres = PQexec(qbuf);
- pqres = PQexec(qbuf);
- if (*pqres == 'R' || *pqres == 'E') {
- elog(NOTICE, "lookupEdges(): Error while executing query : %s\n", qbuf);
- elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
- return;
- }
- pbufname = ++pqres;
- pbuf = PQparray(pbufname);
- ntups = PQntuplesGroup(pbuf,0);
-
- if (ntups == 0) { return; }
-
- fromNode_attnum = PQfnumber(pbuf, 0, "fromNode");
- fromPort_attnum = PQfnumber(pbuf, 0, "fromPort");
- toNode_attnum = PQfnumber(pbuf, 0, "toNode");
- toPort_attnum = PQfnumber(pbuf, 0, "toPort");
-
- for (i=0;i<ntups;i++) {
-
- fromNode = PQgetvalue(pbuf, i, fromNode_attnum);
- toNode = PQgetvalue(pbuf, i, toNode_attnum);
- fromPortStr = PQgetvalue(pbuf, i, fromPort_attnum);
- toPortStr = PQgetvalue(pbuf, i, toPort_attnum);
-
- if (!fromPortStr || fromPortStr[0] == '\0') {
- elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with invalid fromPort value!");
- return;
- }
- if (!toPortStr || toPortStr[0] == '\0') {
- elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with invalid toPort value!!");
- return;
- }
- fromPort = atoi(fromPortStr);
- toPort = atoi(toPortStr);
-
- fromNodePtr = findNodeInRecipe(r, fromNode);
- if (!fromNodePtr) {
- elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with bad fromNode value!");
- return;
- }
- toNodePtr = findNodeInRecipe(r, toNode);
- if (!toNodePtr) {
- elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with bad toNode value!");
- return;
- }
-
- /* check to see if the from port is already connected.
- if it is, then this means we should construct a Tee node
- */
- if (fromNodePtr->outNodes->val[fromPort-1] != NULL) {
- TgNodePtr tn;
-
- tn = connectTee(r,fromNodePtr, toNodePtr, fromPort, toPort);
- addArr_TgNodePtr(r->allNodes,&tn);
- } else {
- fromNodePtr->outNodes->val[fromPort-1] = toNodePtr;
- toNodePtr->inNodes->val[toPort-1] = fromNodePtr;
- }
- }
-
- PQclear(pbufname);
+ char qbuf[MAX_QBUF_LENGTH];
+ int i;
+ char *pqres;
+ char *pbufname;
+ PortalBuffer *pbuf;
+ int ntups;
+ int fromNode_attnum;
+ int fromPort_attnum;
+ int toPort_attnum;
+ int toNode_attnum;
+ char *toNode,
+ *fromNode;
+ char *toPortStr,
+ *fromPortStr;
+ int toPort,
+ fromPort;
+
+ TgNodePtr fromNodePtr,
+ toNodePtr;
+
+ sprintf(qbuf, Q_LOOKUP_EDGES_IN_RECIPE, name);
+ pqres = PQexec(qbuf);
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E')
+ {
+ elog(NOTICE, "lookupEdges(): Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf, 0);
+
+ if (ntups == 0)
+ {
+ return;
+ }
+
+ fromNode_attnum = PQfnumber(pbuf, 0, "fromNode");
+ fromPort_attnum = PQfnumber(pbuf, 0, "fromPort");
+ toNode_attnum = PQfnumber(pbuf, 0, "toNode");
+ toPort_attnum = PQfnumber(pbuf, 0, "toPort");
+
+ for (i = 0; i < ntups; i++)
+ {
+
+ fromNode = PQgetvalue(pbuf, i, fromNode_attnum);
+ toNode = PQgetvalue(pbuf, i, toNode_attnum);
+ fromPortStr = PQgetvalue(pbuf, i, fromPort_attnum);
+ toPortStr = PQgetvalue(pbuf, i, toPort_attnum);
+
+ if (!fromPortStr || fromPortStr[0] == '\0')
+ {
+ elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with invalid fromPort value!");
+ return;
+ }
+ if (!toPortStr || toPortStr[0] == '\0')
+ {
+ elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with invalid toPort value!!");
+ return;
+ }
+ fromPort = atoi(fromPortStr);
+ toPort = atoi(toPortStr);
+
+ fromNodePtr = findNodeInRecipe(r, fromNode);
+ if (!fromNodePtr)
+ {
+ elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with bad fromNode value!");
+ return;
+ }
+ toNodePtr = findNodeInRecipe(r, toNode);
+ if (!toNodePtr)
+ {
+ elog(NOTICE, "lookupEdges(): SANITY CHECK failed. Edge with bad toNode value!");
+ return;
+ }
+
+ /*
+ * check to see if the from port is already connected. if it is,
+ * then this means we should construct a Tee node
+ */
+ if (fromNodePtr->outNodes->val[fromPort - 1] != NULL)
+ {
+ TgNodePtr tn;
+
+ tn = connectTee(r, fromNodePtr, toNodePtr, fromPort, toPort);
+ addArr_TgNodePtr(r->allNodes, &tn);
+ }
+ else
+ {
+ fromNodePtr->outNodes->val[fromPort - 1] = toNodePtr;
+ toNodePtr->inNodes->val[toPort - 1] = fromNodePtr;
+ }
+ }
+
+ PQclear(pbufname);
}
/*
@@ -412,216 +456,235 @@ lookupEdges(TgRecipe *r, char* name)
returns the teeNode created
*/
-static TgNode*
-connectTee(TgRecipe *r, TgNodePtr fromNode, TgNodePtr toNode,
- int fromPort, int toPort)
+static TgNode *
+connectTee(TgRecipe * r, TgNodePtr fromNode, TgNodePtr toNode,
+ int fromPort, int toPort)
{
- TgNodePtr origToNode;
- TgNodePtr tn;
- TgNodePtr BlankNodePtr;
- int origToPort;
- int i;
-
- /* the toNode formerly pointed to */
- origToNode = fromNode->outNodes->val[fromPort-1];
-
- if (origToNode == NULL) {
- elog(NOTICE,"Internal Error: connectTee() called with a null origToNode");
- return;
- }
-
- for (i=0;i<origToNode->inNodes->num;i++) {
- if (origToNode->inNodes->val[i] == fromNode)
- break;
- }
-
- /* the inport of the former toNode */
- /* ports start with 1, array indices start from 0 */
- origToPort = i + 1;
-
- /* add a tee node now. */
- tn = malloc(sizeof(TgNode));
- /* generate a name for the tee node table */
- tn->nodeName = malloc(50);
- sprintf(tn->nodeName, "tee_%d", newoid());
-/* tn->nodeName = NULL; */
-
- tn->nodeType = TG_TEE_NODE;
- tn->nodeElem = NULL;
- tn->inNodes = newArr_TgNodePtr();
- tn->outNodes = newArr_TgNodePtr();
-
- BlankNodePtr = (TgNodePtr)NULL;
- /* each TgTeeNode has one input and two outputs, NULL them initiallly */
- addArr_TgNodePtr(tn->inNodes, &BlankNodePtr);
- addArr_TgNodePtr(tn->outNodes, &BlankNodePtr);
- addArr_TgNodePtr(tn->outNodes, &BlankNodePtr);
-
- /* make the old toNode the left parent of the tee node
- add the new toNode as the right parent of the tee node */
- tn->outNodes->val[0] = origToNode;
- origToNode->inNodes->val[origToPort-1] = tn;
-
- tn->outNodes->val[1] = toNode;
- toNode->inNodes->val[toPort-1] = tn;
-
- /* connect the fromNode to the new tee node */
- fromNode->outNodes->val[fromPort-1] = tn;
- tn->inNodes->val[0] = fromNode;
-
- return tn;
+ TgNodePtr origToNode;
+ TgNodePtr tn;
+ TgNodePtr BlankNodePtr;
+ int origToPort;
+ int i;
+
+ /* the toNode formerly pointed to */
+ origToNode = fromNode->outNodes->val[fromPort - 1];
+
+ if (origToNode == NULL)
+ {
+ elog(NOTICE, "Internal Error: connectTee() called with a null origToNode");
+ return;
+ }
+
+ for (i = 0; i < origToNode->inNodes->num; i++)
+ {
+ if (origToNode->inNodes->val[i] == fromNode)
+ break;
+ }
+
+ /* the inport of the former toNode */
+ /* ports start with 1, array indices start from 0 */
+ origToPort = i + 1;
+
+ /* add a tee node now. */
+ tn = malloc(sizeof(TgNode));
+ /* generate a name for the tee node table */
+ tn->nodeName = malloc(50);
+ sprintf(tn->nodeName, "tee_%d", newoid());
+/* tn->nodeName = NULL; */
+
+ tn->nodeType = TG_TEE_NODE;
+ tn->nodeElem = NULL;
+ tn->inNodes = newArr_TgNodePtr();
+ tn->outNodes = newArr_TgNodePtr();
+
+ BlankNodePtr = (TgNodePtr) NULL;
+ /* each TgTeeNode has one input and two outputs, NULL them initiallly */
+ addArr_TgNodePtr(tn->inNodes, &BlankNodePtr);
+ addArr_TgNodePtr(tn->outNodes, &BlankNodePtr);
+ addArr_TgNodePtr(tn->outNodes, &BlankNodePtr);
+
+ /*
+ * make the old toNode the left parent of the tee node add the new
+ * toNode as the right parent of the tee node
+ */
+ tn->outNodes->val[0] = origToNode;
+ origToNode->inNodes->val[origToPort - 1] = tn;
+
+ tn->outNodes->val[1] = toNode;
+ toNode->inNodes->val[toPort - 1] = tn;
+
+ /* connect the fromNode to the new tee node */
+ fromNode->outNodes->val[fromPort - 1] = tn;
+ tn->inNodes->val[0] = fromNode;
+
+ return tn;
}
/* -------------------------------------
fillAllNodes
- fill out the nodes of a recipe
+ fill out the nodes of a recipe
------------------------------------ */
-void
-fillAllNodes(TgRecipe *r, char* name)
+void
+fillAllNodes(TgRecipe * r, char *name)
{
- char qbuf[MAX_QBUF_LENGTH];
- int i;
- char *pqres;
- char *pbufname;
- PortalBuffer *pbuf;
- int ntups;
- TgElement *elem;
- TgNode *node;
-
- /* 1) fill out the elements that are in the recipe */
- sprintf(qbuf, Q_RETRIEVE_ELEMENTS_IN_RECIPE, name);
- pqres = PQexec(qbuf);
- if (*pqres == 'R' || *pqres == 'E') {
- elog(NOTICE, "fillAllNodes(): Error while executing query : %s\n", qbuf);
- elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
- return;
- }
- pbufname = ++pqres;
- pbuf = PQparray(pbufname);
- ntups = PQntuplesGroup(pbuf,0);
- for (i=0;i<ntups;i++) {
- elem = malloc(sizeof(TgElement));
- fillTgElement(elem, pbuf, i);
- addArr_TgElementPtr(r->elements, &elem);
- }
- PQclear(pbufname);
-
- sprintf(qbuf, Q_RETRIEVE_NODES_IN_RECIPE, name);
- pqres = PQexec(qbuf);
- if (*pqres == 'R' || *pqres == 'E') {
- elog(NOTICE, "fillAllNodes(): Error while executing query : %s\n", qbuf);
- elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
- return;
- }
- pbufname = ++pqres;
- pbuf = PQparray(pbufname);
- ntups = PQntuplesGroup(pbuf,0);
- for (i=0;i<ntups;i++) {
- node = malloc(sizeof(TgNode));
- fillTgNode(r, node, pbuf, i);
- addArr_TgNodePtr(r->allNodes, &node);
- }
- PQclear(pbufname);
+ char qbuf[MAX_QBUF_LENGTH];
+ int i;
+ char *pqres;
+ char *pbufname;
+ PortalBuffer *pbuf;
+ int ntups;
+ TgElement *elem;
+ TgNode *node;
+
+ /* 1) fill out the elements that are in the recipe */
+ sprintf(qbuf, Q_RETRIEVE_ELEMENTS_IN_RECIPE, name);
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E')
+ {
+ elog(NOTICE, "fillAllNodes(): Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf, 0);
+ for (i = 0; i < ntups; i++)
+ {
+ elem = malloc(sizeof(TgElement));
+ fillTgElement(elem, pbuf, i);
+ addArr_TgElementPtr(r->elements, &elem);
+ }
+ PQclear(pbufname);
+
+ sprintf(qbuf, Q_RETRIEVE_NODES_IN_RECIPE, name);
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E')
+ {
+ elog(NOTICE, "fillAllNodes(): Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf, 0);
+ for (i = 0; i < ntups; i++)
+ {
+ node = malloc(sizeof(TgNode));
+ fillTgNode(r, node, pbuf, i);
+ addArr_TgNodePtr(r->allNodes, &node);
+ }
+ PQclear(pbufname);
}
/* -------------------------------------
fillAllElements
- fill out the elements of a recipe
+ fill out the elements of a recipe
------------------------------------ */
-void
-fillAllElements(TgRecipe *r, char* name)
+void
+fillAllElements(TgRecipe * r, char *name)
{
- char qbuf[MAX_QBUF_LENGTH];
- int i;
- char *pqres;
- char *pbufname;
- PortalBuffer *pbuf;
- int ntups;
- TgElement *elem;
-
- sprintf(qbuf, Q_RETRIEVE_ELEMENTS_IN_RECIPE, name);
- pqres = PQexec(qbuf);
- if (*pqres == 'R' || *pqres == 'E') {
- elog(NOTICE, "fillAllElements(): Error while executing query : %s\n", qbuf);
- elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
- return;
- }
- pbufname = ++pqres;
- pbuf = PQparray(pbufname);
- ntups = PQntuplesGroup(pbuf,0);
- for (i=0;i<ntups;i++) {
- elem = malloc(sizeof(TgElement));
- fillTgElement(elem, pbuf, i);
- addArr_TgElementPtr(r->elements, &elem);
- }
- PQclear(pbufname);
-
+ char qbuf[MAX_QBUF_LENGTH];
+ int i;
+ char *pqres;
+ char *pbufname;
+ PortalBuffer *pbuf;
+ int ntups;
+ TgElement *elem;
+
+ sprintf(qbuf, Q_RETRIEVE_ELEMENTS_IN_RECIPE, name);
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E')
+ {
+ elog(NOTICE, "fillAllElements(): Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf, 0);
+ for (i = 0; i < ntups; i++)
+ {
+ elem = malloc(sizeof(TgElement));
+ fillTgElement(elem, pbuf, i);
+ addArr_TgElementPtr(r->elements, &elem);
+ }
+ PQclear(pbufname);
+
}
/* -------------------------------------
fillTgRecipe
- takes a query result in the PortalBuffer containing a Recipe
- and converts it to a C TgRecipe strcture
+ takes a query result in the PortalBuffer containing a Recipe
+ and converts it to a C TgRecipe strcture
------------------------------------ */
-TgRecipe*
-fillTgRecipe(PortalBuffer* pbuf, int tupno)
+TgRecipe *
+fillTgRecipe(PortalBuffer * pbuf, int tupno)
{
- TgRecipe* r;
- int i,j;
-
- /* 1) set up the recipe structure */
- r = (TgRecipe*)malloc(sizeof(TgRecipe));
- fillTgElement(&r->elmValue, pbuf, 0);
- r->elmValue.elemType = TG_RECIPE;
- r->allNodes = newArr_TgNodePtr();
- r->rootNodes = newArr_TgNodePtr();
- r->eyes = newArr_TgNodePtr();
- r->tees = newArr_TgNodePtr();
- r->elements = newArr_TgElementPtr();
-
- /* 2) find all the elements. There may be less elements than nodes
- because you can have multiple instantiations of an element
- in a recipe*/
- fillAllElements(r, r->elmValue.elemName);
-
- /* 3) find all the nodes in the recipe*/
- fillAllNodes(r, r->elmValue.elemName);
-
- /* 4) find all the edges, and connect the nodes,
- may also add tee nodes to the allNodes field*/
- lookupEdges(r, r->elmValue.elemName);
-
- /* 5) find all the rootNodes in the recipe */
- /* root nodes are nodes with no incoming nodes or
- whose incoming nodes are all null */
- /* 6) find all the eyes in the recipe */
- /* eye nodes are nodes with the node type TG_EYE_NODE */
- /* 7) find all the tee nodes in the recipe */
- /* tee nodes are nodes with the node type TG_TEE_NODE */
- for (i=0;i<r->allNodes->num;i++) {
- TgNode* nptr = r->allNodes->val[i];
-
- if (nptr->nodeType == TG_EYE_NODE)
- addArr_TgNodePtr(r->eyes, &nptr);
- else
- if (nptr->nodeType == TG_TEE_NODE)
- addArr_TgNodePtr(r->tees, &nptr);
-
- if (nptr->inNodes->num == 0)
- addArr_TgNodePtr(r->rootNodes, &nptr);
- else {
- for (j=0;
- j<nptr->inNodes->num && (nptr->inNodes->val[j] == NULL);
- j++);
- if (j == nptr->inNodes->num)
- addArr_TgNodePtr(r->rootNodes, &nptr);
- }
- }
-
- return r;
+ TgRecipe *r;
+ int i,
+ j;
+
+ /* 1) set up the recipe structure */
+ r = (TgRecipe *) malloc(sizeof(TgRecipe));
+ fillTgElement(&r->elmValue, pbuf, 0);
+ r->elmValue.elemType = TG_RECIPE;
+ r->allNodes = newArr_TgNodePtr();
+ r->rootNodes = newArr_TgNodePtr();
+ r->eyes = newArr_TgNodePtr();
+ r->tees = newArr_TgNodePtr();
+ r->elements = newArr_TgElementPtr();
+
+ /*
+ * 2) find all the elements. There may be less elements than nodes
+ * because you can have multiple instantiations of an element in a
+ * recipe
+ */
+ fillAllElements(r, r->elmValue.elemName);
+
+ /* 3) find all the nodes in the recipe */
+ fillAllNodes(r, r->elmValue.elemName);
+
+ /*
+ * 4) find all the edges, and connect the nodes, may also add tee
+ * nodes to the allNodes field
+ */
+ lookupEdges(r, r->elmValue.elemName);
+
+ /* 5) find all the rootNodes in the recipe */
+
+ /*
+ * root nodes are nodes with no incoming nodes or whose incoming nodes
+ * are all null
+ */
+ /* 6) find all the eyes in the recipe */
+ /* eye nodes are nodes with the node type TG_EYE_NODE */
+ /* 7) find all the tee nodes in the recipe */
+ /* tee nodes are nodes with the node type TG_TEE_NODE */
+ for (i = 0; i < r->allNodes->num; i++)
+ {
+ TgNode *nptr = r->allNodes->val[i];
+
+ if (nptr->nodeType == TG_EYE_NODE)
+ addArr_TgNodePtr(r->eyes, &nptr);
+ else if (nptr->nodeType == TG_TEE_NODE)
+ addArr_TgNodePtr(r->tees, &nptr);
+
+ if (nptr->inNodes->num == 0)
+ addArr_TgNodePtr(r->rootNodes, &nptr);
+ else
+ {
+ for (j = 0;
+ j < nptr->inNodes->num && (nptr->inNodes->val[j] == NULL);
+ j++);
+ if (j == nptr->inNodes->num)
+ addArr_TgNodePtr(r->rootNodes, &nptr);
+ }
+ }
+
+ return r;
}
@@ -630,65 +693,72 @@ fillTgRecipe(PortalBuffer* pbuf, int tupno)
retrieveRecipe
find the recipe with the given name
------------------------------------ */
-TgRecipe*
-retrieveRecipe(char* name)
+TgRecipe *
+retrieveRecipe(char *name)
{
- char qbuf[MAX_QBUF_LENGTH];
- TgRecipe* recipe;
- char *pqres;
- char *pbufname;
- PortalBuffer *pbuf;
- int ntups;
-
- sprintf(qbuf, Q_RETRIEVE_RECIPE_BYNAME, name);
-
- pqres = PQexec(qbuf);
- if (*pqres == 'R' || *pqres == 'E') {
- elog(NOTICE, "retrieveRecipe: Error while executing query : %s\n", qbuf);
- elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
- return NULL;
- }
- pbufname = ++pqres;
- pbuf = PQparray(pbufname);
- ntups = PQntuplesGroup(pbuf,0);
- if (ntups == 0) {
- elog(NOTICE, "retrieveRecipe(): No recipe named %s exists\n", name);
- return NULL;
- }
- if (ntups != 1) {
- elog(NOTICE, "retrieveRecipe(): Multiple (%d) recipes named %s exists\n", ntups, name);
- return NULL;
- }
-
- recipe = fillTgRecipe(pbuf,0);
-
- PQclear(pbufname);
- return recipe;
+ char qbuf[MAX_QBUF_LENGTH];
+ TgRecipe *recipe;
+ char *pqres;
+ char *pbufname;
+ PortalBuffer *pbuf;
+ int ntups;
+
+ sprintf(qbuf, Q_RETRIEVE_RECIPE_BYNAME, name);
+
+ pqres = PQexec(qbuf);
+ if (*pqres == 'R' || *pqres == 'E')
+ {
+ elog(NOTICE, "retrieveRecipe: Error while executing query : %s\n", qbuf);
+ elog(NOTICE, "result = %s, error is %s\n", pqres, PQerrormsg);
+ return NULL;
+ }
+ pbufname = ++pqres;
+ pbuf = PQparray(pbufname);
+ ntups = PQntuplesGroup(pbuf, 0);
+ if (ntups == 0)
+ {
+ elog(NOTICE, "retrieveRecipe(): No recipe named %s exists\n", name);
+ return NULL;
+ }
+ if (ntups != 1)
+ {
+ elog(NOTICE, "retrieveRecipe(): Multiple (%d) recipes named %s exists\n", ntups, name);
+ return NULL;
+ }
+
+ recipe = fillTgRecipe(pbuf, 0);
+
+ PQclear(pbufname);
+ return recipe;
}
/* -------------------- copyXXX functions ----------------------- */
-void copyTgElementPtr(TgElementPtr* from, TgElementPtr* to)
+void
+copyTgElementPtr(TgElementPtr * from, TgElementPtr * to)
{
- *to = *from;
+ *to = *from;
}
-void copyTgNodePtr(TgNodePtr* from, TgNodePtr* to)
+void
+copyTgNodePtr(TgNodePtr * from, TgNodePtr * to)
{
- *to = *from;
+ *to = *from;
}
-void copyTgRecipePtr(TgRecipePtr* from, TgRecipePtr* to)
+void
+copyTgRecipePtr(TgRecipePtr * from, TgRecipePtr * to)
{
- *to = *from;
+ *to = *from;
}
-void copyTgString(TgString* from, TgString* to)
+void
+copyTgString(TgString * from, TgString * to)
{
- TgString fromTgString = *from;
- TgString toTgString;
- toTgString = (TgString)malloc(strlen(fromTgString)+1);
- strcpy(toTgString, fromTgString);
- *to = toTgString;
-}
+ TgString fromTgString = *from;
+ TgString toTgString;
+ toTgString = (TgString) malloc(strlen(fromTgString) + 1);
+ strcpy(toTgString, fromTgString);
+ *to = toTgString;
+}
diff --git a/src/backend/tioga/tgRecipe.h b/src/backend/tioga/tgRecipe.h
index c6ee78e5068..669092982bc 100644
--- a/src/backend/tioga/tgRecipe.h
+++ b/src/backend/tioga/tgRecipe.h
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* tgRecipe.h--
- * Tioga recipe-related definitions and declarations
- * these functions can be used in both the frontend and the
- * backend
- *
- * to use this header, you must also include
- * "utils/geo-decls.h"
- * and "libpq/libpq.h"
+ * Tioga recipe-related definitions and declarations
+ * these functions can be used in both the frontend and the
+ * backend
+ *
+ * to use this header, you must also include
+ * "utils/geo-decls.h"
+ * and "libpq/libpq.h"
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: tgRecipe.h,v 1.1.1.1 1996/07/09 06:22:00 scrappy Exp $
+ * $Id: tgRecipe.h,v 1.2 1997/09/07 04:49:50 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,99 +23,112 @@
#include "utils/geo-decls.h"
#else
#include "libpq-fe.h"
-typedef struct {
- double x, y;
-} Point; /* this should match whatever is in geo-decls.h*/
-#endif /* TIOGA_FRONTEND */
-
-typedef enum {TG_INGRED,
- TG_EYE,
- TG_RECIPE} TgElemType;
-
-typedef enum { TG_SQL,
- TG_C,
- TG_RECIPE_GRAPH,
- TG_COMPILED
- } TgSrcLangType;
-
-typedef enum { TG_INGRED_NODE,
- TG_EYE_NODE,
- TG_RECIPE_NODE,
- TG_TEE_NODE /* tee nodes are not stored in the db
- we create them when we read the recipe
- back */
- } TgNodeType;
+typedef struct
+{
+ double x,
+ y;
+} Point; /* this should match whatever is in
+
+ * geo-decls.h */
+
+#endif /* TIOGA_FRONTEND */
+
+typedef enum
+{
+ TG_INGRED,
+ TG_EYE,
+ TG_RECIPE
+} TgElemType;
+
+typedef enum
+{
+ TG_SQL,
+ TG_C,
+ TG_RECIPE_GRAPH,
+ TG_COMPILED
+} TgSrcLangType;
+
+typedef enum
+{
+ TG_INGRED_NODE,
+ TG_EYE_NODE,
+ TG_RECIPE_NODE,
+ TG_TEE_NODE /* tee nodes are not stored in the db we
+ * create them when we read the recipe
+ * back */
+} TgNodeType;
/* -- type definition for setting up in memory Tioga recipe structure -- */
/* -- see 'recipe-schema.sql' for their corresponding database types -- */
-typedef char *TgString;
+typedef char *TgString;
typedef struct _tgelement *TgElementPtr;
-typedef struct _tgnode *TgNodePtr;
-typedef struct _tgrecipe *TgRecipePtr;
+typedef struct _tgnode *TgNodePtr;
+typedef struct _tgrecipe *TgRecipePtr;
/* auto-generated header containing Arr_TgString, Arr_TgElementPtr,
and Arr_TgNodePtr */
-#include "tioga/Arr_TgRecipe.h"
+#include "tioga/Arr_TgRecipe.h"
/* C structure representation of a Tioga Element */
-typedef struct _tgelement {
- char *elemName; /* name of function this element represent */
- TgElemType elemType; /* type of this element */
- Arr_TgString *inPorts; /* names of inputs */
- Arr_TgString *inTypes; /* name of input types */
- Arr_TgString *outPorts; /* type of output */
- Arr_TgString *outTypes; /* name of output types */
- char *doc; /* description of this element */
- Arr_TgString *keywords; /* keywords used to search for this element */
- char *icon; /* iconic representation */
- char *src; /* source code for this element */
- TgSrcLangType srcLang; /* source language */
- char *owner; /* owner recipe name */
-} TgElement;
+typedef struct _tgelement
+{
+ char *elemName; /* name of function this element represent */
+ TgElemType elemType; /* type of this element */
+ Arr_TgString *inPorts; /* names of inputs */
+ Arr_TgString *inTypes; /* name of input types */
+ Arr_TgString *outPorts; /* type of output */
+ Arr_TgString *outTypes; /* name of output types */
+ char *doc; /* description of this element */
+ Arr_TgString *keywords; /* keywords used to search for this
+ * element */
+ char *icon; /* iconic representation */
+ char *src; /* source code for this element */
+ TgSrcLangType srcLang; /* source language */
+ char *owner; /* owner recipe name */
+} TgElement;
/* C structure representation of a Tioga Node */
-typedef struct _tgnode {
- char *nodeName; /* name of this node */
- TgNodeType nodeType; /* type of this node */
- Point loc; /* screen location of the node. */
- TgElement *nodeElem; /* the underlying element of this node */
- Arr_TgNodePtr *inNodes; /* variable array of in node pointers
- * a NULL TgNodePtr indicates a run-time
- * parameter*/
- Arr_TgNodePtr *outNodes; /* variable array of out node pointers. */
-} TgNode;
+typedef struct _tgnode
+{
+ char *nodeName; /* name of this node */
+ TgNodeType nodeType; /* type of this node */
+ Point loc; /* screen location of the node. */
+ TgElement *nodeElem; /* the underlying element of this node */
+ Arr_TgNodePtr *inNodes; /* variable array of in node pointers a
+ * NULL TgNodePtr indicates a run-time
+ * parameter */
+ Arr_TgNodePtr *outNodes; /* variable array of out node pointers. */
+} TgNode;
/* C structure representation of a Tioga Recipe */
-typedef struct _tgrecipe {
- TgElement elmValue; /* "inherits" TgElement attributes. */
- Arr_TgNodePtr *allNodes; /* array of all nodes for this recipe. */
- Arr_TgNodePtr *rootNodes; /* array of root nodes for this recipe. --
- root nodes are nodes with no parents */
- Arr_TgNodePtr *eyes; /* array of pointers for the browser nodes
- * recipe, execution of recipe starts
- * by traversing the recipe C structure
- * from the eye nodes pointed by these
- * pointers. */
- Arr_TgNodePtr *tees; /* array of pointers of all the tee nodes */
- Arr_TgElementPtr *elements; /* array of all the elements in this recipe,
- * elements may be shared by multiple nodes */
-
-} TgRecipe;
+typedef struct _tgrecipe
+{
+ TgElement elmValue; /* "inherits" TgElement attributes. */
+ Arr_TgNodePtr *allNodes; /* array of all nodes for this recipe. */
+ Arr_TgNodePtr *rootNodes; /* array of root nodes for this recipe. --
+ * root nodes are nodes with no parents */
+ Arr_TgNodePtr *eyes; /* array of pointers for the browser nodes
+ * recipe, execution of recipe starts by
+ * traversing the recipe C structure from
+ * the eye nodes pointed by these
+ * pointers. */
+ Arr_TgNodePtr *tees; /* array of pointers of all the tee nodes */
+ Arr_TgElementPtr *elements; /* array of all the elements in this
+ * recipe, elements may be shared by
+ * multiple nodes */
+
+} TgRecipe;
/* functions defined in tgRecipe.c */
-extern TgRecipe* retrieveRecipe(char* name);
-extern TgElement* findElemInRecipe(TgRecipe *r, char* elemName);
-extern TgNode* findNodeInRecipe(TgRecipe *r, char* nodeName);
+extern TgRecipe *retrieveRecipe(char *name);
+extern TgElement *findElemInRecipe(TgRecipe * r, char *elemName);
+extern TgNode *findNodeInRecipe(TgRecipe * r, char *nodeName);
/* ---- copyXXX functions ---- */
-extern void copyTgElementPtr(TgElementPtr *, TgElementPtr *);
-extern void copyTgNodePtr(TgNodePtr *, TgNodePtr *);
-extern void copyTgRecipePtr(TgRecipePtr *, TgRecipePtr *);
-extern void copyTgString(TgString *, TgString *);
-
-
-
-
+extern void copyTgElementPtr(TgElementPtr *, TgElementPtr *);
+extern void copyTgNodePtr(TgNodePtr *, TgNodePtr *);
+extern void copyTgRecipePtr(TgRecipePtr *, TgRecipePtr *);
+extern void copyTgString(TgString *, TgString *);
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 33580a95125..d4b8f1ca0b6 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* acl.c--
- * Basic access control list data structures manipulation routines.
+ * Basic access control list data structures manipulation routines.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.13 1997/08/19 21:34:10 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.14 1997/09/07 04:49:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,561 +21,629 @@
#include "utils/syscache.h"
#include "miscadmin.h"
-static char *getid(char *s, char *n);
-static int32 aclitemeq(AclItem *a1, AclItem *a2);
-static int32 aclitemgt(AclItem *a1, AclItem *a2);
-static char *aclparse(char *s, AclItem *aip, unsigned *modechg);
+static char *getid(char *s, char *n);
+static int32 aclitemeq(AclItem * a1, AclItem * a2);
+static int32 aclitemgt(AclItem * a1, AclItem * a2);
+static char *aclparse(char *s, AclItem * aip, unsigned *modechg);
-#define ACL_IDTYPE_GID_KEYWORD "group"
-#define ACL_IDTYPE_UID_KEYWORD "user"
+#define ACL_IDTYPE_GID_KEYWORD "group"
+#define ACL_IDTYPE_UID_KEYWORD "user"
/*
* getid
- * Consumes the first alphanumeric string (identifier) found in string
- * 's', ignoring any leading white space.
+ * Consumes the first alphanumeric string (identifier) found in string
+ * 's', ignoring any leading white space.
*
* RETURNS:
- * the string position in 's' that points to the next non-space character
- * in 's'. Also:
- * - loads the identifier into 'name'. (If no identifier is found, 'name'
- * contains an empty string).
+ * the string position in 's' that points to the next non-space character
+ * in 's'. Also:
+ * - loads the identifier into 'name'. (If no identifier is found, 'name'
+ * contains an empty string).
*/
-static char *
+static char *
getid(char *s, char *n)
{
- unsigned len;
- char *id;
-
- Assert(s && n);
-
- while (isspace(*s))
- ++s;
- for (id = s, len = 0; isalnum(*s) || *s == '_'; ++len, ++s)
- ;
- if (len > sizeof(NameData))
- elog(WARN, "getid: identifier cannot be >%d characters",
- sizeof(NameData));
- if (len > 0)
- memmove(n, id, len);
- n[len] = '\0';
- while (isspace(*s))
- ++s;
- return(s);
+ unsigned len;
+ char *id;
+
+ Assert(s && n);
+
+ while (isspace(*s))
+ ++s;
+ for (id = s, len = 0; isalnum(*s) || *s == '_'; ++len, ++s)
+ ;
+ if (len > sizeof(NameData))
+ elog(WARN, "getid: identifier cannot be >%d characters",
+ sizeof(NameData));
+ if (len > 0)
+ memmove(n, id, len);
+ n[len] = '\0';
+ while (isspace(*s))
+ ++s;
+ return (s);
}
/*
* aclparse
- * Consumes and parses an ACL specification of the form:
- * [group|user] [A-Za-z0-9]*[+-=][rwaR]*
- * from string 's', ignoring any leading white space or white space
- * between the optional id type keyword (group|user) and the actual
- * ACL specification.
+ * Consumes and parses an ACL specification of the form:
+ * [group|user] [A-Za-z0-9]*[+-=][rwaR]*
+ * from string 's', ignoring any leading white space or white space
+ * between the optional id type keyword (group|user) and the actual
+ * ACL specification.
*
- * This routine is called by the parser as well as aclitemin(), hence
- * the added generality.
+ * This routine is called by the parser as well as aclitemin(), hence
+ * the added generality.
*
* RETURNS:
- * the string position in 's' immediately following the ACL
- * specification. Also:
- * - loads the structure pointed to by 'aip' with the appropriate
- * UID/GID, id type identifier and mode type values.
- * - loads 'modechg' with the mode change flag.
+ * the string position in 's' immediately following the ACL
+ * specification. Also:
+ * - loads the structure pointed to by 'aip' with the appropriate
+ * UID/GID, id type identifier and mode type values.
+ * - loads 'modechg' with the mode change flag.
*/
-static char *
-aclparse(char *s, AclItem *aip, unsigned *modechg)
+static char *
+aclparse(char *s, AclItem * aip, unsigned *modechg)
{
- HeapTuple htp;
- char name[NAMEDATALEN];
-
- Assert(s && aip && modechg);
-
- aip->ai_idtype = ACL_IDTYPE_UID;
- s = getid(s, name);
- if (*s != ACL_MODECHG_ADD_CHR &&
- *s != ACL_MODECHG_DEL_CHR &&
- *s != ACL_MODECHG_EQL_CHR)
- { /* we just read a keyword, not a name */
- if (!strcmp(name, ACL_IDTYPE_GID_KEYWORD)) {
- aip->ai_idtype = ACL_IDTYPE_GID;
- } else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD)) {
- elog(WARN, "aclparse: bad keyword, must be [group|user]");
+ HeapTuple htp;
+ char name[NAMEDATALEN];
+
+ Assert(s && aip && modechg);
+
+ aip->ai_idtype = ACL_IDTYPE_UID;
+ s = getid(s, name);
+ if (*s != ACL_MODECHG_ADD_CHR &&
+ *s != ACL_MODECHG_DEL_CHR &&
+ *s != ACL_MODECHG_EQL_CHR)
+ { /* we just read a keyword, not a name */
+ if (!strcmp(name, ACL_IDTYPE_GID_KEYWORD))
+ {
+ aip->ai_idtype = ACL_IDTYPE_GID;
+ }
+ else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD))
+ {
+ elog(WARN, "aclparse: bad keyword, must be [group|user]");
+ }
+ s = getid(s, name); /* move s to the name beyond the keyword */
+ if (name[0] == '\0')
+ elog(WARN, "aclparse: a name must follow the [group|user] keyword");
}
- s = getid(s, name); /* move s to the name beyond the keyword */
if (name[0] == '\0')
- elog(WARN, "aclparse: a name must follow the [group|user] keyword");
- }
- if (name[0] == '\0')
- aip->ai_idtype = ACL_IDTYPE_WORLD;
-
- switch (*s) {
- case ACL_MODECHG_ADD_CHR: *modechg = ACL_MODECHG_ADD; break;
- case ACL_MODECHG_DEL_CHR: *modechg = ACL_MODECHG_DEL; break;
- case ACL_MODECHG_EQL_CHR: *modechg = ACL_MODECHG_EQL; break;
- default: elog(WARN, "aclparse: mode change flag must use \"%s\"",
- ACL_MODECHG_STR);
- }
-
- aip->ai_mode = ACL_NO;
- while (isalpha(*++s)) {
- switch (*s) {
- case ACL_MODE_AP_CHR: aip->ai_mode |= ACL_AP; break;
- case ACL_MODE_RD_CHR: aip->ai_mode |= ACL_RD; break;
- case ACL_MODE_WR_CHR: aip->ai_mode |= ACL_WR; break;
- case ACL_MODE_RU_CHR: aip->ai_mode |= ACL_RU; break;
- default: elog(WARN, "aclparse: mode flags must use \"%s\"",
- ACL_MODE_STR);
+ aip->ai_idtype = ACL_IDTYPE_WORLD;
+
+ switch (*s)
+ {
+ case ACL_MODECHG_ADD_CHR:
+ *modechg = ACL_MODECHG_ADD;
+ break;
+ case ACL_MODECHG_DEL_CHR:
+ *modechg = ACL_MODECHG_DEL;
+ break;
+ case ACL_MODECHG_EQL_CHR:
+ *modechg = ACL_MODECHG_EQL;
+ break;
+ default:
+ elog(WARN, "aclparse: mode change flag must use \"%s\"",
+ ACL_MODECHG_STR);
}
- }
-
- switch (aip->ai_idtype) {
- case ACL_IDTYPE_UID:
- htp = SearchSysCacheTuple(USENAME, PointerGetDatum(name),
- 0,0,0);
- if (!HeapTupleIsValid(htp))
- elog(WARN, "aclparse: non-existent user \"%s\"", name);
- aip->ai_id = ((Form_pg_user) GETSTRUCT(htp))->usesysid;
- break;
- case ACL_IDTYPE_GID:
- aip->ai_id = get_grosysid(name);
- break;
- case ACL_IDTYPE_WORLD:
- aip->ai_id = ACL_ID_WORLD;
- break;
- }
-
+
+ aip->ai_mode = ACL_NO;
+ while (isalpha(*++s))
+ {
+ switch (*s)
+ {
+ case ACL_MODE_AP_CHR:
+ aip->ai_mode |= ACL_AP;
+ break;
+ case ACL_MODE_RD_CHR:
+ aip->ai_mode |= ACL_RD;
+ break;
+ case ACL_MODE_WR_CHR:
+ aip->ai_mode |= ACL_WR;
+ break;
+ case ACL_MODE_RU_CHR:
+ aip->ai_mode |= ACL_RU;
+ break;
+ default:
+ elog(WARN, "aclparse: mode flags must use \"%s\"",
+ ACL_MODE_STR);
+ }
+ }
+
+ switch (aip->ai_idtype)
+ {
+ case ACL_IDTYPE_UID:
+ htp = SearchSysCacheTuple(USENAME, PointerGetDatum(name),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ elog(WARN, "aclparse: non-existent user \"%s\"", name);
+ aip->ai_id = ((Form_pg_user) GETSTRUCT(htp))->usesysid;
+ break;
+ case ACL_IDTYPE_GID:
+ aip->ai_id = get_grosysid(name);
+ break;
+ case ACL_IDTYPE_WORLD:
+ aip->ai_id = ACL_ID_WORLD;
+ break;
+ }
+
#ifdef ACLDEBUG_TRACE
- elog(DEBUG, "aclparse: correctly read [%x %d %x], modechg=%x",
- aip->ai_idtype, aip->ai_id, aip->ai_mode, *modechg);
+ elog(DEBUG, "aclparse: correctly read [%x %d %x], modechg=%x",
+ aip->ai_idtype, aip->ai_id, aip->ai_mode, *modechg);
#endif
- return(s);
+ return (s);
}
/*
* makeacl
- * Allocates storage for a new Acl with 'n' entries.
+ * Allocates storage for a new Acl with 'n' entries.
*
* RETURNS:
- * the new Acl
+ * the new Acl
*/
-Acl *
+Acl *
makeacl(int n)
{
- Acl *new_acl;
- Size size;
-
- if (n < 0)
- elog(WARN, "makeacl: invalid size: %d\n", n);
- size = ACL_N_SIZE(n);
- if (!(new_acl = (Acl *) palloc(size)))
- elog(WARN, "makeacl: palloc failed on %d\n", size);
- memset((char *) new_acl, 0, size);
- new_acl->size = size;
- new_acl->ndim = 1;
- new_acl->flags = 0;
- ARR_LBOUND(new_acl)[0] = 0;
- ARR_DIMS(new_acl)[0] = n;
- return(new_acl);
+ Acl *new_acl;
+ Size size;
+
+ if (n < 0)
+ elog(WARN, "makeacl: invalid size: %d\n", n);
+ size = ACL_N_SIZE(n);
+ if (!(new_acl = (Acl *) palloc(size)))
+ elog(WARN, "makeacl: palloc failed on %d\n", size);
+ memset((char *) new_acl, 0, size);
+ new_acl->size = size;
+ new_acl->ndim = 1;
+ new_acl->flags = 0;
+ ARR_LBOUND(new_acl)[0] = 0;
+ ARR_DIMS(new_acl)[0] = n;
+ return (new_acl);
}
/*
* aclitemin
- * Allocates storage for, and fills in, a new AclItem given a string
- * 's' that contains an ACL specification. See aclparse for details.
+ * Allocates storage for, and fills in, a new AclItem given a string
+ * 's' that contains an ACL specification. See aclparse for details.
*
* RETURNS:
- * the new AclItem
+ * the new AclItem
*/
-AclItem *
+AclItem *
aclitemin(char *s)
{
- unsigned modechg;
- AclItem *aip;
-
- if (!s)
- elog(WARN, "aclitemin: null string");
-
- aip = (AclItem *) palloc(sizeof(AclItem));
- if (!aip)
- elog(WARN, "aclitemin: palloc failed");
- s = aclparse(s, aip, &modechg);
- if (modechg != ACL_MODECHG_EQL)
- elog(WARN, "aclitemin: cannot accept anything but = ACLs");
- while (isspace(*s))
- ++s;
- if (*s)
- elog(WARN, "aclitemin: extra garbage at end of specification");
- return(aip);
+ unsigned modechg;
+ AclItem *aip;
+
+ if (!s)
+ elog(WARN, "aclitemin: null string");
+
+ aip = (AclItem *) palloc(sizeof(AclItem));
+ if (!aip)
+ elog(WARN, "aclitemin: palloc failed");
+ s = aclparse(s, aip, &modechg);
+ if (modechg != ACL_MODECHG_EQL)
+ elog(WARN, "aclitemin: cannot accept anything but = ACLs");
+ while (isspace(*s))
+ ++s;
+ if (*s)
+ elog(WARN, "aclitemin: extra garbage at end of specification");
+ return (aip);
}
/*
* aclitemout
- * Allocates storage for, and fills in, a new null-delimited string
- * containing a formatted ACL specification. See aclparse for details.
+ * Allocates storage for, and fills in, a new null-delimited string
+ * containing a formatted ACL specification. See aclparse for details.
*
* RETURNS:
- * the new string
+ * the new string
*/
-char *
-aclitemout(AclItem *aip)
+char *
+aclitemout(AclItem * aip)
{
- register char *p;
- char *out;
- HeapTuple htp;
- unsigned i;
- static AclItem default_aclitem = { ACL_ID_WORLD,
- ACL_IDTYPE_WORLD,
- ACL_WORLD_DEFAULT };
- extern char *int2out();
- char *tmpname;
-
- if (!aip)
- aip = &default_aclitem;
-
- p = out = palloc(strlen("group =arwR ") + 1 + NAMEDATALEN);
- if (!out)
- elog(WARN, "aclitemout: palloc failed");
- *p = '\0';
-
- switch (aip->ai_idtype) {
- case ACL_IDTYPE_UID:
- htp = SearchSysCacheTuple(USESYSID, ObjectIdGetDatum(aip->ai_id),
- 0,0,0);
- if (!HeapTupleIsValid(htp)) {
- char *tmp = int2out(aip->ai_id);
-
- elog(NOTICE, "aclitemout: usesysid %d not found",
- aip->ai_id);
- strcat(p, tmp);
- pfree(tmp);
- } else
- strncat(p, (char *) &((Form_pg_user)
- GETSTRUCT(htp))->usename,
- sizeof(NameData));
- break;
- case ACL_IDTYPE_GID:
- strcat(p, "group ");
- tmpname = get_groname(aip->ai_id);
- strncat(p, tmpname, NAMEDATALEN);
- break;
- case ACL_IDTYPE_WORLD:
- break;
- default:
- elog(WARN, "aclitemout: bad ai_idtype: %d", aip->ai_idtype);
- break;
- }
- while (*p)
- ++p;
- *p++ = '=';
- for (i = 0; i < N_ACL_MODES; ++i)
- if ((aip->ai_mode >> i) & 01)
- *p++ = ACL_MODE_STR[i];
- *p = '\0';
-
- return(out);
+ register char *p;
+ char *out;
+ HeapTuple htp;
+ unsigned i;
+ static AclItem default_aclitem = {ACL_ID_WORLD,
+ ACL_IDTYPE_WORLD,
+ ACL_WORLD_DEFAULT};
+ extern char *int2out();
+ char *tmpname;
+
+ if (!aip)
+ aip = &default_aclitem;
+
+ p = out = palloc(strlen("group =arwR ") + 1 + NAMEDATALEN);
+ if (!out)
+ elog(WARN, "aclitemout: palloc failed");
+ *p = '\0';
+
+ switch (aip->ai_idtype)
+ {
+ case ACL_IDTYPE_UID:
+ htp = SearchSysCacheTuple(USESYSID, ObjectIdGetDatum(aip->ai_id),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(htp))
+ {
+ char *tmp = int2out(aip->ai_id);
+
+ elog(NOTICE, "aclitemout: usesysid %d not found",
+ aip->ai_id);
+ strcat(p, tmp);
+ pfree(tmp);
+ }
+ else
+ strncat(p, (char *) &((Form_pg_user)
+ GETSTRUCT(htp))->usename,
+ sizeof(NameData));
+ break;
+ case ACL_IDTYPE_GID:
+ strcat(p, "group ");
+ tmpname = get_groname(aip->ai_id);
+ strncat(p, tmpname, NAMEDATALEN);
+ break;
+ case ACL_IDTYPE_WORLD:
+ break;
+ default:
+ elog(WARN, "aclitemout: bad ai_idtype: %d", aip->ai_idtype);
+ break;
+ }
+ while (*p)
+ ++p;
+ *p++ = '=';
+ for (i = 0; i < N_ACL_MODES; ++i)
+ if ((aip->ai_mode >> i) & 01)
+ *p++ = ACL_MODE_STR[i];
+ *p = '\0';
+
+ return (out);
}
/*
* aclitemeq
* aclitemgt
- * AclItem equality and greater-than comparison routines.
- * Two AclItems are equal iff they are both NULL or they have the
- * same identifier (and identifier type).
+ * AclItem equality and greater-than comparison routines.
+ * Two AclItems are equal iff they are both NULL or they have the
+ * same identifier (and identifier type).
*
* RETURNS:
- * a boolean value indicating = or >
+ * a boolean value indicating = or >
*/
-static int32
-aclitemeq(AclItem *a1, AclItem *a2)
+static int32
+aclitemeq(AclItem * a1, AclItem * a2)
{
- if (!a1 && !a2)
- return(1);
- if (!a1 || !a2)
- return(0);
- return(a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id);
+ if (!a1 && !a2)
+ return (1);
+ if (!a1 || !a2)
+ return (0);
+ return (a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id);
}
-static int32
-aclitemgt(AclItem *a1, AclItem *a2)
+static int32
+aclitemgt(AclItem * a1, AclItem * a2)
{
- if (a1 && !a2)
- return(1);
- if (!a1 || !a2)
- return(0);
- return((a1->ai_idtype > a2->ai_idtype) ||
- (a1->ai_idtype == a2->ai_idtype && a1->ai_id > a2->ai_id));
+ if (a1 && !a2)
+ return (1);
+ if (!a1 || !a2)
+ return (0);
+ return ((a1->ai_idtype > a2->ai_idtype) ||
+ (a1->ai_idtype == a2->ai_idtype && a1->ai_id > a2->ai_id));
}
-Acl *
+Acl *
aclownerdefault(AclId ownerid)
{
- Acl *acl;
- AclItem *aip;
-
- acl = makeacl(2);
- aip = ACL_DAT(acl);
- aip[0].ai_idtype = ACL_IDTYPE_WORLD;
- aip[0].ai_id = ACL_ID_WORLD;
- aip[0].ai_mode = ACL_WORLD_DEFAULT;
- aip[1].ai_idtype = ACL_IDTYPE_UID;
- aip[1].ai_id = ownerid;
- aip[1].ai_mode = ACL_OWNER_DEFAULT;
- return(acl);
+ Acl *acl;
+ AclItem *aip;
+
+ acl = makeacl(2);
+ aip = ACL_DAT(acl);
+ aip[0].ai_idtype = ACL_IDTYPE_WORLD;
+ aip[0].ai_id = ACL_ID_WORLD;
+ aip[0].ai_mode = ACL_WORLD_DEFAULT;
+ aip[1].ai_idtype = ACL_IDTYPE_UID;
+ aip[1].ai_id = ownerid;
+ aip[1].ai_mode = ACL_OWNER_DEFAULT;
+ return (acl);
}
-Acl *
+Acl *
acldefault(void)
{
- Acl *acl;
- AclItem *aip;
-
- acl = makeacl(1);
- aip = ACL_DAT(acl);
- aip[0].ai_idtype = ACL_IDTYPE_WORLD;
- aip[0].ai_id = ACL_ID_WORLD;
- aip[0].ai_mode = ACL_WORLD_DEFAULT;
- return(acl);
+ Acl *acl;
+ AclItem *aip;
+
+ acl = makeacl(1);
+ aip = ACL_DAT(acl);
+ aip[0].ai_idtype = ACL_IDTYPE_WORLD;
+ aip[0].ai_id = ACL_ID_WORLD;
+ aip[0].ai_mode = ACL_WORLD_DEFAULT;
+ return (acl);
}
-Acl *
-aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
+Acl *
+aclinsert3(Acl * old_acl, AclItem * mod_aip, unsigned modechg)
{
- Acl *new_acl;
- AclItem *old_aip, *new_aip;
- unsigned src, dst, num;
-
- if (!old_acl || ACL_NUM(old_acl) < 1) {
- new_acl = makeacl(0);
- return(new_acl);
- }
- if (!mod_aip) {
- new_acl = makeacl(ACL_NUM(old_acl));
- memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
- return(new_acl);
- }
-
- num = ACL_NUM(old_acl);
- old_aip = ACL_DAT(old_acl);
-
- /*
- * Search the ACL for an existing entry for 'id'. If one exists,
- * just modify the entry in-place (well, in the same position, since
- * we actually return a copy); otherwise, insert the new entry in
- * sort-order.
- */
- /* find the first element not less than the element to be inserted */
- for (dst = 0; dst < num && aclitemgt(mod_aip, old_aip+dst); ++dst)
- ;
- if (dst < num && aclitemeq(mod_aip, old_aip+dst)) {
- /* modify in-place */
- new_acl = makeacl(ACL_NUM(old_acl));
- memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
- new_aip = ACL_DAT(new_acl);
- src = dst;
- } else {
- new_acl = makeacl(num + 1);
- new_aip = ACL_DAT(new_acl);
- if (dst == 0) { /* start */
- elog(WARN, "aclinsert3: insertion before world ACL??");
- } else if (dst >= num) { /* end */
- memmove((char *) new_aip,
- (char *) old_aip,
- num * sizeof(AclItem));
- } else { /* middle */
- memmove((char *) new_aip,
- (char *) old_aip,
- dst * sizeof(AclItem));
- memmove((char *) (new_aip+dst+1),
- (char *) (old_aip+dst),
- (num - dst) * sizeof(AclItem));
+ Acl *new_acl;
+ AclItem *old_aip,
+ *new_aip;
+ unsigned src,
+ dst,
+ num;
+
+ if (!old_acl || ACL_NUM(old_acl) < 1)
+ {
+ new_acl = makeacl(0);
+ return (new_acl);
}
- new_aip[dst].ai_id = mod_aip->ai_id;
- new_aip[dst].ai_idtype = mod_aip->ai_idtype;
- num++; /* set num to the size of new_acl */
- src = 0; /* world entry */
- }
- switch (modechg) {
- case ACL_MODECHG_ADD: new_aip[dst].ai_mode =
- old_aip[src].ai_mode | mod_aip->ai_mode;
- break;
- case ACL_MODECHG_DEL: new_aip[dst].ai_mode =
- old_aip[src].ai_mode & ~mod_aip->ai_mode;
- break;
- case ACL_MODECHG_EQL: new_aip[dst].ai_mode =
- mod_aip->ai_mode;
- break;
- }
- /* if the newly added entry has no permissions, delete it from
- the list. For example, this helps in removing entries for users who
- no longer exists...*/
- for (dst = 1; dst < num; dst++) {
- if (new_aip[dst].ai_mode == 0) {
- int i;
- for (i=dst+1; i<num; i++) {
- new_aip[i-1].ai_id = new_aip[i].ai_id;
- new_aip[i-1].ai_idtype = new_aip[i].ai_idtype;
- new_aip[i-1].ai_mode = new_aip[i].ai_mode;
- }
- ARR_DIMS(new_acl)[0] = num -1 ;
- /* Adjust also the array size because it is used for memmove */
- ARR_SIZE(new_acl) -= sizeof(AclItem);
- break;
+ if (!mod_aip)
+ {
+ new_acl = makeacl(ACL_NUM(old_acl));
+ memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+ return (new_acl);
}
- }
- return(new_acl);
+ num = ACL_NUM(old_acl);
+ old_aip = ACL_DAT(old_acl);
+
+ /*
+ * Search the ACL for an existing entry for 'id'. If one exists, just
+ * modify the entry in-place (well, in the same position, since we
+ * actually return a copy); otherwise, insert the new entry in
+ * sort-order.
+ */
+ /* find the first element not less than the element to be inserted */
+ for (dst = 0; dst < num && aclitemgt(mod_aip, old_aip + dst); ++dst)
+ ;
+ if (dst < num && aclitemeq(mod_aip, old_aip + dst))
+ {
+ /* modify in-place */
+ new_acl = makeacl(ACL_NUM(old_acl));
+ memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+ new_aip = ACL_DAT(new_acl);
+ src = dst;
+ }
+ else
+ {
+ new_acl = makeacl(num + 1);
+ new_aip = ACL_DAT(new_acl);
+ if (dst == 0)
+ { /* start */
+ elog(WARN, "aclinsert3: insertion before world ACL??");
+ }
+ else if (dst >= num)
+ { /* end */
+ memmove((char *) new_aip,
+ (char *) old_aip,
+ num * sizeof(AclItem));
+ }
+ else
+ { /* middle */
+ memmove((char *) new_aip,
+ (char *) old_aip,
+ dst * sizeof(AclItem));
+ memmove((char *) (new_aip + dst + 1),
+ (char *) (old_aip + dst),
+ (num - dst) * sizeof(AclItem));
+ }
+ new_aip[dst].ai_id = mod_aip->ai_id;
+ new_aip[dst].ai_idtype = mod_aip->ai_idtype;
+ num++; /* set num to the size of new_acl */
+ src = 0; /* world entry */
+ }
+ switch (modechg)
+ {
+ case ACL_MODECHG_ADD:
+ new_aip[dst].ai_mode =
+ old_aip[src].ai_mode | mod_aip->ai_mode;
+ break;
+ case ACL_MODECHG_DEL:
+ new_aip[dst].ai_mode =
+ old_aip[src].ai_mode & ~mod_aip->ai_mode;
+ break;
+ case ACL_MODECHG_EQL:
+ new_aip[dst].ai_mode =
+ mod_aip->ai_mode;
+ break;
+ }
+
+ /*
+ * if the newly added entry has no permissions, delete it from the
+ * list. For example, this helps in removing entries for users who no
+ * longer exists...
+ */
+ for (dst = 1; dst < num; dst++)
+ {
+ if (new_aip[dst].ai_mode == 0)
+ {
+ int i;
+
+ for (i = dst + 1; i < num; i++)
+ {
+ new_aip[i - 1].ai_id = new_aip[i].ai_id;
+ new_aip[i - 1].ai_idtype = new_aip[i].ai_idtype;
+ new_aip[i - 1].ai_mode = new_aip[i].ai_mode;
+ }
+ ARR_DIMS(new_acl)[0] = num - 1;
+ /* Adjust also the array size because it is used for memmove */
+ ARR_SIZE(new_acl) -= sizeof(AclItem);
+ break;
+ }
+ }
+
+ return (new_acl);
}
/*
* aclinsert
*
*/
-Acl *
-aclinsert(Acl *old_acl, AclItem *mod_aip)
+Acl *
+aclinsert(Acl * old_acl, AclItem * mod_aip)
{
- return(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL));
+ return (aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL));
}
-Acl *
-aclremove(Acl *old_acl, AclItem *mod_aip)
+Acl *
+aclremove(Acl * old_acl, AclItem * mod_aip)
{
- Acl *new_acl;
- AclItem *old_aip, *new_aip;
- unsigned dst, old_num, new_num;
-
- if (!old_acl || ACL_NUM(old_acl) < 1) {
- new_acl = makeacl(0);
- return(new_acl);
- }
- if (!mod_aip) {
- new_acl = makeacl(ACL_NUM(old_acl));
- memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
- return(new_acl);
- }
-
- old_num = ACL_NUM(old_acl);
- old_aip = ACL_DAT(old_acl);
-
- for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip+dst); ++dst)
- ;
- if (dst >= old_num) { /* not found or empty */
- new_acl = makeacl(ACL_NUM(old_acl));
- memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
- } else {
- new_num = old_num - 1;
- new_acl = makeacl(ACL_NUM(old_acl) - 1);
- new_aip = ACL_DAT(new_acl);
- if (dst == 0) { /* start */
- elog(WARN, "aclremove: removal of the world ACL??");
- } else if (dst == old_num - 1) {/* end */
- memmove((char *) new_aip,
- (char *) old_aip,
- new_num * sizeof(AclItem));
- } else { /* middle */
- memmove((char *) new_aip,
- (char *) old_aip,
- dst * sizeof(AclItem));
- memmove((char *) (new_aip+dst),
- (char *) (old_aip+dst+1),
- (new_num - dst) * sizeof(AclItem));
+ Acl *new_acl;
+ AclItem *old_aip,
+ *new_aip;
+ unsigned dst,
+ old_num,
+ new_num;
+
+ if (!old_acl || ACL_NUM(old_acl) < 1)
+ {
+ new_acl = makeacl(0);
+ return (new_acl);
}
- }
- return(new_acl);
+ if (!mod_aip)
+ {
+ new_acl = makeacl(ACL_NUM(old_acl));
+ memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+ return (new_acl);
+ }
+
+ old_num = ACL_NUM(old_acl);
+ old_aip = ACL_DAT(old_acl);
+
+ for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip + dst); ++dst)
+ ;
+ if (dst >= old_num)
+ { /* not found or empty */
+ new_acl = makeacl(ACL_NUM(old_acl));
+ memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
+ }
+ else
+ {
+ new_num = old_num - 1;
+ new_acl = makeacl(ACL_NUM(old_acl) - 1);
+ new_aip = ACL_DAT(new_acl);
+ if (dst == 0)
+ { /* start */
+ elog(WARN, "aclremove: removal of the world ACL??");
+ }
+ else if (dst == old_num - 1)
+ { /* end */
+ memmove((char *) new_aip,
+ (char *) old_aip,
+ new_num * sizeof(AclItem));
+ }
+ else
+ { /* middle */
+ memmove((char *) new_aip,
+ (char *) old_aip,
+ dst * sizeof(AclItem));
+ memmove((char *) (new_aip + dst),
+ (char *) (old_aip + dst + 1),
+ (new_num - dst) * sizeof(AclItem));
+ }
+ }
+ return (new_acl);
}
int32
-aclcontains(Acl *acl, AclItem *aip)
+aclcontains(Acl * acl, AclItem * aip)
{
- unsigned i, num;
- AclItem *aidat;
-
- if (!acl || !aip || ((num = ACL_NUM(acl)) < 1))
- return(0);
- aidat = ACL_DAT(acl);
- for (i = 0; i < num; ++i)
- if (aclitemeq(aip, aidat+i))
- return(1);
- return(0);
+ unsigned i,
+ num;
+ AclItem *aidat;
+
+ if (!acl || !aip || ((num = ACL_NUM(acl)) < 1))
+ return (0);
+ aidat = ACL_DAT(acl);
+ for (i = 0; i < num; ++i)
+ if (aclitemeq(aip, aidat + i))
+ return (1);
+ return (0);
}
/* parser support routines */
/*
* aclmakepriv
- * make a acl privilege string out of an existing privilege string
+ * make a acl privilege string out of an existing privilege string
* and a new privilege
*
* does not add duplicate privileges
- *
+ *
* the CALLER is reponsible for free'ing the string returned
*/
-char*
-aclmakepriv(char* old_privlist, char new_priv)
+char *
+aclmakepriv(char *old_privlist, char new_priv)
{
- char* priv;
- int i;
- int l;
+ char *priv;
+ int i;
+ int l;
- Assert(strlen(old_privlist)<5);
- priv = malloc(5); /* at most "rwaR" */;
+ Assert(strlen(old_privlist) < 5);
+ priv = malloc(5); /* at most "rwaR" */ ;
- if (old_privlist == NULL || old_privlist[0] == '\0') {
- priv[0] = new_priv;
- priv[1] = '\0';
- return priv;
- }
+ if (old_privlist == NULL || old_privlist[0] == '\0')
+ {
+ priv[0] = new_priv;
+ priv[1] = '\0';
+ return priv;
+ }
+
+ strcpy(priv, old_privlist);
+
+ l = strlen(old_privlist);
- strcpy(priv,old_privlist);
-
- l = strlen(old_privlist);
+ if (l == 4)
+ { /* can't add any more privileges */
+ return priv;
+ }
+
+ /* check to see if the new privilege is already in the old string */
+ for (i = 0; i < l; i++)
+ {
+ if (priv[i] == new_priv)
+ break;
+ }
+ if (i == l)
+ { /* we really have a new privilege */
+ priv[l] = new_priv;
+ priv[l + 1] = '\0';
+ }
- if (l == 4) { /* can't add any more privileges */
return priv;
- }
-
- /* check to see if the new privilege is already in the old string */
- for (i=0;i<l;i++) {
- if (priv[i] == new_priv)
- break;
- }
- if (i == l) { /* we really have a new privilege*/
- priv[l] = new_priv;
- priv[l+1] = '\0';
- }
-
- return priv;
}
/*
* aclmakeuser
- * user_type must be "A" - all users
- * "G" - group
- * "U" - user
+ * user_type must be "A" - all users
+ * "G" - group
+ * "U" - user
*
* concatentates the two strings together with a space in between
- *
+ *
* this routine is used in the parser
- *
+ *
* the CALLER is responsible for freeing the memory allocated
*/
-char*
-aclmakeuser(char* user_type, char* user)
+char *
+aclmakeuser(char *user_type, char *user)
{
- char* user_list;
-
- user_list = malloc(strlen(user) + 3);
- sprintf(user_list, "%s %s", user_type, user);
- return user_list;
+ char *user_list;
+
+ user_list = malloc(strlen(user) + 3);
+ sprintf(user_list, "%s %s", user_type, user);
+ return user_list;
}
/*
* makeAclStmt:
- * this is a helper routine called by the parser
+ * this is a helper routine called by the parser
* create a ChangeAclStmt
- * we take in the privilegs, relation_name_list, and grantee
+ * we take in the privilegs, relation_name_list, and grantee
* as well as a single character '+' or '-' to indicate grant or revoke
*
* returns a new ChangeACLStmt*
@@ -584,35 +652,34 @@ aclmakeuser(char* user_type, char* user)
* then calling aclparse;
*/
-ChangeACLStmt*
-makeAclStmt(char* privileges, List* rel_list, char* grantee,
- char grant_or_revoke)
+ChangeACLStmt *
+makeAclStmt(char *privileges, List * rel_list, char *grantee,
+ char grant_or_revoke)
{
- ChangeACLStmt *n = makeNode(ChangeACLStmt);
- char str[MAX_PARSE_BUFFER];
-
- n->aclitem = (AclItem*)palloc(sizeof(AclItem));
- /* the grantee string is "G <group_name>", "U <user_name>", or "ALL" */
- if (grantee[0] == 'G') /* group permissions */
+ ChangeACLStmt *n = makeNode(ChangeACLStmt);
+ char str[MAX_PARSE_BUFFER];
+
+ n->aclitem = (AclItem *) palloc(sizeof(AclItem));
+ /* the grantee string is "G <group_name>", "U <user_name>", or "ALL" */
+ if (grantee[0] == 'G') /* group permissions */
{
- sprintf(str,"%s %s%c%s",
- ACL_IDTYPE_GID_KEYWORD,
- grantee+2, grant_or_revoke,privileges);
- }
- else if (grantee[0] == 'U') /* user permission */
+ sprintf(str, "%s %s%c%s",
+ ACL_IDTYPE_GID_KEYWORD,
+ grantee + 2, grant_or_revoke, privileges);
+ }
+ else if (grantee[0] == 'U') /* user permission */
{
- sprintf(str,"%s %s%c%s",
- ACL_IDTYPE_UID_KEYWORD,
- grantee+2, grant_or_revoke,privileges);
+ sprintf(str, "%s %s%c%s",
+ ACL_IDTYPE_UID_KEYWORD,
+ grantee + 2, grant_or_revoke, privileges);
}
- else /* all permission */
+ else
+/* all permission */
{
- sprintf(str,"%c%s",
- grant_or_revoke,privileges);
+ sprintf(str, "%c%s",
+ grant_or_revoke, privileges);
}
- n->relNames = rel_list;
- aclparse(str, n->aclitem, (unsigned*)&n->modechg);
- return n;
+ n->relNames = rel_list;
+ aclparse(str, n->aclitem, (unsigned *) &n->modechg);
+ return n;
}
-
-
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 48a78366b01..073b0a1fd01 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* arrayfuncs.c--
- * Special functions for arrays.
+ * Special functions for arrays.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.15 1997/08/19 21:34:18 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.16 1997/09/07 04:49:55 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,1411 +30,1707 @@
#include "libpq/libpq-fs.h"
#include "libpq/be-fsstubs.h"
-#define ASSGN "="
+#define ASSGN "="
/* An array has the following internal structure:
- * <nbytes> - total number of bytes
- * <ndim> - number of dimensions of the array
- * <flags> - bit mask of flags
- * <dim> - size of each array axis
- * <dim_lower> - lower boundary of each dimension
- * <actual data> - whatever is the stored data
+ * <nbytes> - total number of bytes
+ * <ndim> - number of dimensions of the array
+ * <flags> - bit mask of flags
+ * <dim> - size of each array axis
+ * <dim_lower> - lower boundary of each dimension
+ * <actual data> - whatever is the stored data
*/
/*-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-*/
-static int _ArrayCount(char *str, int dim[], int typdelim);
-static char *_ReadArrayStr(char *arrayStr, int nitems, int ndim, int dim[],
- func_ptr inputproc, Oid typelem, char typdelim,
- int typlen, bool typbyval, char typalign,
- int *nbytes);
+static int _ArrayCount(char *str, int dim[], int typdelim);
+static char *
+_ReadArrayStr(char *arrayStr, int nitems, int ndim, int dim[],
+ func_ptr inputproc, Oid typelem, char typdelim,
+ int typlen, bool typbyval, char typalign,
+ int *nbytes);
+
#ifdef LOARRAY
-static char *_ReadLOArray(char *str, int *nbytes, int *fd, bool *chunkFlag,
- int ndim, int dim[], int baseSize);
+static char *
+_ReadLOArray(char *str, int *nbytes, int *fd, bool * chunkFlag,
+ int ndim, int dim[], int baseSize);
+
#endif
-static void _CopyArrayEls(char **values, char *p, int nitems, int typlen,
+static void
+_CopyArrayEls(char **values, char *p, int nitems, int typlen,
char typalign, bool typbyval);
-static void system_cache_lookup(Oid element_type, bool input, int *typlen,
- bool *typbyval, char *typdelim, Oid *typelem, Oid *proc,
- char *typalign);
-static Datum _ArrayCast(char *value, bool byval, int len);
+static void
+system_cache_lookup(Oid element_type, bool input, int *typlen,
+ bool * typbyval, char *typdelim, Oid * typelem, Oid * proc,
+ char *typalign);
+static Datum _ArrayCast(char *value, bool byval, int len);
+
#ifdef LOARRAY
-static char *_AdvanceBy1word(char *str, char **word);
+static char *_AdvanceBy1word(char *str, char **word);
+
#endif
-static void _ArrayRange(int st[], int endp[], int bsize, char *destPtr,
- ArrayType *array, int from);
-static int _ArrayClipCount(int stI[], int endpI[], ArrayType *array);
-static void _LOArrayRange(int st[], int endp[], int bsize, int srcfd,
- int destfd, ArrayType *array, int isSrcLO, bool *isNull);
-static void _ReadArray (int st[], int endp[], int bsize, int srcfd, int destfd,
- ArrayType *array, int isDestLO, bool *isNull);
-static ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest);
-static SanityCheckInput(int ndim, int n, int dim[], int lb[], int indx[]);
-static int array_read(char *destptr, int eltsize, int nitems, char *srcptr);
-static char *array_seek(char *ptr, int eltsize, int nitems);
+static void
+_ArrayRange(int st[], int endp[], int bsize, char *destPtr,
+ ArrayType * array, int from);
+static int _ArrayClipCount(int stI[], int endpI[], ArrayType * array);
+static void
+_LOArrayRange(int st[], int endp[], int bsize, int srcfd,
+ int destfd, ArrayType * array, int isSrcLO, bool * isNull);
+static void
+_ReadArray(int st[], int endp[], int bsize, int srcfd, int destfd,
+ ArrayType * array, int isDestLO, bool * isNull);
+static ArrayCastAndSet(char *src, bool typbyval, int typlen, char *dest);
+static SanityCheckInput(int ndim, int n, int dim[], int lb[], int indx[]);
+static int array_read(char *destptr, int eltsize, int nitems, char *srcptr);
+static char *array_seek(char *ptr, int eltsize, int nitems);
/*---------------------------------------------------------------------
- * array_in :
- * converts an array from the external format in "string" to
- * it internal format.
+ * array_in :
+ * converts an array from the external format in "string" to
+ * it internal format.
* return value :
- * the internal representation of the input array
+ * the internal representation of the input array
*--------------------------------------------------------------------
*/
-char *
-array_in(char *string, /* input array in external form */
- Oid element_type) /* type OID of an array element */
+char *
+array_in(char *string, /* input array in external form */
+ Oid element_type) /* type OID of an array element */
{
- int typlen;
- bool typbyval, done;
- char typdelim;
- Oid typinput;
- Oid typelem;
- char *string_save, *p, *q, *r;
- func_ptr inputproc;
- int i, nitems, dummy;
- int32 nbytes;
- char *dataPtr;
- ArrayType *retval = NULL;
- int ndim, dim[MAXDIM], lBound[MAXDIM];
- char typalign;
-
- system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
- &typelem, &typinput, &typalign);
-
- fmgr_info(typinput, &inputproc, &dummy);
-
- string_save = (char *) palloc(strlen(string) + 3);
- strcpy(string_save, string);
-
- /* --- read array dimensions ---------- */
- p = q = string_save; done = false;
- for ( ndim = 0; !done; ) {
- while (isspace(*p)) p++;
- if (*p == '[' ) {
- p++;
- if ((r = (char *)strchr(p, ':')) == (char *)NULL)
- lBound[ndim] = 1;
- else {
- *r = '\0';
- lBound[ndim] = atoi(p);
- p = r + 1;
- }
- for (q = p; isdigit(*q); q++);
- if (*q != ']')
- elog(WARN, "array_in: missing ']' in array declaration");
- *q = '\0';
- dim[ndim] = atoi(p);
- if ((dim[ndim] < 0) || (lBound[ndim] < 0))
- elog(WARN,"array_in: array dimensions need to be positive");
- dim[ndim] = dim[ndim] - lBound[ndim] + 1;
- if (dim[ndim] < 0)
- elog(WARN, "array_in: upper_bound cannot be < lower_bound");
- p = q + 1; ndim++;
- } else {
- done = true;
- }
- }
-
- if (ndim == 0) {
- if (*p == '{') {
- ndim = _ArrayCount(p, dim, typdelim);
- for (i = 0; i < ndim; lBound[i++] = 1);
- } else {
- elog(WARN,"array_in: Need to specify dimension");
- }
- } else {
- while (isspace(*p)) p++;
- if (strncmp(p, ASSGN, strlen(ASSGN)))
- elog(WARN, "array_in: missing assignment operator");
- p+= strlen(ASSGN);
- while (isspace(*p)) p++;
- }
-
+ int typlen;
+ bool typbyval,
+ done;
+ char typdelim;
+ Oid typinput;
+ Oid typelem;
+ char *string_save,
+ *p,
+ *q,
+ *r;
+ func_ptr inputproc;
+ int i,
+ nitems,
+ dummy;
+ int32 nbytes;
+ char *dataPtr;
+ ArrayType *retval = NULL;
+ int ndim,
+ dim[MAXDIM],
+ lBound[MAXDIM];
+ char typalign;
+
+ system_cache_lookup(element_type, true, &typlen, &typbyval, &typdelim,
+ &typelem, &typinput, &typalign);
+
+ fmgr_info(typinput, &inputproc, &dummy);
+
+ string_save = (char *) palloc(strlen(string) + 3);
+ strcpy(string_save, string);
+
+ /* --- read array dimensions ---------- */
+ p = q = string_save;
+ done = false;
+ for (ndim = 0; !done;)
+ {
+ while (isspace(*p))
+ p++;
+ if (*p == '[')
+ {
+ p++;
+ if ((r = (char *) strchr(p, ':')) == (char *) NULL)
+ lBound[ndim] = 1;
+ else
+ {
+ *r = '\0';
+ lBound[ndim] = atoi(p);
+ p = r + 1;
+ }
+ for (q = p; isdigit(*q); q++);
+ if (*q != ']')
+ elog(WARN, "array_in: missing ']' in array declaration");
+ *q = '\0';
+ dim[ndim] = atoi(p);
+ if ((dim[ndim] < 0) || (lBound[ndim] < 0))
+ elog(WARN, "array_in: array dimensions need to be positive");
+ dim[ndim] = dim[ndim] - lBound[ndim] + 1;
+ if (dim[ndim] < 0)
+ elog(WARN, "array_in: upper_bound cannot be < lower_bound");
+ p = q + 1;
+ ndim++;
+ }
+ else
+ {
+ done = true;
+ }
+ }
+
+ if (ndim == 0)
+ {
+ if (*p == '{')
+ {
+ ndim = _ArrayCount(p, dim, typdelim);
+ for (i = 0; i < ndim; lBound[i++] = 1);
+ }
+ else
+ {
+ elog(WARN, "array_in: Need to specify dimension");
+ }
+ }
+ else
+ {
+ while (isspace(*p))
+ p++;
+ if (strncmp(p, ASSGN, strlen(ASSGN)))
+ elog(WARN, "array_in: missing assignment operator");
+ p += strlen(ASSGN);
+ while (isspace(*p))
+ p++;
+ }
+
#ifdef ARRAYDEBUG
-printf( "array_in- ndim %d (", ndim);
-for (i = 0; i < ndim; i++) {
- printf(" %d", dim[i]);
-};
-printf( ") for %s\n", string);
+ printf("array_in- ndim %d (", ndim);
+ for (i = 0; i < ndim; i++)
+ {
+ printf(" %d", dim[i]);
+ };
+ printf(") for %s\n", string);
#endif
- nitems = getNitems( ndim, dim);
- if (nitems == 0) {
- char *emptyArray = palloc(sizeof(ArrayType));
- memset(emptyArray, 0, sizeof(ArrayType));
- * (int32 *) emptyArray = sizeof(ArrayType);
- return emptyArray;
- }
-
- if (*p == '{') {
- /* array not a large object */
- dataPtr =
- (char *) _ReadArrayStr(p, nitems, ndim, dim, inputproc, typelem,
- typdelim, typlen, typbyval, typalign,
- &nbytes );
- nbytes += ARR_OVERHEAD(ndim);
- retval = (ArrayType *) palloc(nbytes);
- memset(retval,0, nbytes);
- memmove(retval, (char *)&nbytes, sizeof(int));
- memmove((char*)ARR_NDIM_PTR(retval), (char *)&ndim, sizeof(int));
- SET_LO_FLAG (false, retval);
- memmove((char *)ARR_DIMS(retval), (char *)dim, ndim*sizeof(int));
- memmove((char *)ARR_LBOUND(retval), (char *)lBound,
- ndim*sizeof(int));
- /* dataPtr is an array of arbitraystuff even though its type is char*
- cast to char** to pass to _CopyArrayEls for now - jolly */
- _CopyArrayEls((char**)dataPtr,
- ARR_DATA_PTR(retval), nitems,
- typlen, typalign, typbyval);
- } else {
+ nitems = getNitems(ndim, dim);
+ if (nitems == 0)
+ {
+ char *emptyArray = palloc(sizeof(ArrayType));
+
+ memset(emptyArray, 0, sizeof(ArrayType));
+ *(int32 *) emptyArray = sizeof(ArrayType);
+ return emptyArray;
+ }
+
+ if (*p == '{')
+ {
+ /* array not a large object */
+ dataPtr =
+ (char *) _ReadArrayStr(p, nitems, ndim, dim, inputproc, typelem,
+ typdelim, typlen, typbyval, typalign,
+ &nbytes);
+ nbytes += ARR_OVERHEAD(ndim);
+ retval = (ArrayType *) palloc(nbytes);
+ memset(retval, 0, nbytes);
+ memmove(retval, (char *) &nbytes, sizeof(int));
+ memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
+ SET_LO_FLAG(false, retval);
+ memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
+ memmove((char *) ARR_LBOUND(retval), (char *) lBound,
+ ndim * sizeof(int));
+
+ /*
+ * dataPtr is an array of arbitraystuff even though its type is
+ * char* cast to char** to pass to _CopyArrayEls for now - jolly
+ */
+ _CopyArrayEls((char **) dataPtr,
+ ARR_DATA_PTR(retval), nitems,
+ typlen, typalign, typbyval);
+ }
+ else
+ {
#ifdef LOARRAY
- int dummy, bytes;
- bool chunked = false;
-
- dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
- dim, typlen );
- nbytes = bytes + ARR_OVERHEAD(ndim);
- retval = (ArrayType *) palloc(nbytes);
- memset(retval, 0,nbytes);
- memmove(retval, (char *)&nbytes, sizeof(int));
- memmove((char *)ARR_NDIM_PTR(retval), (char *)&ndim, sizeof(int));
- SET_LO_FLAG (true, retval);
- SET_CHUNK_FLAG (chunked, retval);
- memmove((char *)ARR_DIMS(retval), (char *)dim, ndim*sizeof(int));
- memmove((char *)ARR_LBOUND(retval),(char *)lBound, ndim*sizeof(int));
- memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
+ int dummy,
+ bytes;
+ bool chunked = false;
+
+ dataPtr = _ReadLOArray(p, &bytes, &dummy, &chunked, ndim,
+ dim, typlen);
+ nbytes = bytes + ARR_OVERHEAD(ndim);
+ retval = (ArrayType *) palloc(nbytes);
+ memset(retval, 0, nbytes);
+ memmove(retval, (char *) &nbytes, sizeof(int));
+ memmove((char *) ARR_NDIM_PTR(retval), (char *) &ndim, sizeof(int));
+ SET_LO_FLAG(true, retval);
+ SET_CHUNK_FLAG(chunked, retval);
+ memmove((char *) ARR_DIMS(retval), (char *) dim, ndim * sizeof(int));
+ memmove((char *) ARR_LBOUND(retval), (char *) lBound, ndim * sizeof(int));
+ memmove(ARR_DATA_PTR(retval), dataPtr, bytes);
#endif
- elog(WARN, "large object arrays not supported");
- }
- pfree(string_save);
- return((char *)retval);
+ elog(WARN, "large object arrays not supported");
+ }
+ pfree(string_save);
+ return ((char *) retval);
}
/*-----------------------------------------------------------------------------
* _ArrayCount --
- * Counts the number of dimensions and the dim[] array for an array string.
- * The syntax for array input is C-like nested curly braces
+ * Counts the number of dimensions and the dim[] array for an array string.
+ * The syntax for array input is C-like nested curly braces
*-----------------------------------------------------------------------------
*/
static int
_ArrayCount(char *str, int dim[], int typdelim)
{
- int nest_level = 0, i;
- int ndim = 0, temp[MAXDIM];
- bool scanning_string = false;
- bool eoArray = false;
- char *q;
-
- for (i = 0; i < MAXDIM; ++i) {
- temp[i] = dim[i] = 0;
- }
-
- if (strncmp (str, "{}", 2) == 0) return(0);
-
- q = str;
- while (eoArray != true) {
- bool done = false;
- while (!done) {
- switch (*q) {
- case '\\':
- /* skip escaped characters (\ and ") inside strings */
- if (scanning_string && *(q+1)) {
- q++;
- }
- break;
- case '\0':
- /* Signal a premature end of the string. DZ - 2-9-1996 */
- elog(WARN, "malformed array constant: %s", str);
- break;
- case '\"':
- scanning_string = ! scanning_string;
- break;
- case '{':
- if (!scanning_string) {
- temp[nest_level] = 0;
- nest_level++;
- }
- break;
- case '}':
- if (!scanning_string) {
- if (!ndim) ndim = nest_level;
- nest_level--;
- if (nest_level) temp[nest_level-1]++;
- if (nest_level == 0) eoArray = done = true;
+ int nest_level = 0,
+ i;
+ int ndim = 0,
+ temp[MAXDIM];
+ bool scanning_string = false;
+ bool eoArray = false;
+ char *q;
+
+ for (i = 0; i < MAXDIM; ++i)
+ {
+ temp[i] = dim[i] = 0;
+ }
+
+ if (strncmp(str, "{}", 2) == 0)
+ return (0);
+
+ q = str;
+ while (eoArray != true)
+ {
+ bool done = false;
+
+ while (!done)
+ {
+ switch (*q)
+ {
+ case '\\':
+ /* skip escaped characters (\ and ") inside strings */
+ if (scanning_string && *(q + 1))
+ {
+ q++;
+ }
+ break;
+ case '\0':
+ /* Signal a premature end of the string. DZ - 2-9-1996 */
+ elog(WARN, "malformed array constant: %s", str);
+ break;
+ case '\"':
+ scanning_string = !scanning_string;
+ break;
+ case '{':
+ if (!scanning_string)
+ {
+ temp[nest_level] = 0;
+ nest_level++;
+ }
+ break;
+ case '}':
+ if (!scanning_string)
+ {
+ if (!ndim)
+ ndim = nest_level;
+ nest_level--;
+ if (nest_level)
+ temp[nest_level - 1]++;
+ if (nest_level == 0)
+ eoArray = done = true;
+ }
+ break;
+ default:
+ if (!ndim)
+ ndim = nest_level;
+ if (*q == typdelim && !scanning_string)
+ done = true;
+ break;
+ }
+ if (!done)
+ q++;
}
- break;
- default:
- if (!ndim) ndim = nest_level;
- if (*q == typdelim && !scanning_string )
- done = true;
- break;
- }
- if (!done) q++;
- }
- temp[ndim-1]++;
- q++;
- if (!eoArray)
- while (isspace(*q)) q++;
- }
- for (i = 0; i < ndim; ++i) {
- dim[i] = temp[i];
- }
-
- return(ndim);
+ temp[ndim - 1]++;
+ q++;
+ if (!eoArray)
+ while (isspace(*q))
+ q++;
+ }
+ for (i = 0; i < ndim; ++i)
+ {
+ dim[i] = temp[i];
+ }
+
+ return (ndim);
}
/*---------------------------------------------------------------------------
* _ReadArrayStr :
- * parses the array string pointed by "arrayStr" and converts it in the
- * internal format. The external format expected is like C array
- * declaration. Unspecified elements are initialized to zero for fixed length
- * base types and to empty varlena structures for variable length base
- * types.
+ * parses the array string pointed by "arrayStr" and converts it in the
+ * internal format. The external format expected is like C array
+ * declaration. Unspecified elements are initialized to zero for fixed length
+ * base types and to empty varlena structures for variable length base
+ * types.
* result :
- * returns the internal representation of the array elements
- * nbytes is set to the size of the array in its internal representation.
+ * returns the internal representation of the array elements
+ * nbytes is set to the size of the array in its internal representation.
*---------------------------------------------------------------------------
*/
-static char *
+static char *
_ReadArrayStr(char *arrayStr,
- int nitems,
- int ndim,
- int dim[],
- func_ptr inputproc, /* function used for the conversion */
- Oid typelem,
- char typdelim,
- int typlen,
- bool typbyval,
- char typalign,
- int *nbytes)
+ int nitems,
+ int ndim,
+ int dim[],
+ func_ptr inputproc, /* function used for the
+ * conversion */
+ Oid typelem,
+ char typdelim,
+ int typlen,
+ bool typbyval,
+ char typalign,
+ int *nbytes)
{
- int i, nest_level = 0;
- char *p, *q, *r, **values;
- bool scanning_string = false;
- int indx[MAXDIM], prod[MAXDIM];
- bool eoArray = false;
-
- mda_get_prod(ndim, dim, prod);
- for (i = 0; i < ndim; indx[i++] = 0);
- /* read array enclosed within {} */
- values = (char **) palloc(nitems * sizeof(char *));
- memset(values, 0, nitems * sizeof(char *));
- q = p = arrayStr;
-
- while ( ! eoArray ) {
- bool done = false;
- int i = -1;
-
- while (!done) {
- switch (*q) {
- case '\\':
- /* Crunch the string on top of the backslash. */
- for (r = q; *r != '\0'; r++) *r = *(r+1);
- break;
- case '\"':
- if (!scanning_string ) {
- while (p != q) p++;
- p++; /* get p past first doublequote */
- } else
- *q = '\0';
- scanning_string = ! scanning_string;
- break;
- case '{':
- if (!scanning_string) {
- p++;
- nest_level++;
- if (nest_level > ndim)
- elog(WARN, "array_in: illformed array constant");
- indx[nest_level - 1] = 0;
- indx[ndim - 1] = 0;
- }
- break;
- case '}':
- if (!scanning_string) {
- if (i == -1)
- i = tuple2linear(ndim, indx, prod);
- nest_level--;
- if (nest_level == 0)
- eoArray = done = true;
- else {
- *q = '\0';
- indx[nest_level - 1]++;
- }
- }
- break;
- default:
- if (*q == typdelim && !scanning_string ) {
- if (i == -1)
- i = tuple2linear(ndim, indx, prod);
- done = true;
- indx[ndim - 1]++;
+ int i,
+ nest_level = 0;
+ char *p,
+ *q,
+ *r,
+ **values;
+ bool scanning_string = false;
+ int indx[MAXDIM],
+ prod[MAXDIM];
+ bool eoArray = false;
+
+ mda_get_prod(ndim, dim, prod);
+ for (i = 0; i < ndim; indx[i++] = 0);
+ /* read array enclosed within {} */
+ values = (char **) palloc(nitems * sizeof(char *));
+ memset(values, 0, nitems * sizeof(char *));
+ q = p = arrayStr;
+
+ while (!eoArray)
+ {
+ bool done = false;
+ int i = -1;
+
+ while (!done)
+ {
+ switch (*q)
+ {
+ case '\\':
+ /* Crunch the string on top of the backslash. */
+ for (r = q; *r != '\0'; r++)
+ *r = *(r + 1);
+ break;
+ case '\"':
+ if (!scanning_string)
+ {
+ while (p != q)
+ p++;
+ p++; /* get p past first doublequote */
+ }
+ else
+ *q = '\0';
+ scanning_string = !scanning_string;
+ break;
+ case '{':
+ if (!scanning_string)
+ {
+ p++;
+ nest_level++;
+ if (nest_level > ndim)
+ elog(WARN, "array_in: illformed array constant");
+ indx[nest_level - 1] = 0;
+ indx[ndim - 1] = 0;
+ }
+ break;
+ case '}':
+ if (!scanning_string)
+ {
+ if (i == -1)
+ i = tuple2linear(ndim, indx, prod);
+ nest_level--;
+ if (nest_level == 0)
+ eoArray = done = true;
+ else
+ {
+ *q = '\0';
+ indx[nest_level - 1]++;
+ }
+ }
+ break;
+ default:
+ if (*q == typdelim && !scanning_string)
+ {
+ if (i == -1)
+ i = tuple2linear(ndim, indx, prod);
+ done = true;
+ indx[ndim - 1]++;
+ }
+ break;
+ }
+ if (!done)
+ q++;
}
- break;
- }
- if (!done)
- q++;
- }
- *q = '\0';
- if (i >= nitems)
- elog(WARN, "array_in: illformed array constant");
- values[i] = (*inputproc) (p, typelem);
- p = ++q;
- if (!eoArray)
- /*
- * if not at the end of the array skip white space
- */
- while (isspace(*q)) {
- p++;
- q++;
- }
- }
- if (typlen > 0) {
- *nbytes = nitems * typlen;
- if (!typbyval)
- for (i = 0; i < nitems; i++)
- if (!values[i]) {
- values[i] = palloc(typlen);
- memset(values[i], 0, typlen);
- }
- } else {
- for (i = 0, *nbytes = 0; i < nitems; i++) {
- if (values[i]) {
- if (typalign=='d') {
- *nbytes += DOUBLEALIGN(* (int32 *) values[i]);
- } else {
- *nbytes += INTALIGN(* (int32 *) values[i]);
+ *q = '\0';
+ if (i >= nitems)
+ elog(WARN, "array_in: illformed array constant");
+ values[i] = (*inputproc) (p, typelem);
+ p = ++q;
+ if (!eoArray)
+
+ /*
+ * if not at the end of the array skip white space
+ */
+ while (isspace(*q))
+ {
+ p++;
+ q++;
+ }
+ }
+ if (typlen > 0)
+ {
+ *nbytes = nitems * typlen;
+ if (!typbyval)
+ for (i = 0; i < nitems; i++)
+ if (!values[i])
+ {
+ values[i] = palloc(typlen);
+ memset(values[i], 0, typlen);
+ }
+ }
+ else
+ {
+ for (i = 0, *nbytes = 0; i < nitems; i++)
+ {
+ if (values[i])
+ {
+ if (typalign == 'd')
+ {
+ *nbytes += DOUBLEALIGN(*(int32 *) values[i]);
+ }
+ else
+ {
+ *nbytes += INTALIGN(*(int32 *) values[i]);
+ }
+ }
+ else
+ {
+ *nbytes += sizeof(int32);
+ values[i] = palloc(sizeof(int32));
+ *(int32 *) values[i] = sizeof(int32);
+ }
}
- } else {
- *nbytes += sizeof(int32);
- values[i] = palloc(sizeof(int32));
- *(int32 *)values[i] = sizeof(int32);
- }
- }
- }
- return((char *)values);
+ }
+ return ((char *) values);
}
/*----------------------------------------------------------------------------
- * Read data about an array to be stored as a large object
+ * Read data about an array to be stored as a large object
*----------------------------------------------------------------------------
*/
#ifdef LOARRAY
-static char *
+static char *
_ReadLOArray(char *str,
- int *nbytes,
- int *fd,
- bool *chunkFlag,
- int ndim,
- int dim[],
- int baseSize)
+ int *nbytes,
+ int *fd,
+ bool * chunkFlag,
+ int ndim,
+ int dim[],
+ int baseSize)
{
- char *inputfile, *accessfile = NULL, *chunkfile = NULL;
- char *retStr, *_AdvanceBy1word();
- Oid lobjId;
-
- str = _AdvanceBy1word(str, &inputfile);
-
- while (str != NULL) {
- char *word;
-
- str = _AdvanceBy1word(str, &word);
-
- if (!strcmp (word, "-chunk")) {
- if (str == NULL)
- elog(WARN, "array_in: access pattern file required");
- str = _AdvanceBy1word(str, &accessfile);
- }
- else if (!strcmp (word, "-noreorg")) {
- if (str == NULL)
- elog(WARN, "array_in: chunk file required");
- str = _AdvanceBy1word(str, &chunkfile);
- } else {
- elog(WARN, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
+ char *inputfile,
+ *accessfile = NULL,
+ *chunkfile = NULL;
+ char *retStr,
+ *_AdvanceBy1word();
+ Oid lobjId;
+
+ str = _AdvanceBy1word(str, &inputfile);
+
+ while (str != NULL)
+ {
+ char *word;
+
+ str = _AdvanceBy1word(str, &word);
+
+ if (!strcmp(word, "-chunk"))
+ {
+ if (str == NULL)
+ elog(WARN, "array_in: access pattern file required");
+ str = _AdvanceBy1word(str, &accessfile);
+ }
+ else if (!strcmp(word, "-noreorg"))
+ {
+ if (str == NULL)
+ elog(WARN, "array_in: chunk file required");
+ str = _AdvanceBy1word(str, &chunkfile);
+ }
+ else
+ {
+ elog(WARN, "usage: <input file> -chunk DEFAULT/<access pattern file> -invert/-native [-noreorg <chunk file>]");
+ }
+ }
+
+ if (inputfile == NULL)
+ elog(WARN, "array_in: missing file name");
+ lobjId = lo_creat(0);
+ *fd = lo_open(lobjId, INV_READ);
+ if (*fd < 0)
+ elog(WARN, "Large object create failed");
+ retStr = inputfile;
+ *nbytes = strlen(retStr) + 2;
+
+ if (accessfile)
+ {
+ FILE *afd;
+
+ if ((afd = AllocateFile(accessfile, "r")) == NULL)
+ elog(WARN, "unable to open access pattern file");
+ *chunkFlag = true;
+ retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
+ chunkfile);
+ FreeFile(afd);
}
- }
-
- if (inputfile == NULL)
- elog(WARN, "array_in: missing file name");
- lobjId = lo_creat(0);
- *fd = lo_open(lobjId, INV_READ);
- if ( *fd < 0 )
- elog(WARN, "Large object create failed");
- retStr = inputfile;
- *nbytes = strlen(retStr) + 2;
-
- if ( accessfile ) {
- FILE *afd;
- if ((afd = AllocateFile(accessfile, "r")) == NULL)
- elog(WARN, "unable to open access pattern file");
- *chunkFlag = true;
- retStr = _ChunkArray(*fd, afd, ndim, dim, baseSize, nbytes,
- chunkfile);
- FreeFile(afd);
- }
- return(retStr);
+ return (retStr);
}
+
#endif
static void
-_CopyArrayEls(char **values,
- char *p,
- int nitems,
- int typlen,
- char typalign,
- bool typbyval)
+_CopyArrayEls(char **values,
+ char *p,
+ int nitems,
+ int typlen,
+ char typalign,
+ bool typbyval)
{
- int i;
-
- for (i = 0; i < nitems; i++) {
- int inc;
- inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
- p += inc;
- if (!typbyval)
- pfree(values[i]);
- }
- pfree(values);
+ int i;
+
+ for (i = 0; i < nitems; i++)
+ {
+ int inc;
+
+ inc = ArrayCastAndSet(values[i], typbyval, typlen, p);
+ p += inc;
+ if (!typbyval)
+ pfree(values[i]);
+ }
+ pfree(values);
}
/*-------------------------------------------------------------------------
- * array_out :
- * takes the internal representation of an array and returns a string
- * containing the array in its external format.
+ * array_out :
+ * takes the internal representation of an array and returns a string
+ * containing the array in its external format.
*-------------------------------------------------------------------------
*/
-char *
-array_out(ArrayType *v, Oid element_type)
+char *
+array_out(ArrayType * v, Oid element_type)
{
- int typlen;
- bool typbyval;
- char typdelim;
- Oid typoutput, typelem;
- func_ptr outputproc;
- char typalign;
-
- char *p, *retval, **values, delim[2];
- int nitems, overall_length, i, j, k, indx[MAXDIM];
- bool dummy_bool;
- int dummy_int;
- int ndim, *dim;
-
- if (v == (ArrayType *) NULL)
- return ((char *) NULL);
-
- if (ARR_IS_LO(v) == true) {
- char *p, *save_p;
- int nbytes;
-
- /* get a wide string to print to */
- p = array_dims(v, &dummy_bool);
- nbytes = strlen(ARR_DATA_PTR(v)) + 4 + *(int *)p;
-
- save_p = (char *) palloc(nbytes);
-
- strcpy(save_p, p + sizeof(int));
- strcat(save_p, ASSGN);
- strcat(save_p, ARR_DATA_PTR(v));
- pfree(p);
- return (save_p);
- }
-
- system_cache_lookup(element_type, false, &typlen, &typbyval,
- &typdelim, &typelem, &typoutput, &typalign);
- fmgr_info(typoutput, & outputproc, &dummy_int);
- sprintf(delim, "%c", typdelim);
- ndim = ARR_NDIM(v);
- dim = ARR_DIMS(v);
- nitems = getNitems(ndim, dim);
-
- if (nitems == 0) {
- char *emptyArray = palloc(3);
- emptyArray[0] = '{';
- emptyArray[1] = '}';
- emptyArray[2] = '\0';
- return emptyArray;
- }
-
- p = ARR_DATA_PTR(v);
- overall_length = 1; /* [TRH] don't forget to count \0 at end. */
- values = (char **) palloc(nitems * sizeof (char *));
- for (i = 0; i < nitems; i++) {
- if (typbyval) {
- switch(typlen) {
- case 1:
- values[i] = (*outputproc) (*p, typelem);
- break;
- case 2:
- values[i] = (*outputproc) (* (int16 *) p, typelem);
- break;
- case 3:
- case 4:
- values[i] = (*outputproc) (* (int32 *) p, typelem);
- break;
- }
- p += typlen;
- } else {
- values[i] = (*outputproc) (p, typelem);
- if (typlen > 0)
- p += typlen;
- else
- p += INTALIGN(* (int32 *) p);
- /*
- * For the pair of double quotes
- */
- overall_length += 2;
- }
- overall_length += (strlen(values[i]) + 1);
- }
-
- /*
- * count total number of curly braces in output string
- */
- for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
-
- p = (char *) palloc(overall_length + 2*j);
- retval = p;
-
- strcpy(p, "{");
- for (i = 0; i < ndim; indx[i++] = 0);
- j = 0; k = 0;
- do {
- for (i = j; i < ndim - 1; i++)
- strcat(p, "{");
- /*
- * Surround anything that is not passed by value in double quotes.
- * See above for more details.
+ int typlen;
+ bool typbyval;
+ char typdelim;
+ Oid typoutput,
+ typelem;
+ func_ptr outputproc;
+ char typalign;
+
+ char *p,
+ *retval,
+ **values,
+ delim[2];
+ int nitems,
+ overall_length,
+ i,
+ j,
+ k,
+ indx[MAXDIM];
+ bool dummy_bool;
+ int dummy_int;
+ int ndim,
+ *dim;
+
+ if (v == (ArrayType *) NULL)
+ return ((char *) NULL);
+
+ if (ARR_IS_LO(v) == true)
+ {
+ char *p,
+ *save_p;
+ int nbytes;
+
+ /* get a wide string to print to */
+ p = array_dims(v, &dummy_bool);
+ nbytes = strlen(ARR_DATA_PTR(v)) + 4 + *(int *) p;
+
+ save_p = (char *) palloc(nbytes);
+
+ strcpy(save_p, p + sizeof(int));
+ strcat(save_p, ASSGN);
+ strcat(save_p, ARR_DATA_PTR(v));
+ pfree(p);
+ return (save_p);
+ }
+
+ system_cache_lookup(element_type, false, &typlen, &typbyval,
+ &typdelim, &typelem, &typoutput, &typalign);
+ fmgr_info(typoutput, &outputproc, &dummy_int);
+ sprintf(delim, "%c", typdelim);
+ ndim = ARR_NDIM(v);
+ dim = ARR_DIMS(v);
+ nitems = getNitems(ndim, dim);
+
+ if (nitems == 0)
+ {
+ char *emptyArray = palloc(3);
+
+ emptyArray[0] = '{';
+ emptyArray[1] = '}';
+ emptyArray[2] = '\0';
+ return emptyArray;
+ }
+
+ p = ARR_DATA_PTR(v);
+ overall_length = 1; /* [TRH] don't forget to count \0 at end. */
+ values = (char **) palloc(nitems * sizeof(char *));
+ for (i = 0; i < nitems; i++)
+ {
+ if (typbyval)
+ {
+ switch (typlen)
+ {
+ case 1:
+ values[i] = (*outputproc) (*p, typelem);
+ break;
+ case 2:
+ values[i] = (*outputproc) (*(int16 *) p, typelem);
+ break;
+ case 3:
+ case 4:
+ values[i] = (*outputproc) (*(int32 *) p, typelem);
+ break;
+ }
+ p += typlen;
+ }
+ else
+ {
+ values[i] = (*outputproc) (p, typelem);
+ if (typlen > 0)
+ p += typlen;
+ else
+ p += INTALIGN(*(int32 *) p);
+
+ /*
+ * For the pair of double quotes
+ */
+ overall_length += 2;
+ }
+ overall_length += (strlen(values[i]) + 1);
+ }
+
+ /*
+ * count total number of curly braces in output string
*/
- if (!typbyval) {
- strcat(p, "\"");
- strcat(p, values[k]);
- strcat(p, "\"");
- } else
- strcat(p, values[k]);
- pfree(values[k++]);
-
- for (i = ndim - 1; i >= 0; i--) {
- indx[i] = (indx[i] + 1)%dim[i];
- if (indx[i]) {
- strcat (p, delim);
- break;
- } else
- strcat (p, "}");
- }
- j = i;
- } while (j != -1);
-
- pfree(values);
- return(retval);
+ for (i = j = 0, k = 1; i < ndim; k *= dim[i++], j += k);
+
+ p = (char *) palloc(overall_length + 2 * j);
+ retval = p;
+
+ strcpy(p, "{");
+ for (i = 0; i < ndim; indx[i++] = 0);
+ j = 0;
+ k = 0;
+ do
+ {
+ for (i = j; i < ndim - 1; i++)
+ strcat(p, "{");
+
+ /*
+ * Surround anything that is not passed by value in double quotes.
+ * See above for more details.
+ */
+ if (!typbyval)
+ {
+ strcat(p, "\"");
+ strcat(p, values[k]);
+ strcat(p, "\"");
+ }
+ else
+ strcat(p, values[k]);
+ pfree(values[k++]);
+
+ for (i = ndim - 1; i >= 0; i--)
+ {
+ indx[i] = (indx[i] + 1) % dim[i];
+ if (indx[i])
+ {
+ strcat(p, delim);
+ break;
+ }
+ else
+ strcat(p, "}");
+ }
+ j = i;
+ } while (j != -1);
+
+ pfree(values);
+ return (retval);
}
/*-----------------------------------------------------------------------------
* array_dims :
- * returns the dimension of the array pointed to by "v"
- *----------------------------------------------------------------------------
+ * returns the dimension of the array pointed to by "v"
+ *----------------------------------------------------------------------------
*/
-char *
-array_dims(ArrayType *v, bool *isNull)
+char *
+array_dims(ArrayType * v, bool * isNull)
{
- char *p, *save_p;
- int nbytes, i;
- int *dimv, *lb;
-
- if (v == (ArrayType *) NULL) RETURN_NULL;
- nbytes = ARR_NDIM(v)*33;
- /*
- * 33 since we assume 15 digits per number + ':' +'[]'
- */
- save_p = p = (char *) palloc(nbytes + 4);
- memset(save_p, 0, nbytes + 4);
- dimv = ARR_DIMS(v); lb = ARR_LBOUND(v);
- p += 4;
- for (i = 0; i < ARR_NDIM(v); i++) {
- sprintf(p, "[%d:%d]", lb[i], dimv[i]+lb[i]-1);
- p += strlen(p);
- }
- nbytes = strlen(save_p + 4) + 4;
- memmove(save_p, &nbytes,4);
- return (save_p);
-}
+ char *p,
+ *save_p;
+ int nbytes,
+ i;
+ int *dimv,
+ *lb;
+
+ if (v == (ArrayType *) NULL)
+ RETURN_NULL;
+ nbytes = ARR_NDIM(v) * 33;
+
+ /*
+ * 33 since we assume 15 digits per number + ':' +'[]'
+ */
+ save_p = p = (char *) palloc(nbytes + 4);
+ memset(save_p, 0, nbytes + 4);
+ dimv = ARR_DIMS(v);
+ lb = ARR_LBOUND(v);
+ p += 4;
+ for (i = 0; i < ARR_NDIM(v); i++)
+ {
+ sprintf(p, "[%d:%d]", lb[i], dimv[i] + lb[i] - 1);
+ p += strlen(p);
+ }
+ nbytes = strlen(save_p + 4) + 4;
+ memmove(save_p, &nbytes, 4);
+ return (save_p);
+}
/*---------------------------------------------------------------------------
* array_ref :
- * This routing takes an array pointer and an index array and returns
- * a pointer to the referred element if element is passed by
- * reference otherwise returns the value of the referred element.
+ * This routing takes an array pointer and an index array and returns
+ * a pointer to the referred element if element is passed by
+ * reference otherwise returns the value of the referred element.
*---------------------------------------------------------------------------
*/
Datum
-array_ref(ArrayType *array,
- int n,
- int indx[],
- int reftype,
- int elmlen,
- int arraylen,
- bool *isNull)
+array_ref(ArrayType * array,
+ int n,
+ int indx[],
+ int reftype,
+ int elmlen,
+ int arraylen,
+ bool * isNull)
{
- int i, ndim, *dim, *lb, offset, nbytes;
- struct varlena *v = NULL;
- char *retval = NULL;
-
- if (array == (ArrayType *) NULL) RETURN_NULL;
- if (arraylen > 0) {
- /*
- * fixed length arrays -- these are assumed to be 1-d
- */
- if (indx[0]*elmlen > arraylen)
- elog(WARN, "array_ref: array bound exceeded");
- retval = (char *)array + indx[0]*elmlen;
- return _ArrayCast(retval, reftype, elmlen);
- }
- dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array);
- ndim = ARR_NDIM(array);
- nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
-
- if (!SanityCheckInput(ndim, n, dim, lb, indx))
- RETURN_NULL;
-
- offset = GetOffset(n, dim, lb, indx);
-
- if (ARR_IS_LO(array)) {
- char * lo_name;
- int fd = 0;
-
- /* We are assuming fixed element lengths here */
- offset *= elmlen;
- lo_name = (char *)ARR_DATA_PTR(array);
+ int i,
+ ndim,
+ *dim,
+ *lb,
+ offset,
+ nbytes;
+ struct varlena *v = NULL;
+ char *retval = NULL;
+
+ if (array == (ArrayType *) NULL)
+ RETURN_NULL;
+ if (arraylen > 0)
+ {
+
+ /*
+ * fixed length arrays -- these are assumed to be 1-d
+ */
+ if (indx[0] * elmlen > arraylen)
+ elog(WARN, "array_ref: array bound exceeded");
+ retval = (char *) array + indx[0] * elmlen;
+ return _ArrayCast(retval, reftype, elmlen);
+ }
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ndim = ARR_NDIM(array);
+ nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
+
+ if (!SanityCheckInput(ndim, n, dim, lb, indx))
+ RETURN_NULL;
+
+ offset = GetOffset(n, dim, lb, indx);
+
+ if (ARR_IS_LO(array))
+ {
+ char *lo_name;
+ int fd = 0;
+
+ /* We are assuming fixed element lengths here */
+ offset *= elmlen;
+ lo_name = (char *) ARR_DATA_PTR(array);
#ifdef LOARRAY
- if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0)
- RETURN_NULL;
-#endif
- if (ARR_IS_CHUNKED(array))
- v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
- else {
- if (lo_lseek(fd, offset, SEEK_SET) < 0)
- RETURN_NULL;
+ if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
+ RETURN_NULL;
+#endif
+ if (ARR_IS_CHUNKED(array))
+ v = _ReadChunkArray1El(indx, elmlen, fd, array, isNull);
+ else
+ {
+ if (lo_lseek(fd, offset, SEEK_SET) < 0)
+ RETURN_NULL;
#ifdef LOARRAY
- v = (struct varlena *) LOread(fd, elmlen);
+ v = (struct varlena *) LOread(fd, elmlen);
#endif
- }
- if (*isNull) RETURN_NULL;
- if (VARSIZE(v) - 4 < elmlen)
- RETURN_NULL;
- lo_close(fd);
- retval = (char *)_ArrayCast((char *)VARDATA(v), reftype, elmlen);
- if ( reftype == 0) { /* not by value */
- char * tempdata = palloc (elmlen);
- memmove(tempdata, retval, elmlen);
- retval = tempdata;
+ }
+ if (*isNull)
+ RETURN_NULL;
+ if (VARSIZE(v) - 4 < elmlen)
+ RETURN_NULL;
+ lo_close(fd);
+ retval = (char *) _ArrayCast((char *) VARDATA(v), reftype, elmlen);
+ if (reftype == 0)
+ { /* not by value */
+ char *tempdata = palloc(elmlen);
+
+ memmove(tempdata, retval, elmlen);
+ retval = tempdata;
+ }
+ pfree(v);
+ return (Datum) retval;
+ }
+
+ if (elmlen > 0)
+ {
+ offset = offset * elmlen;
+ /* off the end of the array */
+ if (nbytes - offset < 1)
+ RETURN_NULL;
+ retval = ARR_DATA_PTR(array) + offset;
+ return _ArrayCast(retval, reftype, elmlen);
+ }
+ else
+ {
+ bool done = false;
+ char *temp;
+ int bytes = nbytes;
+
+ temp = ARR_DATA_PTR(array);
+ i = 0;
+ while (bytes > 0 && !done)
+ {
+ if (i == offset)
+ {
+ retval = temp;
+ done = true;
+ }
+ bytes -= INTALIGN(*(int32 *) temp);
+ temp += INTALIGN(*(int32 *) temp);
+ i++;
+ }
+ if (!done)
+ RETURN_NULL;
+ return (Datum) retval;
}
- pfree(v);
- return (Datum) retval;
- }
-
- if (elmlen > 0) {
- offset = offset * elmlen;
- /* off the end of the array */
- if (nbytes - offset < 1) RETURN_NULL;
- retval = ARR_DATA_PTR (array) + offset;
- return _ArrayCast(retval, reftype, elmlen);
- } else {
- bool done = false;
- char *temp;
- int bytes = nbytes;
- temp = ARR_DATA_PTR (array);
- i = 0;
- while (bytes > 0 && !done) {
- if (i == offset) {
- retval = temp;
- done = true;
- }
- bytes -= INTALIGN(* (int32 *) temp);
- temp += INTALIGN(* (int32 *) temp);
- i++;
- }
- if (! done)
- RETURN_NULL;
- return (Datum) retval;
- }
}
/*-----------------------------------------------------------------------------
* array_clip :
- * This routine takes an array and a range of indices (upperIndex and
- * lowerIndx), creates a new array structure for the referred elements
- * and returns a pointer to it.
+ * This routine takes an array and a range of indices (upperIndex and
+ * lowerIndx), creates a new array structure for the referred elements
+ * and returns a pointer to it.
*-----------------------------------------------------------------------------
*/
Datum
-array_clip(ArrayType *array,
- int n,
- int upperIndx[],
- int lowerIndx[],
- int reftype,
- int len,
- bool *isNull)
+array_clip(ArrayType * array,
+ int n,
+ int upperIndx[],
+ int lowerIndx[],
+ int reftype,
+ int len,
+ bool * isNull)
{
- int i, ndim, *dim, *lb, nbytes;
- ArrayType *newArr;
- int bytes, span[MAXDIM];
-
- /* timer_start(); */
- if (array == (ArrayType *) NULL)
- RETURN_NULL;
- dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array);
- ndim = ARR_NDIM(array);
- nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
-
- if (!SanityCheckInput(ndim, n, dim, lb, upperIndx))
- RETURN_NULL;
-
- if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx))
- RETURN_NULL;
-
- for (i = 0; i < n; i++)
- if (lowerIndx[i] > upperIndx[i])
- elog(WARN, "lowerIndex cannot be larger than upperIndx");
- mda_get_range(n, span, lowerIndx, upperIndx);
-
- if (ARR_IS_LO(array)) {
+ int i,
+ ndim,
+ *dim,
+ *lb,
+ nbytes;
+ ArrayType *newArr;
+ int bytes,
+ span[MAXDIM];
+
+ /* timer_start(); */
+ if (array == (ArrayType *) NULL)
+ RETURN_NULL;
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ndim = ARR_NDIM(array);
+ nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
+
+ if (!SanityCheckInput(ndim, n, dim, lb, upperIndx))
+ RETURN_NULL;
+
+ if (!SanityCheckInput(ndim, n, dim, lb, lowerIndx))
+ RETURN_NULL;
+
+ for (i = 0; i < n; i++)
+ if (lowerIndx[i] > upperIndx[i])
+ elog(WARN, "lowerIndex cannot be larger than upperIndx");
+ mda_get_range(n, span, lowerIndx, upperIndx);
+
+ if (ARR_IS_LO(array))
+ {
#ifdef LOARRAY
- char * lo_name;
+ char *lo_name;
+
#endif
- char *newname = NULL;
- int fd = 0, newfd = 0, isDestLO = true, rsize;
-
- if (len < 0)
- elog(WARN, "array_clip: array of variable length objects not supported");
+ char *newname = NULL;
+ int fd = 0,
+ newfd = 0,
+ isDestLO = true,
+ rsize;
+
+ if (len < 0)
+ elog(WARN, "array_clip: array of variable length objects not supported");
#ifdef LOARRAY
- lo_name = (char *)ARR_DATA_PTR(array);
- if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_READ:O_RDONLY)) < 0)
- RETURN_NULL;
- newname = _array_newLO( &newfd, Unix );
+ lo_name = (char *) ARR_DATA_PTR(array);
+ if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_READ : O_RDONLY)) < 0)
+ RETURN_NULL;
+ newname = _array_newLO(&newfd, Unix);
#endif
- bytes = strlen(newname) + 1 + ARR_OVERHEAD(n);
- newArr = (ArrayType *) palloc(bytes);
- memmove(newArr, array, sizeof(ArrayType));
- memmove(newArr, &bytes, sizeof(int));
- memmove(ARR_DIMS(newArr), span, n*sizeof(int));
- memmove(ARR_LBOUND(newArr), lowerIndx, n*sizeof(int));
- strcpy(ARR_DATA_PTR(newArr), newname);
-
- rsize = compute_size (lowerIndx, upperIndx, n, len);
- if (rsize < MAX_BUFF_SIZE) {
- char *buff;
- rsize += 4;
- buff = palloc(rsize);
- if ( buff )
- isDestLO = false;
- if (ARR_IS_CHUNKED(array)) {
- _ReadChunkArray(lowerIndx, upperIndx, len, fd, &(buff[4]),
- array,0,isNull);
- } else {
- _ReadArray(lowerIndx, upperIndx, len, fd, (int)&(buff[4]),
- array,
- 0,isNull);
- }
- memmove(buff, &rsize, 4);
+ bytes = strlen(newname) + 1 + ARR_OVERHEAD(n);
+ newArr = (ArrayType *) palloc(bytes);
+ memmove(newArr, array, sizeof(ArrayType));
+ memmove(newArr, &bytes, sizeof(int));
+ memmove(ARR_DIMS(newArr), span, n * sizeof(int));
+ memmove(ARR_LBOUND(newArr), lowerIndx, n * sizeof(int));
+ strcpy(ARR_DATA_PTR(newArr), newname);
+
+ rsize = compute_size(lowerIndx, upperIndx, n, len);
+ if (rsize < MAX_BUFF_SIZE)
+ {
+ char *buff;
+
+ rsize += 4;
+ buff = palloc(rsize);
+ if (buff)
+ isDestLO = false;
+ if (ARR_IS_CHUNKED(array))
+ {
+ _ReadChunkArray(lowerIndx, upperIndx, len, fd, &(buff[4]),
+ array, 0, isNull);
+ }
+ else
+ {
+ _ReadArray(lowerIndx, upperIndx, len, fd, (int) &(buff[4]),
+ array,
+ 0, isNull);
+ }
+ memmove(buff, &rsize, 4);
#ifdef LOARRAY
- if (! *isNull)
- bytes = LOwrite(newfd, (struct varlena *)buff);
+ if (!*isNull)
+ bytes = LOwrite(newfd, (struct varlena *) buff);
#endif
- pfree (buff);
- }
- if (isDestLO)
- if (ARR_IS_CHUNKED(array)) {
- _ReadChunkArray(lowerIndx, upperIndx, len, fd, (char*)newfd, array,
- 1,isNull);
- } else {
- _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1,isNull);
- }
+ pfree(buff);
+ }
+ if (isDestLO)
+ if (ARR_IS_CHUNKED(array))
+ {
+ _ReadChunkArray(lowerIndx, upperIndx, len, fd, (char *) newfd, array,
+ 1, isNull);
+ }
+ else
+ {
+ _ReadArray(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
+ }
#ifdef LOARRAY
- LOclose(fd);
- LOclose(newfd);
+ LOclose(fd);
+ LOclose(newfd);
#endif
- if (*isNull) {
- pfree(newArr);
- newArr = NULL;
- }
- /* timer_end(); */
- return ((Datum) newArr);
- }
-
- if (len > 0) {
- bytes = getNitems(n, span);
- bytes = bytes*len + ARR_OVERHEAD(n);
- } else {
- bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
- bytes += ARR_OVERHEAD(n);
- }
- newArr = (ArrayType *) palloc(bytes);
- memmove(newArr, array, sizeof(ArrayType));
- memmove(newArr, &bytes, sizeof(int));
- memmove(ARR_DIMS(newArr), span, n*sizeof(int));
- memmove(ARR_LBOUND(newArr), lowerIndx, n*sizeof(int));
- _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1);
- return (Datum) newArr;
+ if (*isNull)
+ {
+ pfree(newArr);
+ newArr = NULL;
+ }
+ /* timer_end(); */
+ return ((Datum) newArr);
+ }
+
+ if (len > 0)
+ {
+ bytes = getNitems(n, span);
+ bytes = bytes * len + ARR_OVERHEAD(n);
+ }
+ else
+ {
+ bytes = _ArrayClipCount(lowerIndx, upperIndx, array);
+ bytes += ARR_OVERHEAD(n);
+ }
+ newArr = (ArrayType *) palloc(bytes);
+ memmove(newArr, array, sizeof(ArrayType));
+ memmove(newArr, &bytes, sizeof(int));
+ memmove(ARR_DIMS(newArr), span, n * sizeof(int));
+ memmove(ARR_LBOUND(newArr), lowerIndx, n * sizeof(int));
+ _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 1);
+ return (Datum) newArr;
}
/*-----------------------------------------------------------------------------
* array_set :
- * This routine sets the value of an array location (specified by an index array)
- * to a new value specified by "dataPtr".
+ * This routine sets the value of an array location (specified by an index array)
+ * to a new value specified by "dataPtr".
* result :
- * returns a pointer to the modified array.
+ * returns a pointer to the modified array.
*-----------------------------------------------------------------------------
*/
-char *
-array_set(ArrayType *array,
- int n,
- int indx[],
- char *dataPtr,
- int reftype,
- int elmlen,
- int arraylen,
- bool *isNull)
+char *
+array_set(ArrayType * array,
+ int n,
+ int indx[],
+ char *dataPtr,
+ int reftype,
+ int elmlen,
+ int arraylen,
+ bool * isNull)
{
- int ndim, *dim, *lb, offset, nbytes;
- char *pos;
-
- if (array == (ArrayType *) NULL)
- RETURN_NULL;
- if (arraylen > 0) {
- /*
- * fixed length arrays -- these are assumed to be 1-d
- */
- if (indx[0]*elmlen > arraylen)
- elog(WARN, "array_ref: array bound exceeded");
- pos = (char *)array + indx[0]*elmlen;
- ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
- return((char *)array);
- }
- dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array);
- ndim = ARR_NDIM(array);
- nbytes = (* (int32 *) array) - ARR_OVERHEAD(ndim);
-
- if (!SanityCheckInput(ndim, n, dim, lb, indx))
- {
- elog(WARN, "array_set: array bound exceeded");
- return((char *)array);
- }
- offset = GetOffset( n, dim, lb, indx);
-
- if (ARR_IS_LO(array)) {
- int fd = 0;
- struct varlena *v;
-
- /* We are assuming fixed element lengths here */
- offset *= elmlen;
+ int ndim,
+ *dim,
+ *lb,
+ offset,
+ nbytes;
+ char *pos;
+
+ if (array == (ArrayType *) NULL)
+ RETURN_NULL;
+ if (arraylen > 0)
+ {
+
+ /*
+ * fixed length arrays -- these are assumed to be 1-d
+ */
+ if (indx[0] * elmlen > arraylen)
+ elog(WARN, "array_ref: array bound exceeded");
+ pos = (char *) array + indx[0] * elmlen;
+ ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
+ return ((char *) array);
+ }
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ndim = ARR_NDIM(array);
+ nbytes = (*(int32 *) array) - ARR_OVERHEAD(ndim);
+
+ if (!SanityCheckInput(ndim, n, dim, lb, indx))
+ {
+ elog(WARN, "array_set: array bound exceeded");
+ return ((char *) array);
+ }
+ offset = GetOffset(n, dim, lb, indx);
+
+ if (ARR_IS_LO(array))
+ {
+ int fd = 0;
+ struct varlena *v;
+
+ /* We are assuming fixed element lengths here */
+ offset *= elmlen;
#ifdef LOARRAY
- char * lo_name;
-
- lo_name = ARR_DATA_PTR(array);
- if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0)
- return((char *)array);
-#endif
- if (lo_lseek(fd, offset, SEEK_SET) < 0)
- return((char *)array);
- v = (struct varlena *) palloc(elmlen + 4);
- VARSIZE (v) = elmlen + 4;
- ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, VARDATA(v));
+ char *lo_name;
+
+ lo_name = ARR_DATA_PTR(array);
+ if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
+ return ((char *) array);
+#endif
+ if (lo_lseek(fd, offset, SEEK_SET) < 0)
+ return ((char *) array);
+ v = (struct varlena *) palloc(elmlen + 4);
+ VARSIZE(v) = elmlen + 4;
+ ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, VARDATA(v));
#ifdef LOARRAY
- n = LOwrite(fd, v);
+ n = LOwrite(fd, v);
#endif
- /* if (n < VARSIZE(v) - 4)
- RETURN_NULL;
- */
- pfree(v);
- lo_close(fd);
- return((char *)array);
- }
- if (elmlen > 0) {
- offset = offset * elmlen;
- /* off the end of the array */
- if (nbytes - offset < 1) return((char *)array);
- pos = ARR_DATA_PTR (array) + offset;
- } else {
- ArrayType *newarray;
- char *elt_ptr;
- int oldsize, newsize, oldlen, newlen, lth0, lth1, lth2;
-
- elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
- oldlen = INTALIGN(*(int32 *)elt_ptr);
- newlen = INTALIGN(*(int32 *)dataPtr);
-
- if (oldlen == newlen) {
- /* new element with same size, overwrite old data */
- ArrayCastAndSet(dataPtr, (bool)reftype, elmlen, elt_ptr);
- return((char *)array);
+
+ /*
+ * if (n < VARSIZE(v) - 4) RETURN_NULL;
+ */
+ pfree(v);
+ lo_close(fd);
+ return ((char *) array);
}
+ if (elmlen > 0)
+ {
+ offset = offset * elmlen;
+ /* off the end of the array */
+ if (nbytes - offset < 1)
+ return ((char *) array);
+ pos = ARR_DATA_PTR(array) + offset;
+ }
+ else
+ {
+ ArrayType *newarray;
+ char *elt_ptr;
+ int oldsize,
+ newsize,
+ oldlen,
+ newlen,
+ lth0,
+ lth1,
+ lth2;
+
+ elt_ptr = array_seek(ARR_DATA_PTR(array), -1, offset);
+ oldlen = INTALIGN(*(int32 *) elt_ptr);
+ newlen = INTALIGN(*(int32 *) dataPtr);
+
+ if (oldlen == newlen)
+ {
+ /* new element with same size, overwrite old data */
+ ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, elt_ptr);
+ return ((char *) array);
+ }
+
+ /* new element with different size, reallocate the array */
+ oldsize = array->size;
+ lth0 = ARR_OVERHEAD(n);
+ lth1 = (int) (elt_ptr - ARR_DATA_PTR(array));
+ lth2 = (int) (oldsize - lth0 - lth1 - oldlen);
+ newsize = lth0 + lth1 + newlen + lth2;
+
+ newarray = (ArrayType *) palloc(newsize);
+ memmove((char *) newarray, (char *) array, lth0 + lth1);
+ newarray->size = newsize;
+ newlen = ArrayCastAndSet(dataPtr, (bool) reftype, elmlen,
+ (char *) newarray + lth0 + lth1);
+ memmove((char *) newarray + lth0 + lth1 + newlen,
+ (char *) array + lth0 + lth1 + oldlen, lth2);
- /* new element with different size, reallocate the array */
- oldsize = array->size;
- lth0 = ARR_OVERHEAD(n);
- lth1 = (int)(elt_ptr - ARR_DATA_PTR(array));
- lth2 = (int)(oldsize - lth0 - lth1 - oldlen);
- newsize = lth0 + lth1 + newlen + lth2;
-
- newarray = (ArrayType *)palloc(newsize);
- memmove((char *)newarray, (char *)array, lth0+lth1);
- newarray->size = newsize;
- newlen = ArrayCastAndSet(dataPtr, (bool)reftype, elmlen,
- (char *)newarray+lth0+lth1);
- memmove((char *)newarray+lth0+lth1+newlen,
- (char *)array+lth0+lth1+oldlen, lth2);
-
- /* ??? who should free this storage ??? */
- return((char *)newarray);
- }
- ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
- return((char *)array);
+ /* ??? who should free this storage ??? */
+ return ((char *) newarray);
+ }
+ ArrayCastAndSet(dataPtr, (bool) reftype, elmlen, pos);
+ return ((char *) array);
}
/*----------------------------------------------------------------------------
* array_assgn :
- * This routine sets the value of a range of array locations (specified
- * by upper and lower index values ) to new values passed as
- * another array
+ * This routine sets the value of a range of array locations (specified
+ * by upper and lower index values ) to new values passed as
+ * another array
* result :
- * returns a pointer to the modified array.
+ * returns a pointer to the modified array.
*----------------------------------------------------------------------------
*/
-char *
-array_assgn(ArrayType *array,
- int n,
- int upperIndx[],
- int lowerIndx[],
- ArrayType *newArr,
- int reftype,
- int len,
- bool *isNull)
+char *
+array_assgn(ArrayType * array,
+ int n,
+ int upperIndx[],
+ int lowerIndx[],
+ ArrayType * newArr,
+ int reftype,
+ int len,
+ bool * isNull)
{
- int i, ndim, *dim, *lb;
-
- if (array == (ArrayType *) NULL)
- RETURN_NULL;
- if (len < 0)
- elog(WARN,"array_assgn:updates on arrays of variable length elements not allowed");
-
- dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array);
- ndim = ARR_NDIM(array);
-
- if (!SanityCheckInput(ndim, n, dim, lb, upperIndx) ||
- !SanityCheckInput(ndim, n, dim, lb, lowerIndx)) {
- return((char *)array);
- }
-
- for (i = 0; i < n; i++)
- if (lowerIndx[i] > upperIndx[i])
- elog(WARN, "lowerIndex larger than upperIndx");
-
- if (ARR_IS_LO(array)) {
- int fd = 0, newfd = 0;
-
+ int i,
+ ndim,
+ *dim,
+ *lb;
+
+ if (array == (ArrayType *) NULL)
+ RETURN_NULL;
+ if (len < 0)
+ elog(WARN, "array_assgn:updates on arrays of variable length elements not allowed");
+
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ndim = ARR_NDIM(array);
+
+ if (!SanityCheckInput(ndim, n, dim, lb, upperIndx) ||
+ !SanityCheckInput(ndim, n, dim, lb, lowerIndx))
+ {
+ return ((char *) array);
+ }
+
+ for (i = 0; i < n; i++)
+ if (lowerIndx[i] > upperIndx[i])
+ elog(WARN, "lowerIndex larger than upperIndx");
+
+ if (ARR_IS_LO(array))
+ {
+ int fd = 0,
+ newfd = 0;
+
#ifdef LOARRAY
- char * lo_name;
+ char *lo_name;
- lo_name = (char *)ARR_DATA_PTR(array);
- if ((fd = LOopen(lo_name, ARR_IS_INV(array)?INV_WRITE:O_WRONLY)) < 0)
- return((char *)array);
+ lo_name = (char *) ARR_DATA_PTR(array);
+ if ((fd = LOopen(lo_name, ARR_IS_INV(array) ? INV_WRITE : O_WRONLY)) < 0)
+ return ((char *) array);
#endif
- if (ARR_IS_LO(newArr)) {
+ if (ARR_IS_LO(newArr))
+ {
#ifdef LOARRAY
- lo_name = (char *)ARR_DATA_PTR(newArr);
- if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr)?INV_READ:O_RDONLY)) < 0)
- return((char *)array);
+ lo_name = (char *) ARR_DATA_PTR(newArr);
+ if ((newfd = LOopen(lo_name, ARR_IS_INV(newArr) ? INV_READ : O_RDONLY)) < 0)
+ return ((char *) array);
#endif
- _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
- lo_close(newfd);
- } else {
- _LOArrayRange(lowerIndx, upperIndx, len, fd, (int)ARR_DATA_PTR(newArr),
- array, 0, isNull);
- }
- lo_close(fd);
- return ((char *) array);
- }
- _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0);
- return (char *) array;
+ _LOArrayRange(lowerIndx, upperIndx, len, fd, newfd, array, 1, isNull);
+ lo_close(newfd);
+ }
+ else
+ {
+ _LOArrayRange(lowerIndx, upperIndx, len, fd, (int) ARR_DATA_PTR(newArr),
+ array, 0, isNull);
+ }
+ lo_close(fd);
+ return ((char *) array);
+ }
+ _ArrayRange(lowerIndx, upperIndx, len, ARR_DATA_PTR(newArr), array, 0);
+ return (char *) array;
}
/*-----------------------------------------------------------------------------
* array_eq :
- * compares two arrays for equality
+ * compares two arrays for equality
* result :
- * returns 1 if the arrays are equal, 0 otherwise.
+ * returns 1 if the arrays are equal, 0 otherwise.
*-----------------------------------------------------------------------------
*/
int
-array_eq (ArrayType *array1, ArrayType *array2)
+array_eq(ArrayType * array1, ArrayType * array2)
{
- if ((array1 == NULL) || (array2 == NULL))
- return(0);
- if (*(int *)array1 != *(int *)array2)
- return (0);
- if (memcmp(array1, array2, *(int *)array1))
- return(0);
- return(1);
+ if ((array1 == NULL) || (array2 == NULL))
+ return (0);
+ if (*(int *) array1 != *(int *) array2)
+ return (0);
+ if (memcmp(array1, array2, *(int *) array1))
+ return (0);
+ return (1);
}
/***************************************************************************/
-/******************| Support Routines |*****************/
+/******************| Support Routines |*****************/
/***************************************************************************/
static void
system_cache_lookup(Oid element_type,
- bool input,
- int *typlen,
- bool *typbyval,
- char *typdelim,
- Oid *typelem,
- Oid *proc,
- char *typalign)
+ bool input,
+ int *typlen,
+ bool * typbyval,
+ char *typdelim,
+ Oid * typelem,
+ Oid * proc,
+ char *typalign)
{
- HeapTuple typeTuple;
- TypeTupleForm typeStruct;
-
- typeTuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(element_type),
- 0,0,0);
-
- if (!HeapTupleIsValid(typeTuple)) {
- elog(WARN, "array_out: Cache lookup failed for type %d\n",
- element_type);
- return;
- }
- typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
- *typlen = typeStruct->typlen;
- *typbyval = typeStruct->typbyval;
- *typdelim = typeStruct->typdelim;
- *typelem = typeStruct->typelem;
- *typalign = typeStruct->typalign;
- if (input) {
- *proc = typeStruct->typinput;
- } else {
- *proc = typeStruct->typoutput;
- }
+ HeapTuple typeTuple;
+ TypeTupleForm typeStruct;
+
+ typeTuple = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(element_type),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(typeTuple))
+ {
+ elog(WARN, "array_out: Cache lookup failed for type %d\n",
+ element_type);
+ return;
+ }
+ typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
+ *typlen = typeStruct->typlen;
+ *typbyval = typeStruct->typbyval;
+ *typdelim = typeStruct->typdelim;
+ *typelem = typeStruct->typelem;
+ *typalign = typeStruct->typalign;
+ if (input)
+ {
+ *proc = typeStruct->typinput;
+ }
+ else
+ {
+ *proc = typeStruct->typoutput;
+ }
}
-static Datum
+static Datum
_ArrayCast(char *value, bool byval, int len)
{
- if (byval) {
- switch (len) {
- case 1:
- return((Datum) * value);
- case 2:
- return((Datum) * (int16 *) value);
- case 3:
- case 4:
- return((Datum) * (int32 *) value);
- default:
- elog(WARN, "array_ref: byval and elt len > 4!");
- break;
- }
- } else {
- return (Datum) value;
- }
- return 0;
+ if (byval)
+ {
+ switch (len)
+ {
+ case 1:
+ return ((Datum) * value);
+ case 2:
+ return ((Datum) * (int16 *) value);
+ case 3:
+ case 4:
+ return ((Datum) * (int32 *) value);
+ default:
+ elog(WARN, "array_ref: byval and elt len > 4!");
+ break;
+ }
+ }
+ else
+ {
+ return (Datum) value;
+ }
+ return 0;
}
static int
ArrayCastAndSet(char *src,
- bool typbyval,
- int typlen,
- char *dest)
+ bool typbyval,
+ int typlen,
+ char *dest)
{
- int inc;
-
- if (typlen > 0) {
- if (typbyval) {
- switch(typlen) {
- case 1:
- *dest = DatumGetChar(src);
- break;
- case 2:
- * (int16 *) dest = DatumGetInt16(src);
- break;
- case 4:
- * (int32 *) dest = (int32)src;
- break;
- }
- } else {
- memmove(dest, src, typlen);
- }
- inc = typlen;
- } else {
- memmove(dest, src, *(int32 *)src);
- inc = (INTALIGN(* (int32 *) src));
- }
- return(inc);
-}
+ int inc;
+
+ if (typlen > 0)
+ {
+ if (typbyval)
+ {
+ switch (typlen)
+ {
+ case 1:
+ *dest = DatumGetChar(src);
+ break;
+ case 2:
+ *(int16 *) dest = DatumGetInt16(src);
+ break;
+ case 4:
+ *(int32 *) dest = (int32) src;
+ break;
+ }
+ }
+ else
+ {
+ memmove(dest, src, typlen);
+ }
+ inc = typlen;
+ }
+ else
+ {
+ memmove(dest, src, *(int32 *) src);
+ inc = (INTALIGN(*(int32 *) src));
+ }
+ return (inc);
+}
#ifdef LOARRAY
-static char *
+static char *
_AdvanceBy1word(char *str, char **word)
{
- char *retstr, *space;
-
- *word = NULL;
- if (str == NULL) return str;
- while (isspace(*str)) str++;
- *word = str;
- if ((space = (char *)strchr(str, ' ')) != (char *) NULL) {
- retstr = space + 1;
- *space = '\0';
- }
- else
- retstr = NULL;
- return retstr;
+ char *retstr,
+ *space;
+
+ *word = NULL;
+ if (str == NULL)
+ return str;
+ while (isspace(*str))
+ str++;
+ *word = str;
+ if ((space = (char *) strchr(str, ' ')) != (char *) NULL)
+ {
+ retstr = space + 1;
+ *space = '\0';
+ }
+ else
+ retstr = NULL;
+ return retstr;
}
+
#endif
static int
SanityCheckInput(int ndim, int n, int dim[], int lb[], int indx[])
{
- int i;
- /* Do Sanity check on input */
- if (n != ndim) return 0;
- for (i = 0; i < ndim; i++)
- if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
- return 0;
- return 1;
+ int i;
+
+ /* Do Sanity check on input */
+ if (n != ndim)
+ return 0;
+ for (i = 0; i < ndim; i++)
+ if ((lb[i] > indx[i]) || (indx[i] >= (dim[i] + lb[i])))
+ return 0;
+ return 1;
}
static void
_ArrayRange(int st[],
- int endp[],
- int bsize,
- char *destPtr,
- ArrayType *array,
- int from)
+ int endp[],
+ int bsize,
+ char *destPtr,
+ ArrayType * array,
+ int from)
{
- int n, *dim, *lb, st_pos, prod[MAXDIM];
- int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
- int i, j, inc;
- char *srcPtr;
-
- n = ARR_NDIM(array); dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array); srcPtr = ARR_DATA_PTR(array);
- for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
- mda_get_prod(n, dim, prod);
- st_pos = tuple2linear(n, st, prod);
- srcPtr = array_seek(srcPtr, bsize, st_pos);
- mda_get_range(n, span, st, endp);
- mda_get_offset_values(n, dist, prod, span);
- for (i=0; i < n; indx[i++]=0);
- i = j = n-1; inc = bsize;
- do {
- srcPtr = array_seek(srcPtr, bsize, dist[j]);
- if (from)
- inc = array_read(destPtr, bsize, 1, srcPtr);
- else
- inc = array_read(srcPtr, bsize, 1, destPtr);
- destPtr += inc; srcPtr += inc;
- } while ((j = next_tuple(i+1, indx, span)) != -1);
+ int n,
+ *dim,
+ *lb,
+ st_pos,
+ prod[MAXDIM];
+ int span[MAXDIM],
+ dist[MAXDIM],
+ indx[MAXDIM];
+ int i,
+ j,
+ inc;
+ char *srcPtr;
+
+ n = ARR_NDIM(array);
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ srcPtr = ARR_DATA_PTR(array);
+ for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
+ mda_get_prod(n, dim, prod);
+ st_pos = tuple2linear(n, st, prod);
+ srcPtr = array_seek(srcPtr, bsize, st_pos);
+ mda_get_range(n, span, st, endp);
+ mda_get_offset_values(n, dist, prod, span);
+ for (i = 0; i < n; indx[i++] = 0);
+ i = j = n - 1;
+ inc = bsize;
+ do
+ {
+ srcPtr = array_seek(srcPtr, bsize, dist[j]);
+ if (from)
+ inc = array_read(destPtr, bsize, 1, srcPtr);
+ else
+ inc = array_read(srcPtr, bsize, 1, destPtr);
+ destPtr += inc;
+ srcPtr += inc;
+ } while ((j = next_tuple(i + 1, indx, span)) != -1);
}
static int
-_ArrayClipCount(int stI[], int endpI[], ArrayType *array)
+_ArrayClipCount(int stI[], int endpI[], ArrayType * array)
{
- int n, *dim, *lb, st_pos, prod[MAXDIM];
- int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
- int i, j, inc, st[MAXDIM], endp[MAXDIM];
- int count = 0;
- char *ptr;
-
- n = ARR_NDIM(array); dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array); ptr = ARR_DATA_PTR(array);
- for (i = 0; i < n; st[i] = stI[i]-lb[i], endp[i]=endpI[i]-lb[i], i++);
- mda_get_prod(n, dim, prod);
- st_pos = tuple2linear(n, st, prod);
- ptr = array_seek(ptr, -1, st_pos);
- mda_get_range(n, span, st, endp);
- mda_get_offset_values(n, dist, prod, span);
- for (i=0; i < n; indx[i++]=0);
- i = j = n-1;
- do {
- ptr = array_seek(ptr, -1, dist[j]);
- inc = INTALIGN(* (int32 *) ptr);
- ptr += inc; count += inc;
- } while ((j = next_tuple(i+1, indx, span)) != -1);
- return count;
+ int n,
+ *dim,
+ *lb,
+ st_pos,
+ prod[MAXDIM];
+ int span[MAXDIM],
+ dist[MAXDIM],
+ indx[MAXDIM];
+ int i,
+ j,
+ inc,
+ st[MAXDIM],
+ endp[MAXDIM];
+ int count = 0;
+ char *ptr;
+
+ n = ARR_NDIM(array);
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ ptr = ARR_DATA_PTR(array);
+ for (i = 0; i < n; st[i] = stI[i] - lb[i], endp[i] = endpI[i] - lb[i], i++);
+ mda_get_prod(n, dim, prod);
+ st_pos = tuple2linear(n, st, prod);
+ ptr = array_seek(ptr, -1, st_pos);
+ mda_get_range(n, span, st, endp);
+ mda_get_offset_values(n, dist, prod, span);
+ for (i = 0; i < n; indx[i++] = 0);
+ i = j = n - 1;
+ do
+ {
+ ptr = array_seek(ptr, -1, dist[j]);
+ inc = INTALIGN(*(int32 *) ptr);
+ ptr += inc;
+ count += inc;
+ } while ((j = next_tuple(i + 1, indx, span)) != -1);
+ return count;
}
-static char *
+static char *
array_seek(char *ptr, int eltsize, int nitems)
{
- int i;
-
- if (eltsize > 0)
- return(ptr + eltsize*nitems);
- for (i = 0; i < nitems; i++)
- ptr += INTALIGN(* (int32 *) ptr);
- return(ptr);
+ int i;
+
+ if (eltsize > 0)
+ return (ptr + eltsize * nitems);
+ for (i = 0; i < nitems; i++)
+ ptr += INTALIGN(*(int32 *) ptr);
+ return (ptr);
}
static int
array_read(char *destptr, int eltsize, int nitems, char *srcptr)
{
- int i, inc, tmp;
-
- if (eltsize > 0) {
- memmove(destptr, srcptr, eltsize*nitems);
- return(eltsize*nitems);
- }
- for (i = inc = 0; i < nitems; i++) {
- tmp = (INTALIGN(* (int32 *) srcptr));
- memmove(destptr, srcptr, tmp);
- srcptr += tmp;
- destptr += tmp;
- inc += tmp;
- }
- return(inc);
+ int i,
+ inc,
+ tmp;
+
+ if (eltsize > 0)
+ {
+ memmove(destptr, srcptr, eltsize * nitems);
+ return (eltsize * nitems);
+ }
+ for (i = inc = 0; i < nitems; i++)
+ {
+ tmp = (INTALIGN(*(int32 *) srcptr));
+ memmove(destptr, srcptr, tmp);
+ srcptr += tmp;
+ destptr += tmp;
+ inc += tmp;
+ }
+ return (inc);
}
static void
_LOArrayRange(int st[],
- int endp[],
- int bsize,
- int srcfd,
- int destfd,
- ArrayType *array,
- int isSrcLO,
- bool *isNull)
+ int endp[],
+ int bsize,
+ int srcfd,
+ int destfd,
+ ArrayType * array,
+ int isSrcLO,
+ bool * isNull)
{
- int n, *dim, st_pos, prod[MAXDIM];
- int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
- int i, j, inc, tmp, *lb, offset;
-
- n = ARR_NDIM(array); dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array);
- for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
-
- mda_get_prod(n, dim, prod);
- st_pos = tuple2linear(n, st, prod);
- offset = st_pos*bsize;
- if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
- return;
- mda_get_range(n, span, st, endp);
- mda_get_offset_values(n, dist, prod, span);
- for (i=0; i < n; indx[i++]=0);
- for (i = n-1, inc = bsize; i >= 0; inc *= span[i--])
- if (dist[i])
- break;
- j = n-1;
- do {
- offset += (dist[j]*bsize);
- if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
- return;
- tmp = _LOtransfer((char**)&srcfd, inc, 1, (char**)&destfd, isSrcLO, 1);
- if ( tmp < inc )
- return;
- offset += inc;
- } while ((j = next_tuple(i+1, indx, span)) != -1);
+ int n,
+ *dim,
+ st_pos,
+ prod[MAXDIM];
+ int span[MAXDIM],
+ dist[MAXDIM],
+ indx[MAXDIM];
+ int i,
+ j,
+ inc,
+ tmp,
+ *lb,
+ offset;
+
+ n = ARR_NDIM(array);
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
+
+ mda_get_prod(n, dim, prod);
+ st_pos = tuple2linear(n, st, prod);
+ offset = st_pos * bsize;
+ if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
+ return;
+ mda_get_range(n, span, st, endp);
+ mda_get_offset_values(n, dist, prod, span);
+ for (i = 0; i < n; indx[i++] = 0);
+ for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
+ if (dist[i])
+ break;
+ j = n - 1;
+ do
+ {
+ offset += (dist[j] * bsize);
+ if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
+ return;
+ tmp = _LOtransfer((char **) &srcfd, inc, 1, (char **) &destfd, isSrcLO, 1);
+ if (tmp < inc)
+ return;
+ offset += inc;
+ } while ((j = next_tuple(i + 1, indx, span)) != -1);
}
static void
-_ReadArray (int st[],
- int endp[],
- int bsize,
- int srcfd,
- int destfd,
- ArrayType *array,
- int isDestLO,
- bool *isNull)
+_ReadArray(int st[],
+ int endp[],
+ int bsize,
+ int srcfd,
+ int destfd,
+ ArrayType * array,
+ int isDestLO,
+ bool * isNull)
{
- int n, *dim, st_pos, prod[MAXDIM];
- int span[MAXDIM], dist[MAXDIM], indx[MAXDIM];
- int i, j, inc, tmp, *lb, offset;
-
- n = ARR_NDIM(array); dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array);
- for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
-
- mda_get_prod(n, dim, prod);
- st_pos = tuple2linear(n, st, prod);
- offset = st_pos*bsize;
- if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
- return;
- mda_get_range(n, span, st, endp);
- mda_get_offset_values(n, dist, prod, span);
- for (i=0; i < n; indx[i++]=0);
- for (i = n-1, inc = bsize; i >= 0; inc *= span[i--])
- if (dist[i])
- break;
- j = n-1;
- do {
- offset += (dist[j]*bsize);
- if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
- return;
- tmp = _LOtransfer((char**)&destfd, inc, 1, (char**)&srcfd, 1, isDestLO);
- if ( tmp < inc )
- return;
- offset += inc;
- } while ((j = next_tuple(i+1, indx, span)) != -1);
+ int n,
+ *dim,
+ st_pos,
+ prod[MAXDIM];
+ int span[MAXDIM],
+ dist[MAXDIM],
+ indx[MAXDIM];
+ int i,
+ j,
+ inc,
+ tmp,
+ *lb,
+ offset;
+
+ n = ARR_NDIM(array);
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++);
+
+ mda_get_prod(n, dim, prod);
+ st_pos = tuple2linear(n, st, prod);
+ offset = st_pos * bsize;
+ if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
+ return;
+ mda_get_range(n, span, st, endp);
+ mda_get_offset_values(n, dist, prod, span);
+ for (i = 0; i < n; indx[i++] = 0);
+ for (i = n - 1, inc = bsize; i >= 0; inc *= span[i--])
+ if (dist[i])
+ break;
+ j = n - 1;
+ do
+ {
+ offset += (dist[j] * bsize);
+ if (lo_lseek(srcfd, offset, SEEK_SET) < 0)
+ return;
+ tmp = _LOtransfer((char **) &destfd, inc, 1, (char **) &srcfd, 1, isDestLO);
+ if (tmp < inc)
+ return;
+ offset += inc;
+ } while ((j = next_tuple(i + 1, indx, span)) != -1);
}
int
_LOtransfer(char **destfd,
- int size,
- int nitems,
- char **srcfd,
- int isSrcLO,
- int isDestLO)
+ int size,
+ int nitems,
+ char **srcfd,
+ int isSrcLO,
+ int isDestLO)
{
#define MAX_READ (512 * 1024)
#define min(a, b) (a < b ? a : b)
- struct varlena *v = NULL;
- int tmp, inc, resid;
-
- inc = nitems*size;
- if (isSrcLO && isDestLO && inc > 0)
- for (tmp = 0, resid = inc;
- resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc) {
+ struct varlena *v = NULL;
+ int tmp,
+ inc,
+ resid;
+
+ inc = nitems * size;
+ if (isSrcLO && isDestLO && inc > 0)
+ for (tmp = 0, resid = inc;
+ resid > 0 && (inc = min(resid, MAX_READ)) > 0; resid -= inc)
+ {
#ifdef LOARRAY
- v = (struct varlena *) LOread((int) *srcfd, inc);
- if (VARSIZE(v) - 4 < inc)
- {pfree(v); return(-1);}
- tmp += LOwrite((int) *destfd, v);
+ v = (struct varlena *) LOread((int) *srcfd, inc);
+ if (VARSIZE(v) - 4 < inc)
+ {
+ pfree(v);
+ return (-1);
+ }
+ tmp += LOwrite((int) *destfd, v);
#endif
- pfree(v);
-
- }
- else if (!isSrcLO && isDestLO) {
- tmp = lo_write((int) *destfd, *srcfd, inc);
- *srcfd = *srcfd + tmp;
- }
- else if (isSrcLO && !isDestLO) {
- tmp = lo_read((int) *srcfd, *destfd, inc);
- *destfd = *destfd + tmp;
- }
- else {
- memmove(*destfd, *srcfd, inc);
- tmp = inc;
- *srcfd += inc;
- *destfd += inc;
- }
- return(tmp);
+ pfree(v);
+
+ }
+ else if (!isSrcLO && isDestLO)
+ {
+ tmp = lo_write((int) *destfd, *srcfd, inc);
+ *srcfd = *srcfd + tmp;
+ }
+ else if (isSrcLO && !isDestLO)
+ {
+ tmp = lo_read((int) *srcfd, *destfd, inc);
+ *destfd = *destfd + tmp;
+ }
+ else
+ {
+ memmove(*destfd, *srcfd, inc);
+ tmp = inc;
+ *srcfd += inc;
+ *destfd += inc;
+ }
+ return (tmp);
#undef MAX_READ
}
-char *
+char *
_array_newLO(int *fd, int flag)
{
- char *p;
- char saveName[NAME_LEN];
-
- p = (char *) palloc(NAME_LEN);
- sprintf(p, "/Arry.%d", newoid());
- strcpy (saveName, p);
+ char *p;
+ char saveName[NAME_LEN];
+
+ p = (char *) palloc(NAME_LEN);
+ sprintf(p, "/Arry.%d", newoid());
+ strcpy(saveName, p);
#ifdef LOARRAY
- if ( (*fd = LOcreat (saveName, 0600, flag)) < 0)
- elog(WARN, "Large object create failed");
+ if ((*fd = LOcreat(saveName, 0600, flag)) < 0)
+ elog(WARN, "Large object create failed");
#endif
- return (p);
+ return (p);
}
-
diff --git a/src/backend/utils/adt/arrayutils.c b/src/backend/utils/adt/arrayutils.c
index fce0b0ddd57..09a58d46e2c 100644
--- a/src/backend/utils/adt/arrayutils.c
+++ b/src/backend/utils/adt/arrayutils.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* arrayutils.c--
- * This file contains some support routines required for array functions.
+ * This file contains some support routines required for array functions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayutils.c,v 1.3 1996/11/10 03:03:03 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayutils.c,v 1.4 1997/09/07 04:49:57 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,94 +20,109 @@
int
GetOffset(int n, int dim[], int lb[], int indx[])
-{
- int i, scale, offset;
- for (i = n-1, scale = 1, offset = 0; i >= 0; scale*=dim[i--])
- offset += (indx[i] - lb[i])*scale;
- return offset ;
+{
+ int i,
+ scale,
+ offset;
+
+ for (i = n - 1, scale = 1, offset = 0; i >= 0; scale *= dim[i--])
+ offset += (indx[i] - lb[i]) * scale;
+ return offset;
}
int
getNitems(int n, int a[])
-{
- int i, ret;
- for (i = 0, ret = 1; i < n; ret *= a[i++]);
- if (n == 0) ret = 0;
- return ret;
+{
+ int i,
+ ret;
+
+ for (i = 0, ret = 1; i < n; ret *= a[i++]);
+ if (n == 0)
+ ret = 0;
+ return ret;
}
int
compute_size(int st[], int endp[], int n, int base)
{
- int i, ret;
- for (i = 0, ret = base; i < n; i++)
- ret *= (endp[i] - st[i] + 1);
- return ret;
+ int i,
+ ret;
+
+ for (i = 0, ret = base; i < n; i++)
+ ret *= (endp[i] - st[i] + 1);
+ return ret;
}
void
mda_get_offset_values(int n, int dist[], int PC[], int span[])
-{
- int i, j;
- for (j = n-2, dist[n-1]=0; j >= 0; j--)
- for (i = j+1, dist[j] = PC[j]-1; i < n;
- dist[j] -= (span[i] - 1)*PC[i], i++);
-}
+{
+ int i,
+ j;
+
+ for (j = n - 2, dist[n - 1] = 0; j >= 0; j--)
+ for (i = j + 1, dist[j] = PC[j] - 1; i < n;
+ dist[j] -= (span[i] - 1) * PC[i], i++);
+}
void
mda_get_range(int n, int span[], int st[], int endp[])
-{
- int i;
- for (i= 0; i < n; i++)
- span[i] = endp[i] - st[i] + 1;
-}
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ span[i] = endp[i] - st[i] + 1;
+}
void
mda_get_prod(int n, int range[], int P[])
-{
- int i;
- for (i= n-2, P[n-1] = 1; i >= 0; i--)
- P[i] = P[i+1] * range[i + 1];
-}
+{
+ int i;
+
+ for (i = n - 2, P[n - 1] = 1; i >= 0; i--)
+ P[i] = P[i + 1] * range[i + 1];
+}
int
tuple2linear(int n, int tup[], int scale[])
{
- int i, lin;
- for (i= lin = 0; i < n; i++)
- lin += tup[i]*scale[i];
- return lin;
-}
+ int i,
+ lin;
+
+ for (i = lin = 0; i < n; i++)
+ lin += tup[i] * scale[i];
+ return lin;
+}
void
array2chunk_coord(int n, int C[], int a_coord[], int c_coord[])
{
- int i;
- for (i= 0; i < n; i++)
- c_coord[i] = a_coord[i]/C[i];
+ int i;
+
+ for (i = 0; i < n; i++)
+ c_coord[i] = a_coord[i] / C[i];
}
/*-----------------------------------------------------------------------------
generates the tuple that is lexicographically one greater than the current
n-tuple in "curr", with the restriction that the i-th element of "curr" is
less than the i-th element of "span".
- RETURNS 0 if no next tuple exists
+ RETURNS 0 if no next tuple exists
1 otherwise
-----------------------------------------------------------------------------*/
int
next_tuple(int n, int curr[], int span[])
{
- int i;
-
- if (!n) return(-1);
- curr[n-1] = (curr[n-1]+1)%span[n-1];
- for (i = n-1; i*(!curr[i]); i--)
- curr[i-1] = (curr[i-1]+1)%span[i-1];
-
- if (i)
- return(i);
- if (curr[0])
- return(0);
- return(-1);
-}
+ int i;
+ if (!n)
+ return (-1);
+ curr[n - 1] = (curr[n - 1] + 1) % span[n - 1];
+ for (i = n - 1; i * (!curr[i]); i--)
+ curr[i - 1] = (curr[i - 1] + 1) % span[i - 1];
+
+ if (i)
+ return (i);
+ if (curr[0])
+ return (0);
+ return (-1);
+}
diff --git a/src/backend/utils/adt/bool.c b/src/backend/utils/adt/bool.c
index cb9163f020f..d02661efa67 100644
--- a/src/backend/utils/adt/bool.c
+++ b/src/backend/utils/adt/bool.c
@@ -1,74 +1,74 @@
/*-------------------------------------------------------------------------
*
* bool.c--
- * Functions for the built-in type "bool".
+ * Functions for the built-in type "bool".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/bool.c,v 1.4 1997/04/27 19:20:07 thomas Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/bool.c,v 1.5 1997/09/07 04:49:58 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "utils/builtins.h" /* where the declarations go */
+#include "utils/builtins.h" /* where the declarations go */
#include "utils/palloc.h"
-/*****************************************************************************
- * USER I/O ROUTINES *
+/*****************************************************************************
+ * USER I/O ROUTINES *
*****************************************************************************/
/*
- * boolin - converts "t" or "f" to 1 or 0
+ * boolin - converts "t" or "f" to 1 or 0
*/
bool
boolin(char *b)
{
- if (b == NULL)
- elog(WARN, "Bad input string for type bool");
- return((bool) (*b == 't') || (*b == 'T'));
+ if (b == NULL)
+ elog(WARN, "Bad input string for type bool");
+ return ((bool) (*b == 't') || (*b == 'T'));
}
/*
- * boolout - converts 1 or 0 to "t" or "f"
+ * boolout - converts 1 or 0 to "t" or "f"
*/
-char *
+char *
boolout(long b)
{
- char *result = (char *) palloc(2);
-
- *result = (b) ? 't' : 'f';
- result[1] = '\0';
- return(result);
+ char *result = (char *) palloc(2);
+
+ *result = (b) ? 't' : 'f';
+ result[1] = '\0';
+ return (result);
}
-/*****************************************************************************
- * PUBLIC ROUTINES *
+/*****************************************************************************
+ * PUBLIC ROUTINES *
*****************************************************************************/
bool
-booleq(int8 arg1, int8 arg2)
-{
- return(arg1 == arg2);
+booleq(int8 arg1, int8 arg2)
+{
+ return (arg1 == arg2);
}
bool
-boolne(int8 arg1, int8 arg2)
+boolne(int8 arg1, int8 arg2)
{
- return(arg1 != arg2);
+ return (arg1 != arg2);
}
bool
-boollt(int8 arg1, int8 arg2)
-{
- return(arg1 < arg2);
+boollt(int8 arg1, int8 arg2)
+{
+ return (arg1 < arg2);
}
bool
-boolgt(int8 arg1, int8 arg2)
-{
- return(arg1 > arg2);
+boolgt(int8 arg1, int8 arg2)
+{
+ return (arg1 > arg2);
}
diff --git a/src/backend/utils/adt/cash.c b/src/backend/utils/adt/cash.c
index 1cadb742e62..763ac5856ce 100644
--- a/src/backend/utils/adt/cash.c
+++ b/src/backend/utils/adt/cash.c
@@ -8,8 +8,8 @@
* A slightly modified version of this file and a discussion of the
* workings can be found in the book "Software Solutions in C" by
* Dale Schumacher, Academic Press, ISBN: 0-12-632360-7.
- *
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.9 1997/08/22 07:12:52 momjian Exp $
+ *
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/cash.c,v 1.10 1997/09/07 04:49:59 momjian Exp $
*/
#include <stdio.h>
@@ -26,332 +26,363 @@
static const char *num_word(Cash value);
/* when we go to 64 bit values we will have to modify this */
-#define CASH_BUFSZ 24
+#define CASH_BUFSZ 24
-#define TERMINATOR (CASH_BUFSZ - 1)
-#define LAST_PAREN (TERMINATOR - 1)
-#define LAST_DIGIT (LAST_PAREN - 1)
+#define TERMINATOR (CASH_BUFSZ - 1)
+#define LAST_PAREN (TERMINATOR - 1)
+#define LAST_DIGIT (LAST_PAREN - 1)
#ifdef USE_LOCALE
static struct lconv *lconv = NULL;
+
#endif
/* cash_in()
* Convert a string to a cash data type.
* Format is [$]###[,]###[.##]
* Examples: 123.45 $123.45 $123,456.78
- *
+ *
* This is currently implemented as a 32-bit integer.
* XXX HACK It looks as though some of the symbols for
- * monetary values returned by localeconv() can be multiple
- * bytes/characters. This code assumes one byte only. - tgl 97/04/14
+ * monetary values returned by localeconv() can be multiple
+ * bytes/characters. This code assumes one byte only. - tgl 97/04/14
*/
-Cash *
+Cash *
cash_in(const char *str)
{
- Cash *result;
-
- Cash value = 0;
- Cash dec = 0;
- Cash sgn = 1;
- int seen_dot = 0;
- const char *s = str;
- int fpoint;
- char dsymbol, ssymbol, psymbol, nsymbol, csymbol;
+ Cash *result;
+
+ Cash value = 0;
+ Cash dec = 0;
+ Cash sgn = 1;
+ int seen_dot = 0;
+ const char *s = str;
+ int fpoint;
+ char dsymbol,
+ ssymbol,
+ psymbol,
+ nsymbol,
+ csymbol;
#ifdef USE_LOCALE
- if (lconv == NULL) lconv = localeconv();
-
- /* frac_digits in the C locale seems to return CHAR_MAX */
- /* best guess is 2 in this case I think */
- fpoint = ((lconv->frac_digits != CHAR_MAX)? lconv->frac_digits: 2); /* int_frac_digits? */
-
- dsymbol = *lconv->mon_decimal_point;
- ssymbol = *lconv->mon_thousands_sep;
- csymbol = *lconv->currency_symbol;
- psymbol = *lconv->positive_sign;
- nsymbol = *lconv->negative_sign;
+ if (lconv == NULL)
+ lconv = localeconv();
+
+ /* frac_digits in the C locale seems to return CHAR_MAX */
+ /* best guess is 2 in this case I think */
+ fpoint = ((lconv->frac_digits != CHAR_MAX) ? lconv->frac_digits : 2); /* int_frac_digits? */
+
+ dsymbol = *lconv->mon_decimal_point;
+ ssymbol = *lconv->mon_thousands_sep;
+ csymbol = *lconv->currency_symbol;
+ psymbol = *lconv->positive_sign;
+ nsymbol = *lconv->negative_sign;
#else
- fpoint = 2;
- dsymbol = '.';
- ssymbol = ',';
- csymbol = '$';
- psymbol = '+';
- nsymbol = '-';
+ fpoint = 2;
+ dsymbol = '.';
+ ssymbol = ',';
+ csymbol = '$';
+ psymbol = '+';
+ nsymbol = '-';
#endif
- /* we need to add all sorts of checking here. For now just */
- /* strip all leading whitespace and any leading dollar sign */
- while (isspace(*s) || *s == csymbol) s++;
-
- /* a leading minus or paren signifies a negative number */
- /* again, better heuristics needed */
- if (*s == nsymbol || *s == '(') {
- sgn = -1;
- s++;
-
- } else if (*s == psymbol) {
- s++;
- }
-
- while (isspace(*s) || *s == csymbol) s++;
-
- for (; ; s++) {
- /* we look for digits as int4 as we have less */
- /* than the required number of decimal places */
- if (isdigit(*s) && dec < fpoint) {
- value = (value * 10) + *s - '0';
-
- if (seen_dot)
- dec++;
-
- /* decimal point? then start counting fractions... */
- } else if (*s == dsymbol && !seen_dot) {
- seen_dot = 1;
+ /* we need to add all sorts of checking here. For now just */
+ /* strip all leading whitespace and any leading dollar sign */
+ while (isspace(*s) || *s == csymbol)
+ s++;
- /* "thousands" separator? then skip... */
- } else if (*s == ssymbol) {
+ /* a leading minus or paren signifies a negative number */
+ /* again, better heuristics needed */
+ if (*s == nsymbol || *s == '(')
+ {
+ sgn = -1;
+ s++;
- } else {
- /* round off */
- if (isdigit(*s) && *s >= '5')
- value++;
-
- /* adjust for less than required decimal places */
- for (; dec < fpoint; dec++)
- value *= 10;
+ }
+ else if (*s == psymbol)
+ {
+ s++;
+ }
- break;
+ while (isspace(*s) || *s == csymbol)
+ s++;
+
+ for (;; s++)
+ {
+ /* we look for digits as int4 as we have less */
+ /* than the required number of decimal places */
+ if (isdigit(*s) && dec < fpoint)
+ {
+ value = (value * 10) + *s - '0';
+
+ if (seen_dot)
+ dec++;
+
+ /* decimal point? then start counting fractions... */
+ }
+ else if (*s == dsymbol && !seen_dot)
+ {
+ seen_dot = 1;
+
+ /* "thousands" separator? then skip... */
+ }
+ else if (*s == ssymbol)
+ {
+
+ }
+ else
+ {
+ /* round off */
+ if (isdigit(*s) && *s >= '5')
+ value++;
+
+ /* adjust for less than required decimal places */
+ for (; dec < fpoint; dec++)
+ value *= 10;
+
+ break;
+ }
}
- }
- while (isspace(*s) || *s == '0' || *s == ')') s++;
+ while (isspace(*s) || *s == '0' || *s == ')')
+ s++;
- if (*s != '\0')
- elog(WARN,"Bad money external representation %s",str);
+ if (*s != '\0')
+ elog(WARN, "Bad money external representation %s", str);
- if (!PointerIsValid(result = PALLOCTYPE(Cash)))
- elog(WARN,"Memory allocation failed, can't input cash '%s'",str);
+ if (!PointerIsValid(result = PALLOCTYPE(Cash)))
+ elog(WARN, "Memory allocation failed, can't input cash '%s'", str);
- *result = (value * sgn);
+ *result = (value * sgn);
- return(result);
-} /* cash_in() */
+ return (result);
+} /* cash_in() */
/* cash_out()
* Function to convert cash to a dollars and cents representation.
* XXX HACK This code appears to assume US conventions for
- * positive-valued amounts. - tgl 97/04/14
+ * positive-valued amounts. - tgl 97/04/14
*/
-const char *
-cash_out(Cash *value)
+const char *
+cash_out(Cash * value)
{
- char *result;
- char buf[CASH_BUFSZ];
- int minus = 0;
- int count = LAST_DIGIT;
- int point_pos;
- int comma_position = 0;
- char mon_group, comma, points;
- char csymbol, dsymbol, *nsymbol;
- char convention;
+ char *result;
+ char buf[CASH_BUFSZ];
+ int minus = 0;
+ int count = LAST_DIGIT;
+ int point_pos;
+ int comma_position = 0;
+ char mon_group,
+ comma,
+ points;
+ char csymbol,
+ dsymbol,
+ *nsymbol;
+ char convention;
#ifdef USE_LOCALE
- if (lconv == NULL) lconv = localeconv();
-
- mon_group = *lconv->mon_grouping;
- comma = *lconv->mon_thousands_sep;
- csymbol = *lconv->currency_symbol;
- dsymbol = *lconv->mon_decimal_point;
- nsymbol = lconv->negative_sign;
- /* frac_digits in the C locale seems to return CHAR_MAX */
- /* best guess is 2 in this case I think */
- points = ((lconv->frac_digits != CHAR_MAX)? lconv->frac_digits: 2); /* int_frac_digits? */
- convention = lconv->n_sign_posn;
+ if (lconv == NULL)
+ lconv = localeconv();
+
+ mon_group = *lconv->mon_grouping;
+ comma = *lconv->mon_thousands_sep;
+ csymbol = *lconv->currency_symbol;
+ dsymbol = *lconv->mon_decimal_point;
+ nsymbol = lconv->negative_sign;
+ /* frac_digits in the C locale seems to return CHAR_MAX */
+ /* best guess is 2 in this case I think */
+ points = ((lconv->frac_digits != CHAR_MAX) ? lconv->frac_digits : 2); /* int_frac_digits? */
+ convention = lconv->n_sign_posn;
#else
- mon_group = 3;
- comma = ',';
- csymbol = '$';
- dsymbol = '.';
- nsymbol = "-";
- points = 2;
- convention = 0;
+ mon_group = 3;
+ comma = ',';
+ csymbol = '$';
+ dsymbol = '.';
+ nsymbol = "-";
+ points = 2;
+ convention = 0;
#endif
- point_pos = LAST_DIGIT - points;
+ point_pos = LAST_DIGIT - points;
- /* We're playing a little fast and loose with this. Shoot me. */
- if (!mon_group || mon_group == CHAR_MAX)
- mon_group = 3;
+ /* We're playing a little fast and loose with this. Shoot me. */
+ if (!mon_group || mon_group == CHAR_MAX)
+ mon_group = 3;
+
+ /* allow more than three decimal points and separate them */
+ if (comma)
+ {
+ point_pos -= (points - 1) / mon_group;
+ comma_position = point_pos % (mon_group + 1);
+ }
+
+ /* we work with positive amounts and add the minus sign at the end */
+ if (*value < 0)
+ {
+ minus = 1;
+ *value *= -1;
+ }
- /* allow more than three decimal points and separate them */
- if (comma) {
- point_pos -= (points - 1)/mon_group;
- comma_position = point_pos % (mon_group + 1);
- }
-
- /* we work with positive amounts and add the minus sign at the end */
- if (*value < 0) {
- minus = 1;
- *value *= -1;
- }
-
- /* allow for trailing negative strings */
- memset(buf, ' ', CASH_BUFSZ);
- buf[TERMINATOR] = buf[LAST_PAREN] = '\0';
-
- while (*value || count > (point_pos - 2)) {
- if (points && count == point_pos)
- buf[count--] = dsymbol;
- else if (comma && count % (mon_group + 1) == comma_position)
- buf[count--] = comma;
-
- buf[count--] = (*value % 10) + '0';
- *value /= 10;
- }
-
- buf[count] = csymbol;
-
- if (buf[LAST_DIGIT] == ',')
- buf[LAST_DIGIT] = buf[LAST_PAREN];
-
- /* see if we need to signify negative amount */
- if (minus) {
- if (!PointerIsValid(result = PALLOC(CASH_BUFSZ + 2 - count + strlen(nsymbol))))
- elog(WARN,"Memory allocation failed, can't output cash",NULL);
-
- /* Position code of 0 means use parens */
- if (convention == 0)
- sprintf(result, "(%s)", buf + count);
- else if (convention == 2)
- sprintf(result, "%s%s", buf + count, nsymbol);
+ /* allow for trailing negative strings */
+ memset(buf, ' ', CASH_BUFSZ);
+ buf[TERMINATOR] = buf[LAST_PAREN] = '\0';
+
+ while (*value || count > (point_pos - 2))
+ {
+ if (points && count == point_pos)
+ buf[count--] = dsymbol;
+ else if (comma && count % (mon_group + 1) == comma_position)
+ buf[count--] = comma;
+
+ buf[count--] = (*value % 10) + '0';
+ *value /= 10;
+ }
+
+ buf[count] = csymbol;
+
+ if (buf[LAST_DIGIT] == ',')
+ buf[LAST_DIGIT] = buf[LAST_PAREN];
+
+ /* see if we need to signify negative amount */
+ if (minus)
+ {
+ if (!PointerIsValid(result = PALLOC(CASH_BUFSZ + 2 - count + strlen(nsymbol))))
+ elog(WARN, "Memory allocation failed, can't output cash", NULL);
+
+ /* Position code of 0 means use parens */
+ if (convention == 0)
+ sprintf(result, "(%s)", buf + count);
+ else if (convention == 2)
+ sprintf(result, "%s%s", buf + count, nsymbol);
+ else
+ sprintf(result, "%s%s", nsymbol, buf + count);
+ }
else
- sprintf(result, "%s%s", nsymbol, buf + count);
- } else {
- if (!PointerIsValid(result = PALLOC(CASH_BUFSZ + 2 - count)))
- elog(WARN,"Memory allocation failed, can't output cash",NULL);
+ {
+ if (!PointerIsValid(result = PALLOC(CASH_BUFSZ + 2 - count)))
+ elog(WARN, "Memory allocation failed, can't output cash", NULL);
- strcpy(result, buf + count);
- }
+ strcpy(result, buf + count);
+ }
- return(result);
-} /* cash_out() */
+ return (result);
+} /* cash_out() */
bool
-cash_eq(Cash *c1, Cash *c2)
+cash_eq(Cash * c1, Cash * c2)
{
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(FALSE);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (FALSE);
- return(*c1 == *c2);
-} /* cash_eq() */
+ return (*c1 == *c2);
+} /* cash_eq() */
bool
-cash_ne(Cash *c1, Cash *c2)
+cash_ne(Cash * c1, Cash * c2)
{
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(FALSE);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (FALSE);
- return(*c1 != *c2);
-} /* cash_ne() */
+ return (*c1 != *c2);
+} /* cash_ne() */
bool
-cash_lt(Cash *c1, Cash *c2)
+cash_lt(Cash * c1, Cash * c2)
{
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(FALSE);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (FALSE);
- return(*c1 < *c2);
-} /* cash_lt() */
+ return (*c1 < *c2);
+} /* cash_lt() */
bool
-cash_le(Cash *c1, Cash *c2)
+cash_le(Cash * c1, Cash * c2)
{
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(FALSE);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (FALSE);
- return(*c1 <= *c2);
-} /* cash_le() */
+ return (*c1 <= *c2);
+} /* cash_le() */
bool
-cash_gt(Cash *c1, Cash *c2)
+cash_gt(Cash * c1, Cash * c2)
{
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(FALSE);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (FALSE);
- return(*c1 > *c2);
-} /* cash_gt() */
+ return (*c1 > *c2);
+} /* cash_gt() */
bool
-cash_ge(Cash *c1, Cash *c2)
+cash_ge(Cash * c1, Cash * c2)
{
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(FALSE);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (FALSE);
- return(*c1 >= *c2);
-} /* cash_ge() */
+ return (*c1 >= *c2);
+} /* cash_ge() */
/* cash_pl()
* Add two cash values.
*/
-Cash *
-cash_pl(Cash *c1, Cash *c2)
+Cash *
+cash_pl(Cash * c1, Cash * c2)
{
- Cash *result;
+ Cash *result;
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(NULL);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (NULL);
- if (!PointerIsValid(result = PALLOCTYPE(Cash)))
- elog(WARN,"Memory allocation failed, can't add cash",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(Cash)))
+ elog(WARN, "Memory allocation failed, can't add cash", NULL);
- *result = (*c1 + *c2);
+ *result = (*c1 + *c2);
- return(result);
-} /* cash_pl() */
+ return (result);
+} /* cash_pl() */
/* cash_mi()
* Subtract two cash values.
*/
-Cash *
-cash_mi(Cash *c1, Cash *c2)
+Cash *
+cash_mi(Cash * c1, Cash * c2)
{
- Cash *result;
+ Cash *result;
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(NULL);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (NULL);
- if (!PointerIsValid(result = PALLOCTYPE(Cash)))
- elog(WARN,"Memory allocation failed, can't subtract cash",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(Cash)))
+ elog(WARN, "Memory allocation failed, can't subtract cash", NULL);
- *result = (*c1 - *c2);
+ *result = (*c1 - *c2);
- return(result);
-} /* cash_mi() */
+ return (result);
+} /* cash_mi() */
/* cash_mul()
* Multiply cash by floating point number.
*/
-Cash *
-cash_mul(Cash *c, float8 *f)
+Cash *
+cash_mul(Cash * c, float8 * f)
{
- Cash *result;
+ Cash *result;
- if (!PointerIsValid(f) || !PointerIsValid(c))
- return(NULL);
+ if (!PointerIsValid(f) || !PointerIsValid(c))
+ return (NULL);
- if (!PointerIsValid(result = PALLOCTYPE(Cash)))
- elog(WARN,"Memory allocation failed, can't multiply cash",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(Cash)))
+ elog(WARN, "Memory allocation failed, can't multiply cash", NULL);
- *result = ((*f) * (*c));
+ *result = ((*f) * (*c));
- return(result);
-} /* cash_mul() */
+ return (result);
+} /* cash_mul() */
/* cash_div()
@@ -360,116 +391,121 @@ cash_mul(Cash *c, float8 *f)
* XXX Don't know if rounding or truncating is correct behavior.
* Round for now. - tgl 97/04/15
*/
-Cash *
-cash_div(Cash *c, float8 *f)
+Cash *
+cash_div(Cash * c, float8 * f)
{
- Cash *result;
+ Cash *result;
- if (!PointerIsValid(f) || !PointerIsValid(c))
- return(NULL);
+ if (!PointerIsValid(f) || !PointerIsValid(c))
+ return (NULL);
- if (!PointerIsValid(result = PALLOCTYPE(Cash)))
- elog(WARN,"Memory allocation failed, can't divide cash",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(Cash)))
+ elog(WARN, "Memory allocation failed, can't divide cash", NULL);
- if (*f == 0.0)
- elog(WARN,"cash_div: divide by 0.0 error");
+ if (*f == 0.0)
+ elog(WARN, "cash_div: divide by 0.0 error");
- *result = rint(*c / *f);
+ *result = rint(*c / *f);
- return(result);
-} /* cash_div() */
+ return (result);
+} /* cash_div() */
/* cashlarger()
* Return larger of two cash values.
*/
-Cash *
-cashlarger(Cash *c1, Cash *c2)
+Cash *
+cashlarger(Cash * c1, Cash * c2)
{
- Cash *result;
+ Cash *result;
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(NULL);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (NULL);
- if (!PointerIsValid(result = PALLOCTYPE(Cash)))
- elog(WARN,"Memory allocation failed, can't return larger cash",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(Cash)))
+ elog(WARN, "Memory allocation failed, can't return larger cash", NULL);
- *result = ((*c1 > *c2)? *c1: *c2);
+ *result = ((*c1 > *c2) ? *c1 : *c2);
- return(result);
-} /* cashlarger() */
+ return (result);
+} /* cashlarger() */
/* cashsmaller()
* Return smaller of two cash values.
*/
-Cash *
-cashsmaller(Cash *c1, Cash *c2)
+Cash *
+cashsmaller(Cash * c1, Cash * c2)
{
- Cash *result;
+ Cash *result;
- if (!PointerIsValid(c1) || !PointerIsValid(c2))
- return(NULL);
+ if (!PointerIsValid(c1) || !PointerIsValid(c2))
+ return (NULL);
- if (!PointerIsValid(result = PALLOCTYPE(Cash)))
- elog(WARN,"Memory allocation failed, can't return smaller cash",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(Cash)))
+ elog(WARN, "Memory allocation failed, can't return smaller cash", NULL);
- *result = ((*c1 < *c2)? *c1: *c2);
+ *result = ((*c1 < *c2) ? *c1 : *c2);
- return(result);
-} /* cashsmaller() */
+ return (result);
+} /* cashsmaller() */
/* cash_words_out()
* This converts a int4 as well but to a representation using words
* Obviously way North American centric - sorry
*/
-const char *
-cash_words_out(Cash *value)
+const char *
+cash_words_out(Cash * value)
{
- static char buf[128];
- char *p = buf;
- Cash m0;
- Cash m1;
- Cash m2;
- Cash m3;
-
- /* work with positive numbers */
- if (*value < 0) {
- *value *= -1;
- strcpy(buf, "minus ");
- p += 6;
- } else {
- *buf = 0;
- }
-
- m0 = *value % 100; /* cents */
- m1 = (*value/100) % 1000; /* hundreds */
- m2 = (*value/100000) % 1000; /* thousands */
- m3 = *value/100000000 % 1000; /* millions */
-
- if (m3) {
- strcat(buf, num_word(m3));
- strcat(buf, " million ");
- }
-
- if (m2) {
- strcat(buf, num_word(m2));
- strcat(buf, " thousand ");
- }
-
- if (m1)
- strcat(buf, num_word(m1));
-
- if (!*p)
- strcat(buf, "zero");
-
- strcat(buf, (int)(*value/100) == 1 ? " dollar and " : " dollars and ");
- strcat(buf, num_word(m0));
- strcat(buf, m0 == 1 ? " cent" : " cents");
- *buf = toupper(*buf);
- return(buf);
-} /* cash_words_out() */
+ static char buf[128];
+ char *p = buf;
+ Cash m0;
+ Cash m1;
+ Cash m2;
+ Cash m3;
+
+ /* work with positive numbers */
+ if (*value < 0)
+ {
+ *value *= -1;
+ strcpy(buf, "minus ");
+ p += 6;
+ }
+ else
+ {
+ *buf = 0;
+ }
+
+ m0 = *value % 100; /* cents */
+ m1 = (*value / 100) % 1000; /* hundreds */
+ m2 = (*value / 100000) % 1000; /* thousands */
+ m3 = *value / 100000000 % 1000; /* millions */
+
+ if (m3)
+ {
+ strcat(buf, num_word(m3));
+ strcat(buf, " million ");
+ }
+
+ if (m2)
+ {
+ strcat(buf, num_word(m2));
+ strcat(buf, " thousand ");
+ }
+
+ if (m1)
+ strcat(buf, num_word(m1));
+
+ if (!*p)
+ strcat(buf, "zero");
+
+ strcat(buf, (int) (*value / 100) == 1 ? " dollar and " : " dollars and ");
+ strcat(buf, num_word(m0));
+ strcat(buf, m0 == 1 ? " cent" : " cents");
+ *buf = toupper(*buf);
+ return (buf);
+} /* cash_words_out() */
/*************************************************************************
@@ -479,48 +515,52 @@ cash_words_out(Cash *value)
static const char *
num_word(Cash value)
{
- static char buf[128];
- static const char *small[] = {
- "zero", "one", "two", "three", "four", "five", "six", "seven",
- "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
- "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty",
- "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety"
- };
- const char **big = small + 18;
- int tu = value % 100;
-
- /* deal with the simple cases first */
- if (value <= 20)
- return(small[value]);
-
- /* is it an even multiple of 100? */
- if (!tu) {
- sprintf(buf, "%s hundred", small[value/100]);
- return(buf);
- }
-
- /* more than 99? */
- if (value > 99) {
- /* is it an even multiple of 10 other than 10? */
- if (value % 10 == 0 && tu > 10)
- sprintf(buf, "%s hundred %s",
- small[value/100], big[tu/10]);
- else if (tu < 20)
- sprintf(buf, "%s hundred and %s",
- small[value/100], small[tu]);
- else
- sprintf(buf, "%s hundred %s %s",
- small[value/100], big[tu/10], small[tu % 10]);
-
- } else {
- /* is it an even multiple of 10 other than 10? */
- if (value % 10 == 0 && tu > 10)
- sprintf(buf, "%s", big[tu/10]);
- else if (tu < 20)
- sprintf(buf, "%s", small[tu]);
+ static char buf[128];
+ static const char *small[] = {
+ "zero", "one", "two", "three", "four", "five", "six", "seven",
+ "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen",
+ "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty",
+ "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety"
+ };
+ const char **big = small + 18;
+ int tu = value % 100;
+
+ /* deal with the simple cases first */
+ if (value <= 20)
+ return (small[value]);
+
+ /* is it an even multiple of 100? */
+ if (!tu)
+ {
+ sprintf(buf, "%s hundred", small[value / 100]);
+ return (buf);
+ }
+
+ /* more than 99? */
+ if (value > 99)
+ {
+ /* is it an even multiple of 10 other than 10? */
+ if (value % 10 == 0 && tu > 10)
+ sprintf(buf, "%s hundred %s",
+ small[value / 100], big[tu / 10]);
+ else if (tu < 20)
+ sprintf(buf, "%s hundred and %s",
+ small[value / 100], small[tu]);
+ else
+ sprintf(buf, "%s hundred %s %s",
+ small[value / 100], big[tu / 10], small[tu % 10]);
+
+ }
else
- sprintf(buf, "%s %s", big[tu/10], small[tu % 10]);
- }
+ {
+ /* is it an even multiple of 10 other than 10? */
+ if (value % 10 == 0 && tu > 10)
+ sprintf(buf, "%s", big[tu / 10]);
+ else if (tu < 20)
+ sprintf(buf, "%s", small[tu]);
+ else
+ sprintf(buf, "%s %s", big[tu / 10], small[tu % 10]);
+ }
- return(buf);
-} /* num_word() */
+ return (buf);
+} /* num_word() */
diff --git a/src/backend/utils/adt/char.c b/src/backend/utils/adt/char.c
index afb87a4d8b3..24e30054b6b 100644
--- a/src/backend/utils/adt/char.c
+++ b/src/backend/utils/adt/char.c
@@ -1,384 +1,460 @@
/*-------------------------------------------------------------------------
*
* char.c--
- * Functions for the built-in type "char".
- * Functions for the built-in type "cid".
- * Functions for the built-in type "char2".
- * Functions for the built-in type "char4".
- * Functions for the built-in type "char8".
- * Functions for the built-in type "char16".
+ * Functions for the built-in type "char".
+ * Functions for the built-in type "cid".
+ * Functions for the built-in type "char2".
+ * Functions for the built-in type "char4".
+ * Functions for the built-in type "char8".
+ * Functions for the built-in type "char16".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/char.c,v 1.7 1997/08/12 20:39:16 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/char.c,v 1.8 1997/09/07 04:50:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/builtins.h" /* where the declarations go */
-/*****************************************************************************
- * USER I/O ROUTINES *
+/*****************************************************************************
+ * USER I/O ROUTINES *
*****************************************************************************/
/*
- * charin - converts "x" to 'x'
+ * charin - converts "x" to 'x'
*/
-int32 charin(char *ch)
+int32
+charin(char *ch)
{
- if (ch == NULL)
- return((int32) NULL);
- return((int32) *ch);
+ if (ch == NULL)
+ return ((int32) NULL);
+ return ((int32) * ch);
}
/*
- * charout - converts 'x' to "x"
+ * charout - converts 'x' to "x"
*/
-char *charout(int32 ch)
+char *
+charout(int32 ch)
{
- char *result = (char *) palloc(2);
-
- result[0] = (char) ch;
- result[1] = '\0';
- return(result);
+ char *result = (char *) palloc(2);
+
+ result[0] = (char) ch;
+ result[1] = '\0';
+ return (result);
}
/*
- * cidin - converts "..." to internal representation.
+ * cidin - converts "..." to internal representation.
*
- * NOTE: we must not use 'charin' because cid might be a non
- * printable character...
+ * NOTE: we must not use 'charin' because cid might be a non
+ * printable character...
*/
-int32 cidin(char *s)
+int32
+cidin(char *s)
{
- CommandId c;
-
- if (s==NULL)
- c = 0;
- else
- c = atoi(s);
-
- return((int32)c);
+ CommandId c;
+
+ if (s == NULL)
+ c = 0;
+ else
+ c = atoi(s);
+
+ return ((int32) c);
}
/*
- * cidout - converts a cid to "..."
+ * cidout - converts a cid to "..."
*
- * NOTE: we must no use 'charout' because cid might be a non
- * printable character...
+ * NOTE: we must no use 'charout' because cid might be a non
+ * printable character...
*/
-char *cidout(int32 c)
-{
- char *result;
- CommandId c2;
-
- /*
- * cid is a number between 0 .. 2^16-1, therefore we need at most
- * 6 chars for the string (5 digits + '\0')
- * NOTE: print it as an UNSIGNED int!
- */
- result = palloc(6);
- c2 = (CommandId)c;
- sprintf(result, "%u", (unsigned)(c2));
- return(result);
+char *
+cidout(int32 c)
+{
+ char *result;
+ CommandId c2;
+
+ /*
+ * cid is a number between 0 .. 2^16-1, therefore we need at most 6
+ * chars for the string (5 digits + '\0') NOTE: print it as an
+ * UNSIGNED int!
+ */
+ result = palloc(6);
+ c2 = (CommandId) c;
+ sprintf(result, "%u", (unsigned) (c2));
+ return (result);
}
/*
- * char16in - converts "..." to internal reprsentation
+ * char16in - converts "..." to internal reprsentation
*
- * Note:
- * Currently if strlen(s) < 14, the extra chars are nulls
+ * Note:
+ * Currently if strlen(s) < 14, the extra chars are nulls
*/
-char *char16in(char *s)
+char *
+char16in(char *s)
{
- char *result;
+ char *result;
- if (s == NULL)
- return(NULL);
- result = (char *) palloc(16);
- strncpy(result, s, 16);
- return(result);
+ if (s == NULL)
+ return (NULL);
+ result = (char *) palloc(16);
+ strncpy(result, s, 16);
+ return (result);
}
/*
- * char16out - converts internal reprsentation to "..."
+ * char16out - converts internal reprsentation to "..."
*/
-char *char16out(char *s)
+char *
+char16out(char *s)
{
- char *result = (char *) palloc(17);
-
- if (s == NULL) {
- result[0] = '-';
- result[1] = '\0';
- } else
- strNcpy(result, s, 16);
- return(result);
+ char *result = (char *) palloc(17);
+
+ if (s == NULL)
+ {
+ result[0] = '-';
+ result[1] = '\0';
+ }
+ else
+ strNcpy(result, s, 16);
+ return (result);
}
-/*****************************************************************************
- * PUBLIC ROUTINES *
+/*****************************************************************************
+ * PUBLIC ROUTINES *
*****************************************************************************/
-bool chareq(int8 arg1, int8 arg2) { return(arg1 == arg2); }
-bool charne(int8 arg1, int8 arg2) { return(arg1 != arg2); }
-bool charlt(int8 arg1, int8 arg2) { return((uint8)arg1 < (uint8)arg2); }
-bool charle(int8 arg1, int8 arg2) { return((uint8)arg1 <= (uint8)arg2); }
-bool chargt(int8 arg1, int8 arg2) { return((uint8)arg1 > (uint8)arg2); }
-bool charge(int8 arg1, int8 arg2) { return((uint8)arg1 >= (uint8)arg2); }
-int8 charpl(int8 arg1, int8 arg2) { return(arg1 + arg2); }
-int8 charmi(int8 arg1, int8 arg2) { return(arg1 - arg2); }
-int8 charmul(int8 arg1, int8 arg2) { return(arg1 * arg2); }
-int8 chardiv(int8 arg1, int8 arg2) { return(arg1 / arg2); }
+bool chareq(int8 arg1, int8 arg2)
+{
+ return (arg1 == arg2);
+}
+bool charne(int8 arg1, int8 arg2)
+{
+ return (arg1 != arg2);
+}
+bool charlt(int8 arg1, int8 arg2)
+{
+ return ((uint8) arg1 < (uint8) arg2);
+}
+bool charle(int8 arg1, int8 arg2)
+{
+ return ((uint8) arg1 <= (uint8) arg2);
+}
+bool chargt(int8 arg1, int8 arg2)
+{
+ return ((uint8) arg1 > (uint8) arg2);
+}
+bool charge(int8 arg1, int8 arg2)
+{
+ return ((uint8) arg1 >= (uint8) arg2);
+}
+int8 charpl(int8 arg1, int8 arg2)
+{
+ return (arg1 + arg2);
+}
+int8 charmi(int8 arg1, int8 arg2)
+{
+ return (arg1 - arg2);
+}
+int8 charmul(int8 arg1, int8 arg2)
+{
+ return (arg1 * arg2);
+}
+int8 chardiv(int8 arg1, int8 arg2)
+{
+ return (arg1 / arg2);
+}
-bool cideq(int8 arg1, int8 arg2) { return(arg1 == arg2); }
+bool cideq(int8 arg1, int8 arg2)
+{
+ return (arg1 == arg2);
+}
/*
- * char16eq - returns 1 iff arguments are equal
- * char16ne - returns 1 iff arguments are not equal
+ * char16eq - returns 1 iff arguments are equal
+ * char16ne - returns 1 iff arguments are not equal
*
- * BUGS:
- * Assumes that "xy\0\0a" should be equal to "xy\0b".
- * If not, can do the comparison backwards for efficiency.
+ * BUGS:
+ * Assumes that "xy\0\0a" should be equal to "xy\0b".
+ * If not, can do the comparison backwards for efficiency.
*
- * char16lt - returns 1 iff a < b
- * char16le - returns 1 iff a <= b
- * char16gt - returns 1 iff a < b
- * char16ge - returns 1 iff a <= b
+ * char16lt - returns 1 iff a < b
+ * char16le - returns 1 iff a <= b
+ * char16gt - returns 1 iff a < b
+ * char16ge - returns 1 iff a <= b
*
*/
-bool char16eq(char *arg1, char *arg2)
+bool
+char16eq(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 16) == 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 16) == 0);
}
-bool char16ne(char *arg1, char *arg2)
+bool
+char16ne(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 16) != 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 16) != 0);
}
-bool char16lt(char *arg1, char *arg2)
+bool
+char16lt(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 16) < 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 16) < 0);
}
-bool char16le(char *arg1, char *arg2)
+bool
+char16le(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 16) <= 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 16) <= 0);
}
-bool char16gt(char *arg1, char *arg2)
+bool
+char16gt(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
-
- return(strncmp(arg1, arg2, 16) > 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+
+ return (strncmp(arg1, arg2, 16) > 0);
}
-bool char16ge(char *arg1, char *arg2)
+bool
+char16ge(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
-
- return(strncmp(arg1, arg2, 16) >= 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+
+ return (strncmp(arg1, arg2, 16) >= 0);
}
/* ============================== char2 ============================== */
-uint16 char2in(char *s)
+uint16
+char2in(char *s)
{
- uint16 res;
-
- if (s == NULL)
- return(0);
-
- strncpy((char *) &res, s, 2);
- return(res);
+ uint16 res;
+
+ if (s == NULL)
+ return (0);
+
+ strncpy((char *) &res, s, 2);
+ return (res);
}
-char *char2out(uint16 s)
+char *
+char2out(uint16 s)
{
- char *result = (char *) palloc(3);
-
- strNcpy(result, (char *) &s, 2);
-
- return(result);
+ char *result = (char *) palloc(3);
+
+ strNcpy(result, (char *) &s, 2);
+
+ return (result);
}
-bool char2eq(uint16 a, uint16 b)
+bool
+char2eq(uint16 a, uint16 b)
{
- return(strncmp((char *) &a, (char *) &b, 2) == 0);
+ return (strncmp((char *) &a, (char *) &b, 2) == 0);
}
-bool char2ne(uint16 a, uint16 b)
+bool
+char2ne(uint16 a, uint16 b)
{
- return(strncmp((char *) &a, (char *) &b, 2) != 0);
+ return (strncmp((char *) &a, (char *) &b, 2) != 0);
}
-bool char2lt(uint16 a, uint16 b)
+bool
+char2lt(uint16 a, uint16 b)
{
- return(strncmp((char *) &a, (char *) &b, 2) < 0);
+ return (strncmp((char *) &a, (char *) &b, 2) < 0);
}
-bool char2le(uint16 a, uint16 b)
+bool
+char2le(uint16 a, uint16 b)
{
- return(strncmp((char *) &a, (char *) &b, 2) <= 0);
+ return (strncmp((char *) &a, (char *) &b, 2) <= 0);
}
-bool char2gt(uint16 a, uint16 b)
+bool
+char2gt(uint16 a, uint16 b)
{
- return(strncmp((char *) &a, (char *) &b, 2) > 0);
+ return (strncmp((char *) &a, (char *) &b, 2) > 0);
}
-bool char2ge(uint16 a, uint16 b)
+bool
+char2ge(uint16 a, uint16 b)
{
- return(strncmp((char *) &a, (char *) &b, 2) >= 0);
+ return (strncmp((char *) &a, (char *) &b, 2) >= 0);
}
-int32 char2cmp(uint16 a, uint16 b)
+int32
+char2cmp(uint16 a, uint16 b)
{
- return (strncmp((char *) &a, (char *) &b, 2));
+ return (strncmp((char *) &a, (char *) &b, 2));
}
/* ============================== char4 ============================== */
-uint32 char4in(char *s)
+uint32
+char4in(char *s)
{
- uint32 res;
-
- if (s == NULL)
- return(0);
-
- strncpy((char *) &res, s, 4);
-
- return(res);
+ uint32 res;
+
+ if (s == NULL)
+ return (0);
+
+ strncpy((char *) &res, s, 4);
+
+ return (res);
}
-char *char4out(s)
- uint32 s;
+char *
+char4out(s)
+uint32 s;
{
- char *result = (char *) palloc(5);
-
- strNcpy(result, (char *) &s, 4);
-
- return(result);
+ char *result = (char *) palloc(5);
+
+ strNcpy(result, (char *) &s, 4);
+
+ return (result);
}
-bool char4eq(uint32 a, uint32 b)
+bool
+char4eq(uint32 a, uint32 b)
{
- return(strncmp((char *) &a, (char *) &b, 4) == 0);
+ return (strncmp((char *) &a, (char *) &b, 4) == 0);
}
-bool char4ne(uint32 a, uint32 b)
+bool
+char4ne(uint32 a, uint32 b)
{
- return(strncmp((char *) &a, (char *) &b, 4) != 0);
+ return (strncmp((char *) &a, (char *) &b, 4) != 0);
}
-bool char4lt(uint32 a, uint32 b)
+bool
+char4lt(uint32 a, uint32 b)
{
- return(strncmp((char *) &a, (char *) &b, 4) < 0);
+ return (strncmp((char *) &a, (char *) &b, 4) < 0);
}
-bool char4le(uint32 a, uint32 b)
+bool
+char4le(uint32 a, uint32 b)
{
- return(strncmp((char *) &a, (char *) &b, 4) <= 0);
+ return (strncmp((char *) &a, (char *) &b, 4) <= 0);
}
-bool char4gt(uint32 a, uint32 b)
+bool
+char4gt(uint32 a, uint32 b)
{
- return(strncmp((char *) &a, (char *) &b, 4) > 0);
+ return (strncmp((char *) &a, (char *) &b, 4) > 0);
}
-bool char4ge(uint32 a, uint32 b)
+bool
+char4ge(uint32 a, uint32 b)
{
- return(strncmp((char *) &a, (char *) &b, 4) >= 0);
+ return (strncmp((char *) &a, (char *) &b, 4) >= 0);
}
-int32 char4cmp(uint32 a, uint32 b)
+int32
+char4cmp(uint32 a, uint32 b)
{
- return(strncmp((char *) &a, (char *) &b, 4));
+ return (strncmp((char *) &a, (char *) &b, 4));
}
/* ============================== char8 ============================== */
-char *char8in(char *s)
+char *
+char8in(char *s)
{
- char *result;
-
- if (s == NULL)
- return((char *) NULL);
-
- result = (char *) palloc(8);
- strncpy(result, s, 8);
- return(result);
+ char *result;
+
+ if (s == NULL)
+ return ((char *) NULL);
+
+ result = (char *) palloc(8);
+ strncpy(result, s, 8);
+ return (result);
}
-char *char8out(char *s)
+char *
+char8out(char *s)
{
- char *result = (char *) palloc(9);
-
- if (s == NULL) {
- result[0] = '-';
- result[1] = '\0';
- } else
- strNcpy(result, s, 8);
- return(result);
+ char *result = (char *) palloc(9);
+
+ if (s == NULL)
+ {
+ result[0] = '-';
+ result[1] = '\0';
+ }
+ else
+ strNcpy(result, s, 8);
+ return (result);
}
-bool char8eq(char *arg1, char *arg2)
+bool
+char8eq(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 8) == 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 8) == 0);
}
-bool char8ne(char *arg1, char *arg2)
+bool
+char8ne(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 8) != 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 8) != 0);
}
-bool char8lt(char *arg1, char *arg2)
+bool
+char8lt(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 8) < 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 8) < 0);
}
-bool char8le(char *arg1, char *arg2)
+bool
+char8le(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 8) <= 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 8) <= 0);
}
-bool char8gt(char *arg1, char *arg2)
+bool
+char8gt(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 8) > 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 8) > 0);
}
-bool char8ge(char *arg1, char *arg2)
+bool
+char8ge(char *arg1, char *arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return(strncmp(arg1, arg2, 8) >= 0);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return (strncmp(arg1, arg2, 8) >= 0);
}
-int32 char8cmp(char *arg1, char *arg2)
+int32
+char8cmp(char *arg1, char *arg2)
{
- return(strncmp(arg1, arg2, 8));
+ return (strncmp(arg1, arg2, 8));
}
diff --git a/src/backend/utils/adt/chunk.c b/src/backend/utils/adt/chunk.c
index 3d9aec0d9e4..fcfc8cdaeb5 100644
--- a/src/backend/utils/adt/chunk.c
+++ b/src/backend/utils/adt/chunk.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/chunk.c,v 1.6 1997/08/19 21:34:27 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/chunk.c,v 1.7 1997/09/07 04:50:04 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,7 +20,7 @@
#include "utils/memutils.h"
#include "libpq/libpq-fs.h"
-#include "storage/fd.h" /* for SEEK_ */
+#include "storage/fd.h" /* for SEEK_ */
#include "catalog/pg_type.h"
@@ -29,581 +29,666 @@
#include "optimizer/internal.h"
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
#define INFTY 500000000
#define MANY 10000
#define MAXPAT 20
-#define quot_ceil(x,y) (((x)+(y)-1)/(y))
-#define min(x,y) (((x) < (y))? (x) : (y))
-#define max(x,y) (((x) > (y))? (x) : (y))
+#define quot_ceil(x,y) (((x)+(y)-1)/(y))
+#define min(x,y) (((x) < (y))? (x) : (y))
+#define max(x,y) (((x) > (y))? (x) : (y))
static CHUNK_INFO cInfo;
/* non-export function prototypes */
-static int _FindBestChunk(int size, int dmax[], int dbest[], int dim,
- int A[MAXPAT][MAXDIM+1], int N);
-static int get_next(int d[], int k, int C, int dmax[]);
-static void initialize_info(CHUNK_INFO *A, int ndim, int dim[], int chunk[]);
+static int
+_FindBestChunk(int size, int dmax[], int dbest[], int dim,
+ int A[MAXPAT][MAXDIM + 1], int N);
+static int get_next(int d[], int k, int C, int dmax[]);
+static void initialize_info(CHUNK_INFO * A, int ndim, int dim[], int chunk[]);
+
#ifdef LOARRAY
-static void _ConvertToChunkFile(int n, int baseSize, int dim[], int C[],
- int srcfd, int destfd);
-static void read_chunk(int chunk_no[], int C[], char a_chunk[], int srcfd,
- int n, int baseSize, int PX[], int dist[]);
-static int write_chunk(struct varlena * a_chunk, int ofile);
-static int seek_and_read(int pos, int size, char buff[], int fp, int from);
+static void
+_ConvertToChunkFile(int n, int baseSize, int dim[], int C[],
+ int srcfd, int destfd);
+static void
+read_chunk(int chunk_no[], int C[], char a_chunk[], int srcfd,
+ int n, int baseSize, int PX[], int dist[]);
+static int write_chunk(struct varlena * a_chunk, int ofile);
+static int seek_and_read(int pos, int size, char buff[], int fp, int from);
+
#endif
-static int GetChunkSize(FILE *fd, int ndim, int dim[MAXDIM], int baseSize,
- int d[MAXDIM]);
+static int
+GetChunkSize(FILE * fd, int ndim, int dim[MAXDIM], int baseSize,
+ int d[MAXDIM]);
/*------------------------------------------------------------------------
* _ChunkArray ---
- * converts an input array to chunked format using the information
- * provided by the access pattern.
+ * converts an input array to chunked format using the information
+ * provided by the access pattern.
* Results:
- * creates a new file that stores the chunked array and returns
- * information about the chunked file
+ * creates a new file that stores the chunked array and returns
+ * information about the chunked file
*-----------------------------------------------------------------------
*/
-char *
+char *
_ChunkArray(int fd,
- FILE *afd,
- int ndim,
- int dim[],
- int baseSize,
- int *nbytes,
- char *chunkfile)
+ FILE * afd,
+ int ndim,
+ int dim[],
+ int baseSize,
+ int *nbytes,
+ char *chunkfile)
{
#ifdef LOARRAY
-int cfd = 0;
+ int cfd = 0;
+
#endif
- int chunk[MAXDIM], csize;
- bool reorgFlag;
-
- if (chunkfile == NULL)
- reorgFlag = true;
- else
- reorgFlag = false;
-
+ int chunk[MAXDIM],
+ csize;
+ bool reorgFlag;
+
+ if (chunkfile == NULL)
+ reorgFlag = true;
+ else
+ reorgFlag = false;
+
#ifdef LOARRAY
- if (reorgFlag)
- /* create new LO for chunked file */
- chunkfile = _array_newLO( &cfd, fileFlag );
- else
- cfd = LOopen(chunkfile, O_RDONLY);
- if (cfd < 0)
- elog(WARN, "Unable to open chunk file");
+ if (reorgFlag)
+ /* create new LO for chunked file */
+ chunkfile = _array_newLO(&cfd, fileFlag);
+ else
+ cfd = LOopen(chunkfile, O_RDONLY);
+ if (cfd < 0)
+ elog(WARN, "Unable to open chunk file");
#endif
- strcpy (cInfo.lo_name, chunkfile);
-
- /* find chunk size */
- csize = GetChunkSize(afd, ndim, dim, baseSize, chunk);
-
+ strcpy(cInfo.lo_name, chunkfile);
+
+ /* find chunk size */
+ csize = GetChunkSize(afd, ndim, dim, baseSize, chunk);
+
#ifdef LOARRAY
- if (reorgFlag)
- /* copy data from input file to chunked file */
- _ConvertToChunkFile(ndim, baseSize, dim, chunk, fd, cfd);
+ if (reorgFlag)
+ /* copy data from input file to chunked file */
+ _ConvertToChunkFile(ndim, baseSize, dim, chunk, fd, cfd);
#endif
-
- initialize_info(&cInfo, ndim, dim, chunk);
- *nbytes = sizeof(CHUNK_INFO);
- return (char *) &cInfo ;
+
+ initialize_info(&cInfo, ndim, dim, chunk);
+ *nbytes = sizeof(CHUNK_INFO);
+ return (char *) &cInfo;
}
/*--------------------------------------------------------------------------
* GetChunkSize --
- * given an access pattern and array dimensionality etc, this program
- * returns the dimensions of the chunk in "d"
+ * given an access pattern and array dimensionality etc, this program
+ * returns the dimensions of the chunk in "d"
*-----------------------------------------------------------------------
*/
static int
-GetChunkSize(FILE *fd,
- int ndim,
- int dim[MAXDIM],
- int baseSize,
- int d[MAXDIM])
+GetChunkSize(FILE * fd,
+ int ndim,
+ int dim[MAXDIM],
+ int baseSize,
+ int d[MAXDIM])
{
- int N, i, j, csize;
- int A[MAXPAT][MAXDIM+1], dmax[MAXDIM];
-
- /*
- * ----------- read input ------------
- */
- fscanf(fd, "%d", &N);
- if ( N > MAXPAT )
- elog(WARN, "array_in: too many access pattern elements");
- for (i = 0; i < N; i++)
- for (j = 0; j < ndim+1; j++)
- if (fscanf(fd, "%d ", &(A[i][j])) == EOF)
- elog (WARN, "array_in: bad access pattern input");
-
- /*
- * estimate chunk size
- */
- for (i = 0; i < ndim; i++)
- for (j = 0, dmax[i] = 1; j < N; j++)
- if (dmax[i] < A[j][i])
- dmax[i] = A[j][i];
- csize = BLCKSZ/baseSize;
-
- _FindBestChunk (csize, dmax, d, ndim, A, N);
-
- return csize;
+ int N,
+ i,
+ j,
+ csize;
+ int A[MAXPAT][MAXDIM + 1],
+ dmax[MAXDIM];
+
+ /*
+ * ----------- read input ------------
+ */
+ fscanf(fd, "%d", &N);
+ if (N > MAXPAT)
+ elog(WARN, "array_in: too many access pattern elements");
+ for (i = 0; i < N; i++)
+ for (j = 0; j < ndim + 1; j++)
+ if (fscanf(fd, "%d ", &(A[i][j])) == EOF)
+ elog(WARN, "array_in: bad access pattern input");
+
+ /*
+ * estimate chunk size
+ */
+ for (i = 0; i < ndim; i++)
+ for (j = 0, dmax[i] = 1; j < N; j++)
+ if (dmax[i] < A[j][i])
+ dmax[i] = A[j][i];
+ csize = BLCKSZ / baseSize;
+
+ _FindBestChunk(csize, dmax, d, ndim, A, N);
+
+ return csize;
}
/*-------------------------------------------------------------------------
* _FindBestChunk --
- * This routine does most of the number crunching to compute the
- * optimal chunk shape.
+ * This routine does most of the number crunching to compute the
+ * optimal chunk shape.
* Called by GetChunkSize
*------------------------------------------------------------------------
*/
static int
_FindBestChunk(int size,
- int dmax[],
- int dbest[],
- int dim,
- int A[MAXPAT][MAXDIM+1],
- int N)
+ int dmax[],
+ int dbest[],
+ int dim,
+ int A[MAXPAT][MAXDIM + 1],
+ int N)
{
- int d[MAXDIM];
- int tc, mintc = INFTY;
-
- d[0] = 0;
- mintc = INFTY;
- while (get_next(d,dim,size, dmax)) {
- /*
- * compute the number of page fetches for a given
- * chunk size (d[]) and access pattern (A[][])
- */
- register int i,j, nc;
- for (i = 0, tc = 0; i < N; i++){
- for (j = 0, nc = 1; j < dim; j++)
- nc *= quot_ceil(A[i][j], d[j]);
- nc *= A[i][dim];
- tc += nc;
+ int d[MAXDIM];
+ int tc,
+ mintc = INFTY;
+
+ d[0] = 0;
+ mintc = INFTY;
+ while (get_next(d, dim, size, dmax))
+ {
+
+ /*
+ * compute the number of page fetches for a given chunk size (d[])
+ * and access pattern (A[][])
+ */
+ register int i,
+ j,
+ nc;
+
+ for (i = 0, tc = 0; i < N; i++)
+ {
+ for (j = 0, nc = 1; j < dim; j++)
+ nc *= quot_ceil(A[i][j], d[j]);
+ nc *= A[i][dim];
+ tc += nc;
+ }
+
+ /*
+ * tc holds the total number of page fetches
+ */
+ if (mintc >= tc)
+ {
+ mintc = tc;
+ for (j = 0; j < dim; dbest[j] = d[j], j++)
+ ;
+ }
}
- /*
- * tc holds the total number of page fetches
- */
- if (mintc >= tc) {
- mintc = tc;
- for (j = 0; j < dim; dbest[j] = d[j], j++)
- ;
- }
- }
- return(mintc);
+ return (mintc);
}
/*----------------------------------------------------------------------
* get_next --
- * Called by _GetBestChunk to get the next tuple in the lexicographic order
+ * Called by _GetBestChunk to get the next tuple in the lexicographic order
*---------------------------------------------------------------------
*/
static int
get_next(int d[], int k, int C, int dmax[])
{
- register int i,j, temp;
-
- if (!d[0]) {
- temp = C;
- for (j = k-1; j >= 0; j--){
- d[j] = min(temp, dmax[j]);
- temp = max(1, temp/d[j]);
- }
- return(1);
- }
-
- for (j = 0, temp = 1; j < k; j++)
- temp *= d[j];
-
- for (i=k-1; i >= 0; i--){
- temp = temp/d[i];
- if (((temp*(d[i]+1)) < C) && (d[i]+1 <= dmax[i]))
- break;
- }
- if (i < 0)
- return(0);
-
- d[i]++;
- j = C/temp;
- d[i] = min(dmax[i], j/(j/d[i]));
- temp = temp*d[i];
- temp = C/temp;
-
- for (j = k-1; j > i; j--){
- d[j] = min(temp, dmax[j]);
- temp = max(1, temp/d[j]);
- }
- return(1);
+ register int i,
+ j,
+ temp;
+
+ if (!d[0])
+ {
+ temp = C;
+ for (j = k - 1; j >= 0; j--)
+ {
+ d[j] = min(temp, dmax[j]);
+ temp = max(1, temp / d[j]);
+ }
+ return (1);
+ }
+
+ for (j = 0, temp = 1; j < k; j++)
+ temp *= d[j];
+
+ for (i = k - 1; i >= 0; i--)
+ {
+ temp = temp / d[i];
+ if (((temp * (d[i] + 1)) < C) && (d[i] + 1 <= dmax[i]))
+ break;
+ }
+ if (i < 0)
+ return (0);
+
+ d[i]++;
+ j = C / temp;
+ d[i] = min(dmax[i], j / (j / d[i]));
+ temp = temp * d[i];
+ temp = C / temp;
+
+ for (j = k - 1; j > i; j--)
+ {
+ d[j] = min(temp, dmax[j]);
+ temp = max(1, temp / d[j]);
+ }
+ return (1);
}
#ifdef LOARRAY
-static char a_chunk[BLCKSZ + 4]; /* 4 since a_chunk is in
- varlena format */
+static char a_chunk[BLCKSZ + 4]; /* 4 since a_chunk is in varlena
+ * format */
+
#endif
static void
-initialize_info(CHUNK_INFO *A, int ndim, int dim[], int chunk[])
+initialize_info(CHUNK_INFO * A, int ndim, int dim[], int chunk[])
{
- int i;
-
- for ( i = 0; i < ndim; i++)
- A->C[i] = chunk[i];
+ int i;
+
+ for (i = 0; i < ndim; i++)
+ A->C[i] = chunk[i];
}
/*--------------------------------------------------------------------------
* Procedure reorganize_data():
- * This procedure reads the input multidimensional array that is organised
- * in the order specified by array "X" and breaks it up into chunks of
- * dimensions specified in "C".
+ * This procedure reads the input multidimensional array that is organised
+ * in the order specified by array "X" and breaks it up into chunks of
+ * dimensions specified in "C".
*
- * This is a very slow process, since reading and writing of LARGE files
- * may be involved.
+ * This is a very slow process, since reading and writing of LARGE files
+ * may be involved.
*
*-------------------------------------------------------------------------
*/
#ifdef LOARRAY
static void
_ConvertToChunkFile(int n,
- int baseSize,
- int dim[],
- int C[],
- int srcfd,
- int destfd)
+ int baseSize,
+ int dim[],
+ int C[],
+ int srcfd,
+ int destfd)
{
- int max_chunks[MAXDIM], chunk_no[MAXDIM];
- int PX[MAXDIM], dist[MAXDIM];
- int csize = 1, i, temp;
-
- for (i = 0; i < n; chunk_no[i++] = 0) {
- max_chunks[i] = dim[i]/C[i];
- csize *= C[i];
- }
- csize *= baseSize;
- temp = csize + 4;
- memmove(a_chunk, &temp, 4);
-
- mda_get_prod(n, dim, PX);
- mda_get_offset_values(n, dist, PX, C);
- for (i = 0; i < n; dist[i] *= baseSize, i++)
- ;
- do {
- read_chunk(chunk_no, C, &(a_chunk[4]), srcfd, n, baseSize, PX, dist);
- write_chunk((struct varlena*)a_chunk, destfd);
- } while (next_tuple(n, chunk_no, max_chunks) != -1);
+ int max_chunks[MAXDIM],
+ chunk_no[MAXDIM];
+ int PX[MAXDIM],
+ dist[MAXDIM];
+ int csize = 1,
+ i,
+ temp;
+
+ for (i = 0; i < n; chunk_no[i++] = 0)
+ {
+ max_chunks[i] = dim[i] / C[i];
+ csize *= C[i];
+ }
+ csize *= baseSize;
+ temp = csize + 4;
+ memmove(a_chunk, &temp, 4);
+
+ mda_get_prod(n, dim, PX);
+ mda_get_offset_values(n, dist, PX, C);
+ for (i = 0; i < n; dist[i] *= baseSize, i++)
+ ;
+ do
+ {
+ read_chunk(chunk_no, C, &(a_chunk[4]), srcfd, n, baseSize, PX, dist);
+ write_chunk((struct varlena *) a_chunk, destfd);
+ } while (next_tuple(n, chunk_no, max_chunks) != -1);
}
/*--------------------------------------------------------------------------
* read_chunk
- * reads a chunk from the input files into a_chunk, the position of the
- * chunk is specified by chunk_no
+ * reads a chunk from the input files into a_chunk, the position of the
+ * chunk is specified by chunk_no
*--------------------------------------------------------------------------
*/
static void
read_chunk(int chunk_no[],
- int C[],
- char a_chunk[],
- int srcfd,
- int n,
- int baseSize,
- int PX[],
- int dist[])
+ int C[],
+ char a_chunk[],
+ int srcfd,
+ int n,
+ int baseSize,
+ int PX[],
+ int dist[])
{
- int i, j, cp, unit_transfer;
- int start_pos, pos[MAXDIM];
- int indx[MAXDIM];
- int fpOff;
-
- for ( i = start_pos = 0; i < n; i++) {
- pos[i] = chunk_no[i] * C[i];
- start_pos += pos[i]*PX[i];
- }
- start_pos *= baseSize;
-
- /* Read a block of dimesion C starting at co-ordinates pos */
- unit_transfer = C[n-1] * baseSize;
-
- for (i = 0; i < n; indx[i++] = 0)
- ;
- fpOff = start_pos;
- seek_and_read(fpOff, unit_transfer, a_chunk, srcfd, SEEK_SET);
- fpOff += unit_transfer;
- cp = unit_transfer;
-
- while ((j = next_tuple(n-1, indx, C)) != -1) {
- fpOff += dist[j];
- seek_and_read(fpOff, unit_transfer, &(a_chunk[cp]), srcfd, SEEK_SET);
- cp += unit_transfer;
- fpOff += unit_transfer;
- }
+ int i,
+ j,
+ cp,
+ unit_transfer;
+ int start_pos,
+ pos[MAXDIM];
+ int indx[MAXDIM];
+ int fpOff;
+
+ for (i = start_pos = 0; i < n; i++)
+ {
+ pos[i] = chunk_no[i] * C[i];
+ start_pos += pos[i] * PX[i];
+ }
+ start_pos *= baseSize;
+
+ /* Read a block of dimesion C starting at co-ordinates pos */
+ unit_transfer = C[n - 1] * baseSize;
+
+ for (i = 0; i < n; indx[i++] = 0)
+ ;
+ fpOff = start_pos;
+ seek_and_read(fpOff, unit_transfer, a_chunk, srcfd, SEEK_SET);
+ fpOff += unit_transfer;
+ cp = unit_transfer;
+
+ while ((j = next_tuple(n - 1, indx, C)) != -1)
+ {
+ fpOff += dist[j];
+ seek_and_read(fpOff, unit_transfer, &(a_chunk[cp]), srcfd, SEEK_SET);
+ cp += unit_transfer;
+ fpOff += unit_transfer;
+ }
}
/*--------------------------------------------------------------------------
* write_chunk()
- * writes a chunk of size csize into the output file
+ * writes a chunk of size csize into the output file
*--------------------------------------------------------------------------
*/
static int
write_chunk(struct varlena * a_chunk, int ofile)
{
- int got_n = 0;
+ int got_n = 0;
+
#ifdef LOARRAY
- got_n = LOwrite (ofile, a_chunk);
+ got_n = LOwrite(ofile, a_chunk);
#endif
- return(got_n);
+ return (got_n);
}
/*--------------------------------------------------------------------------
* seek_and_read()
- * seeks to the asked location in the input file and reads the
- * appropriate number of blocks
- * Called By: read_chunk()
+ * seeks to the asked location in the input file and reads the
+ * appropriate number of blocks
+ * Called By: read_chunk()
*--------------------------------------------------------------------------
*/
static int
seek_and_read(int pos, int size, char buff[], int fp, int from)
{
- struct varlena *v = NULL;
-
- /* Assuming only one file */
- if ( lo_lseek(fp, pos, from ) < 0)
- elog(WARN, "File seek error");
+ struct varlena *v = NULL;
+
+ /* Assuming only one file */
+ if (lo_lseek(fp, pos, from) < 0)
+ elog(WARN, "File seek error");
#ifdef LOARRAY
- v = (struct varlena *) LOread(fp, size);
+ v = (struct varlena *) LOread(fp, size);
#endif
- if (VARSIZE(v) - 4 < size)
- elog(WARN, "File read error");
- memmove(buff, VARDATA(v), size);
- pfree(v);
- return(1);
-
+ if (VARSIZE(v) - 4 < size)
+ elog(WARN, "File read error");
+ memmove(buff, VARDATA(v), size);
+ pfree(v);
+ return (1);
+
}
-#endif /* LOARRAY */
+
+#endif /* LOARRAY */
/*----------------------------------------------------------------------------
* _ReadChunkArray --
- * returns the subarray specified bu the range indices "st" and "endp"
- * from the chunked array stored in file "fp"
+ * returns the subarray specified bu the range indices "st" and "endp"
+ * from the chunked array stored in file "fp"
*---------------------------------------------------------------------------
*/
int
_ReadChunkArray(int st[],
- int endp[],
- int bsize,
- int fp,
- char *destfp,
- ArrayType *array,
- int isDestLO,
- bool *isNull)
+ int endp[],
+ int bsize,
+ int fp,
+ char *destfp,
+ ArrayType * array,
+ int isDestLO,
+ bool * isNull)
{
- int i,j,jj;
- int n, temp, words_read;
- int chunk_span[MAXDIM], chunk_off[MAXDIM];
- int chunk_st[MAXDIM], chunk_end[MAXDIM];
- int block_seek;
-
- int bptr, *C, csize, *dim, *lb;
- int range_st[MAXDIM], range_end[MAXDIM],
- range[MAXDIM], array_span[MAXDIM];
- int PA[MAXDIM], PCHUNK[MAXDIM], PC[MAXDIM];
- int to_read;
- int cdist[MAXDIM], adist[MAXDIM];
- int dist[MAXDIM], temp_seek;
-
- int srcOff; /* Needed since LO don't understand SEEK_CUR*/
- char *baseDestFp = (char *)destfp;
-
- CHUNK_INFO *A = (CHUNK_INFO *) ARR_DATA_PTR(array);
- n = ARR_NDIM(array);
- dim = ARR_DIMS(array);
- lb = ARR_LBOUND(array);
- C = A->C;
-
- csize = C[n-1];
- PC[n-1] = 1;
- temp = dim[n - 1]/C[n-1];
- for (i = n-2; i >= 0; i--){
- PC[i] = PC[i+1] * temp;
- temp = dim[i] / C[i];
- csize *= C[i];
- }
-
- for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++)
- ;
- mda_get_prod(n, C, PCHUNK);
- mda_get_range(n, array_span, st, endp);
- mda_get_prod(n, array_span, PA);
-
- array2chunk_coord(n, C, st, chunk_st);
- array2chunk_coord(n, C, endp, chunk_end);
- mda_get_range(n, chunk_span, chunk_st, chunk_end);
- mda_get_offset_values(n, dist, PC, chunk_span);
-
- for (i = 0; i < n; i++) {
- range_st[i] = st[i];
- range_end[i] = min(chunk_st[i]*C[i]+C[i]-1, endp[i]);
- }
-
- for (i = j = 0; i < n; i++)
- j+= chunk_st[i]*PC[i];
- temp_seek = srcOff = j * csize * bsize;
- if (lo_lseek(fp, srcOff, SEEK_SET) < 0) RETURN_NULL;
-
- jj = n-1;
- for (i = 0; i < n; chunk_off[i++] = 0)
- ;
- words_read = 0; temp_seek = 0;
- do {
- /* Write chunk (chunk_st) to output buffer */
- mda_get_range(n, array_span, range_st, range_end);
- mda_get_offset_values(n, adist, PA, array_span);
- mda_get_offset_values(n, cdist, PCHUNK, array_span);
- for (i=0; i < n; range[i] = range_st[i]-st[i], i++);
- bptr = tuple2linear(n, range, PA);
- for (i = 0; i < n; range[i++] = 0);
- j = n-1; bptr *= bsize;
- if (isDestLO) {
- if (lo_lseek((int)destfp, bptr, SEEK_SET) < 0)
- RETURN_NULL;
- }
- else
- destfp = baseDestFp + bptr;
- for(i = 0, block_seek = 0; i < n; i++)
- block_seek += (range_st[i]-(chunk_st[i] + chunk_off[i])
- *C[i])*PCHUNK[i];
- if (dist[jj] + block_seek + temp_seek) {
- temp = (dist[jj]*csize+block_seek+temp_seek)*bsize;
- srcOff += temp;
- if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
- RETURN_NULL;
- }
- for (i = n-1, to_read = bsize; i >= 0;
- to_read *= min(C[i], array_span[i]), i--)
- if (cdist[i] || adist[i])
- break;
- do {
- if (cdist[j]) {
- srcOff += (cdist[j]*bsize);
- if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
- RETURN_NULL;
- }
- block_seek += cdist[j];
- bptr += adist[j]*bsize;
- if (isDestLO) {
- if (lo_lseek((int)destfp, bptr, SEEK_SET) < 0)
- RETURN_NULL;
- }
- else
- destfp = baseDestFp + bptr;
- temp = _LOtransfer ((char**)&destfp, to_read, 1, (char**)&fp, 1, isDestLO);
- if (temp < to_read)
+ int i,
+ j,
+ jj;
+ int n,
+ temp,
+ words_read;
+ int chunk_span[MAXDIM],
+ chunk_off[MAXDIM];
+ int chunk_st[MAXDIM],
+ chunk_end[MAXDIM];
+ int block_seek;
+
+ int bptr,
+ *C,
+ csize,
+ *dim,
+ *lb;
+ int range_st[MAXDIM],
+ range_end[MAXDIM],
+ range[MAXDIM],
+ array_span[MAXDIM];
+ int PA[MAXDIM],
+ PCHUNK[MAXDIM],
+ PC[MAXDIM];
+ int to_read;
+ int cdist[MAXDIM],
+ adist[MAXDIM];
+ int dist[MAXDIM],
+ temp_seek;
+
+ int srcOff; /* Needed since LO don't understand
+ * SEEK_CUR */
+ char *baseDestFp = (char *) destfp;
+
+ CHUNK_INFO *A = (CHUNK_INFO *) ARR_DATA_PTR(array);
+
+ n = ARR_NDIM(array);
+ dim = ARR_DIMS(array);
+ lb = ARR_LBOUND(array);
+ C = A->C;
+
+ csize = C[n - 1];
+ PC[n - 1] = 1;
+ temp = dim[n - 1] / C[n - 1];
+ for (i = n - 2; i >= 0; i--)
+ {
+ PC[i] = PC[i + 1] * temp;
+ temp = dim[i] / C[i];
+ csize *= C[i];
+ }
+
+ for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++)
+ ;
+ mda_get_prod(n, C, PCHUNK);
+ mda_get_range(n, array_span, st, endp);
+ mda_get_prod(n, array_span, PA);
+
+ array2chunk_coord(n, C, st, chunk_st);
+ array2chunk_coord(n, C, endp, chunk_end);
+ mda_get_range(n, chunk_span, chunk_st, chunk_end);
+ mda_get_offset_values(n, dist, PC, chunk_span);
+
+ for (i = 0; i < n; i++)
+ {
+ range_st[i] = st[i];
+ range_end[i] = min(chunk_st[i] * C[i] + C[i] - 1, endp[i]);
+ }
+
+ for (i = j = 0; i < n; i++)
+ j += chunk_st[i] * PC[i];
+ temp_seek = srcOff = j * csize * bsize;
+ if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
RETURN_NULL;
- srcOff += to_read;
- words_read+=to_read;
- bptr += to_read;
- block_seek += (to_read/bsize);
- /*
- * compute next tuple in range[]
- */
- {
- int x;
- if (!(i+1))
- j = -1;
- else {
- range[i] = (range[i]+1)%array_span[i];
- for (x = i; x*(!range[x]); x--)
- range[x-1] = (range[x-1]+1)%array_span[x-1];
- if (x)
- j = x;
- else {
- if (range[0])
- j = 0;
- else
- j = -1;
- }
- }
- }
- /*
- * end of compute next tuple --
- * j is set to -1 if tuple generation is over
- */
- } while (j != -1);
-
- block_seek = csize - block_seek;
- temp_seek = block_seek;
- jj = next_tuple(n, chunk_off, chunk_span);
- if (jj == -1)
- break;
- range_st[jj] = (chunk_st[jj]+chunk_off[jj])*C[jj];
- range_end[jj] = min(range_st[jj] + C[jj]-1, endp[jj]);
-
- for (i = jj+1; i < n; i++) {
- range_st[i] = st[i];
- range_end[i] = min((chunk_st[i]+chunk_off[i])*C[i]+C[i]-1, endp[i]);
- }
- } while (jj != -1);
- return(words_read);
+
+ jj = n - 1;
+ for (i = 0; i < n; chunk_off[i++] = 0)
+ ;
+ words_read = 0;
+ temp_seek = 0;
+ do
+ {
+ /* Write chunk (chunk_st) to output buffer */
+ mda_get_range(n, array_span, range_st, range_end);
+ mda_get_offset_values(n, adist, PA, array_span);
+ mda_get_offset_values(n, cdist, PCHUNK, array_span);
+ for (i = 0; i < n; range[i] = range_st[i] - st[i], i++);
+ bptr = tuple2linear(n, range, PA);
+ for (i = 0; i < n; range[i++] = 0);
+ j = n - 1;
+ bptr *= bsize;
+ if (isDestLO)
+ {
+ if (lo_lseek((int) destfp, bptr, SEEK_SET) < 0)
+ RETURN_NULL;
+ }
+ else
+ destfp = baseDestFp + bptr;
+ for (i = 0, block_seek = 0; i < n; i++)
+ block_seek += (range_st[i] - (chunk_st[i] + chunk_off[i])
+ * C[i]) * PCHUNK[i];
+ if (dist[jj] + block_seek + temp_seek)
+ {
+ temp = (dist[jj] * csize + block_seek + temp_seek) * bsize;
+ srcOff += temp;
+ if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
+ RETURN_NULL;
+ }
+ for (i = n - 1, to_read = bsize; i >= 0;
+ to_read *= min(C[i], array_span[i]), i--)
+ if (cdist[i] || adist[i])
+ break;
+ do
+ {
+ if (cdist[j])
+ {
+ srcOff += (cdist[j] * bsize);
+ if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
+ RETURN_NULL;
+ }
+ block_seek += cdist[j];
+ bptr += adist[j] * bsize;
+ if (isDestLO)
+ {
+ if (lo_lseek((int) destfp, bptr, SEEK_SET) < 0)
+ RETURN_NULL;
+ }
+ else
+ destfp = baseDestFp + bptr;
+ temp = _LOtransfer((char **) &destfp, to_read, 1, (char **) &fp, 1, isDestLO);
+ if (temp < to_read)
+ RETURN_NULL;
+ srcOff += to_read;
+ words_read += to_read;
+ bptr += to_read;
+ block_seek += (to_read / bsize);
+
+ /*
+ * compute next tuple in range[]
+ */
+ {
+ int x;
+
+ if (!(i + 1))
+ j = -1;
+ else
+ {
+ range[i] = (range[i] + 1) % array_span[i];
+ for (x = i; x * (!range[x]); x--)
+ range[x - 1] = (range[x - 1] + 1) % array_span[x - 1];
+ if (x)
+ j = x;
+ else
+ {
+ if (range[0])
+ j = 0;
+ else
+ j = -1;
+ }
+ }
+ }
+
+ /*
+ * end of compute next tuple -- j is set to -1 if tuple
+ * generation is over
+ */
+ } while (j != -1);
+
+ block_seek = csize - block_seek;
+ temp_seek = block_seek;
+ jj = next_tuple(n, chunk_off, chunk_span);
+ if (jj == -1)
+ break;
+ range_st[jj] = (chunk_st[jj] + chunk_off[jj]) * C[jj];
+ range_end[jj] = min(range_st[jj] + C[jj] - 1, endp[jj]);
+
+ for (i = jj + 1; i < n; i++)
+ {
+ range_st[i] = st[i];
+ range_end[i] = min((chunk_st[i] + chunk_off[i]) * C[i] + C[i] - 1, endp[i]);
+ }
+ } while (jj != -1);
+ return (words_read);
}
/*------------------------------------------------------------------------
* _ReadChunkArray1El --
- * returns one element of the chunked array as specified by the index "st"
- * the chunked file descriptor is "fp"
+ * returns one element of the chunked array as specified by the index "st"
+ * the chunked file descriptor is "fp"
*-------------------------------------------------------------------------
*/
struct varlena *
_ReadChunkArray1El(int st[],
- int bsize,
- int fp,
- ArrayType *array,
- bool *isNull)
+ int bsize,
+ int fp,
+ ArrayType * array,
+ bool * isNull)
{
- int i, j, n, temp, srcOff;
- int chunk_st[MAXDIM];
-
- int *C, csize, *dim, *lb;
- int PCHUNK[MAXDIM], PC[MAXDIM];
-
- CHUNK_INFO *A = (CHUNK_INFO *) ARR_DATA_PTR(array);
-
- n = ARR_NDIM(array);
- lb = ARR_LBOUND(array);
- C = A->C;
- dim = ARR_DIMS(array);
-
- csize = C[n-1];
- PC[n-1] = 1;
- temp = dim[n - 1]/C[n-1];
- for (i = n-2; i >= 0; i--){
- PC[i] = PC[i+1] * temp;
- temp = dim[i] / C[i];
- csize *= C[i];
- }
-
- for (i = 0; i < n; st[i] -= lb[i], i++);
- mda_get_prod(n, C, PCHUNK);
-
- array2chunk_coord(n, C, st, chunk_st);
-
- for (i = j = 0; i < n; i++)
- j+= chunk_st[i]*PC[i];
- srcOff = j * csize;
-
- for(i = 0; i < n; i++)
- srcOff += (st[i]-chunk_st[i]*C[i])*PCHUNK[i];
-
- srcOff *= bsize;
- if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
- RETURN_NULL;
+ int i,
+ j,
+ n,
+ temp,
+ srcOff;
+ int chunk_st[MAXDIM];
+
+ int *C,
+ csize,
+ *dim,
+ *lb;
+ int PCHUNK[MAXDIM],
+ PC[MAXDIM];
+
+ CHUNK_INFO *A = (CHUNK_INFO *) ARR_DATA_PTR(array);
+
+ n = ARR_NDIM(array);
+ lb = ARR_LBOUND(array);
+ C = A->C;
+ dim = ARR_DIMS(array);
+
+ csize = C[n - 1];
+ PC[n - 1] = 1;
+ temp = dim[n - 1] / C[n - 1];
+ for (i = n - 2; i >= 0; i--)
+ {
+ PC[i] = PC[i + 1] * temp;
+ temp = dim[i] / C[i];
+ csize *= C[i];
+ }
+
+ for (i = 0; i < n; st[i] -= lb[i], i++);
+ mda_get_prod(n, C, PCHUNK);
+
+ array2chunk_coord(n, C, st, chunk_st);
+
+ for (i = j = 0; i < n; i++)
+ j += chunk_st[i] * PC[i];
+ srcOff = j * csize;
+
+ for (i = 0; i < n; i++)
+ srcOff += (st[i] - chunk_st[i] * C[i]) * PCHUNK[i];
+
+ srcOff *= bsize;
+ if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
+ RETURN_NULL;
#ifdef LOARRAY
- return (struct varlena *) LOread(fp, bsize);
+ return (struct varlena *) LOread(fp, bsize);
#endif
- return (struct varlena *) 0;
+ return (struct varlena *) 0;
}
-
diff --git a/src/backend/utils/adt/date.c b/src/backend/utils/adt/date.c
index d86bc29429a..40369f9a84e 100644
--- a/src/backend/utils/adt/date.c
+++ b/src/backend/utils/adt/date.c
@@ -1,25 +1,25 @@
/*-------------------------------------------------------------------------
*
* date.c--
- * Utilities for the built-in type "AbsoluteTime" (defined in nabstime).
- * Functions for the built-in type "RelativeTime".
- * Functions for the built-in type "TimeInterval".
+ * Utilities for the built-in type "AbsoluteTime" (defined in nabstime).
+ * Functions for the built-in type "RelativeTime".
+ * Functions for the built-in type "TimeInterval".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.14 1997/09/05 18:11:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.15 1997/09/07 04:50:06 momjian Exp $
*
* NOTES
- * This code is actually (almost) unused.
- * It needs to be integrated with Time and struct trange.
+ * This code is actually (almost) unused.
+ * It needs to be integrated with Time and struct trange.
*
* XXX This code needs to be rewritten to work with the "new" definitions
* XXX in h/tim.h. Look for int32's, int, long, etc. in the code. The
* XXX definitions in h/tim.h may need to be rethought also.
*
- * XXX This code has been cleaned up some - avi 07/07/93
+ * XXX This code has been cleaned up some - avi 07/07/93
*
*-------------------------------------------------------------------------
*/
@@ -33,910 +33,1017 @@
#include "postgres.h"
#include "miscadmin.h"
#ifdef HAVE_FLOAT_H
-# include <float.h>
+#include <float.h>
#endif
#ifdef HAVE_LIMITS_H
-# include <limits.h>
+#include <limits.h>
#endif
#include "access/xact.h"
-#include "utils/builtins.h" /* where function declarations go */
+#include "utils/builtins.h" /* where function declarations go */
#include "utils/palloc.h"
#include "utils/dt.h"
-#define INVALID_RELTIME_STR "Undefined RelTime"
-#define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
-#define RELTIME_LABEL '@'
-#define RELTIME_PAST "ago"
-#define DIRMAXLEN (sizeof(RELTIME_PAST)-1)
+#define INVALID_RELTIME_STR "Undefined RelTime"
+#define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
+#define RELTIME_LABEL '@'
+#define RELTIME_PAST "ago"
+#define DIRMAXLEN (sizeof(RELTIME_PAST)-1)
/*
- * Unix epoch is Jan 1 00:00:00 1970. Postgres knows about times
- * sixty-eight years on either side of that.
- */
+ * Unix epoch is Jan 1 00:00:00 1970. Postgres knows about times
+ * sixty-eight years on either side of that.
+ */
-#define IsSpace(C) ((C) == ' ')
+#define IsSpace(C) ((C) == ' ')
-#define T_INTERVAL_INVAL 0 /* data represents no valid interval */
-#define T_INTERVAL_VALID 1 /* data represents a valid interval */
+#define T_INTERVAL_INVAL 0 /* data represents no valid interval */
+#define T_INTERVAL_VALID 1 /* data represents a valid interval */
/*
* ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
- * 0 1 2 3 4 5 6
+ * 0 1 2 3 4 5 6
* 1234567890123456789012345678901234567890123456789012345678901234
*
* we allocate some extra -- timezones are usually 3 characters but
* this is not in the POSIX standard...
*/
-#define T_INTERVAL_LEN 80
-#define INVALID_INTERVAL_STR "Undefined Range"
-#define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1)
+#define T_INTERVAL_LEN 80
+#define INVALID_INTERVAL_STR "Undefined Range"
+#define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1)
#define ABSTIMEMIN(t1, t2) abstimele((t1),(t2)) ? (t1) : (t2)
#define ABSTIMEMAX(t1, t2) abstimelt((t1),(t2)) ? (t2) : (t1)
#if FALSE
-static char *unit_tab[] = {
+static char *unit_tab[] = {
"second", "seconds", "minute", "minutes",
"hour", "hours", "day", "days", "week", "weeks",
- "month", "months", "year", "years"};
-#define UNITMAXLEN 7 /* max length of a unit name */
-#define NUNITS 14 /* number of different units */
+"month", "months", "year", "years"};
+
+#define UNITMAXLEN 7 /* max length of a unit name */
+#define NUNITS 14 /* number of different units */
/* table of seconds per unit (month = 30 days, year = 365 days) */
-static int sec_tab[] = {
- 1,1, 60, 60,
- 3600, 3600, 86400, 86400, 604800, 604800,
- 2592000, 2592000, 31536000, 31536000 };
+static int sec_tab[] = {
+ 1, 1, 60, 60,
+ 3600, 3600, 86400, 86400, 604800, 604800,
+2592000, 2592000, 31536000, 31536000};
+
#endif
/*
* Function prototypes -- internal to this file only
*/
-static void reltime2tm(int32 time, struct tm *tm);
+static void reltime2tm(int32 time, struct tm * tm);
#if FALSE
-static int correct_unit(char unit[], int *unptr);
-static int correct_dir(char direction[], int *signptr);
+static int correct_unit(char unit[], int *unptr);
+static int correct_dir(char direction[], int *signptr);
+
#endif
-static int istinterval(char *i_string,
- AbsoluteTime *i_start,
- AbsoluteTime *i_end);
+static int
+istinterval(char *i_string,
+ AbsoluteTime * i_start,
+ AbsoluteTime * i_end);
-/*****************************************************************************
- * USER I/O ROUTINES *
+/*****************************************************************************
+ * USER I/O ROUTINES *
*****************************************************************************/
/*
- * reltimein - converts a reltime string in an internal format
+ * reltimein - converts a reltime string in an internal format
*/
RelativeTime
reltimein(char *str)
{
- RelativeTime result;
+ RelativeTime result;
- struct tm tt, *tm = &tt;
- double fsec;
- int dtype;
- char *field[MAXDATEFIELDS];
- int nf, ftype[MAXDATEFIELDS];
- char lowstr[MAXDATELEN+1];
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
+ int dtype;
+ char *field[MAXDATEFIELDS];
+ int nf,
+ ftype[MAXDATEFIELDS];
+ char lowstr[MAXDATELEN + 1];
- if (!PointerIsValid(str))
- elog(WARN,"Bad (null) date external representation",NULL);
+ if (!PointerIsValid(str))
+ elog(WARN, "Bad (null) date external representation", NULL);
- if (strlen(str) > MAXDATELEN)
- elog( WARN, "Bad (length) reltime external representation '%s'",str);
+ if (strlen(str) > MAXDATELEN)
+ elog(WARN, "Bad (length) reltime external representation '%s'", str);
- if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateDelta( field, ftype, nf, &dtype, tm, &fsec) != 0))
- elog(WARN,"Bad reltime external representation '%s'",str);
+ if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
+ elog(WARN, "Bad reltime external representation '%s'", str);
#ifdef DATEDEBUG
-printf( "reltimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE);
+ printf("reltimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE);
#endif
- switch (dtype) {
- case DTK_DELTA:
- result = ((((tm->tm_hour*60)+tm->tm_min)*60)+tm->tm_sec);
- result += (((tm->tm_year*365)+(tm->tm_mon*30)+tm->tm_mday)*(24*60*60));
- return(result);
+ switch (dtype)
+ {
+ case DTK_DELTA:
+ result = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec);
+ result += (((tm->tm_year * 365) + (tm->tm_mon * 30) + tm->tm_mday) * (24 * 60 * 60));
+ return (result);
- default:
- return(INVALID_RELTIME);
- }
+ default:
+ return (INVALID_RELTIME);
+ }
- elog(WARN,"Bad reltime (internal coding error) '%s'",str);
- return(INVALID_RELTIME);
-} /* reltimein() */
+ elog(WARN, "Bad reltime (internal coding error) '%s'", str);
+ return (INVALID_RELTIME);
+} /* reltimein() */
/*
- * reltimeout - converts the internal format to a reltime string
+ * reltimeout - converts the internal format to a reltime string
*/
-char *reltimeout(int32 time)
+char *
+reltimeout(int32 time)
{
- char *result;
- struct tm tt, *tm = &tt;
- char buf[MAXDATELEN+1];
+ char *result;
+ struct tm tt,
+ *tm = &tt;
+ char buf[MAXDATELEN + 1];
- if (time == INVALID_RELTIME) {
- strcpy( buf, INVALID_RELTIME_STR);
+ if (time == INVALID_RELTIME)
+ {
+ strcpy(buf, INVALID_RELTIME_STR);
- } else {
- reltime2tm(time, tm);
- EncodeTimeSpan( tm, 0, DateStyle, buf);
- }
+ }
+ else
+ {
+ reltime2tm(time, tm);
+ EncodeTimeSpan(tm, 0, DateStyle, buf);
+ }
- result = PALLOC(strlen(buf)+1);
- strcpy( result, buf);
+ result = PALLOC(strlen(buf) + 1);
+ strcpy(result, buf);
- return(result);
-} /* reltimeout() */
+ return (result);
+} /* reltimeout() */
#define TMODULO(t,q,u) {q = (t / u); \
- if (q != 0) t -= (q * u);}
+ if (q != 0) t -= (q * u);}
static void
-reltime2tm(int32 time, struct tm *tm)
+reltime2tm(int32 time, struct tm * tm)
{
- TMODULO(time, tm->tm_year, 31536000);
- TMODULO(time, tm->tm_mon, 2592000);
- TMODULO(time, tm->tm_mday, 86400);
- TMODULO(time, tm->tm_hour, 3600);
- TMODULO(time, tm->tm_min, 60);
- TMODULO(time, tm->tm_sec, 1);
+ TMODULO(time, tm->tm_year, 31536000);
+ TMODULO(time, tm->tm_mon, 2592000);
+ TMODULO(time, tm->tm_mday, 86400);
+ TMODULO(time, tm->tm_hour, 3600);
+ TMODULO(time, tm->tm_min, 60);
+ TMODULO(time, tm->tm_sec, 1);
- return;
-} /* reltime2tm() */
+ return;
+} /* reltime2tm() */
#if FALSE
- char *timestring;
- long quantity;
- register int i;
- int unitnr;
-
- timestring = (char *) palloc(Max(strlen(INVALID_RELTIME_STR),
- UNITMAXLEN) + 1);
- if (timevalue == INVALID_RELTIME) {
- strcpy(timestring,INVALID_RELTIME_STR);
- return(timestring);
- }
- if (timevalue == 0)
- i = 1; /* unit = 'seconds' */
- else
- for (i = 12; i >= 0; i = i-2)
- if ((timevalue % sec_tab[i]) == 0)
- break; /* appropriate unit found */
- unitnr = i;
- quantity = (timevalue / sec_tab[unitnr]);
- if (quantity > 1 || quantity < -1)
- unitnr++; /* adjust index for PLURAL of unit */
- if (quantity >= 0)
- sprintf( timestring, "%c %lu %s", RELTIME_LABEL,
- quantity, unit_tab[unitnr]);
- else
- sprintf( timestring, "%c %lu %s %s", RELTIME_LABEL,
- (quantity * -1), unit_tab[unitnr], RELTIME_PAST);
- return(timestring);
+char *timestring;
+long quantity;
+register int i;
+int unitnr;
+
+timestring = (char *) palloc(Max(strlen(INVALID_RELTIME_STR),
+ UNITMAXLEN) + 1);
+if (timevalue == INVALID_RELTIME)
+{
+ strcpy(timestring, INVALID_RELTIME_STR);
+ return (timestring);
+}
+
+if (timevalue == 0)
+ i = 1; /* unit = 'seconds' */
+else
+ for (i = 12; i >= 0; i = i - 2)
+ if ((timevalue % sec_tab[i]) == 0)
+ break; /* appropriate unit found */
+unitnr = i;
+quantity = (timevalue / sec_tab[unitnr]);
+if (quantity > 1 || quantity < -1)
+ unitnr++; /* adjust index for PLURAL of unit */
+if (quantity >= 0)
+ sprintf(timestring, "%c %lu %s", RELTIME_LABEL,
+ quantity, unit_tab[unitnr]);
+else
+ sprintf(timestring, "%c %lu %s %s", RELTIME_LABEL,
+ (quantity * -1), unit_tab[unitnr], RELTIME_PAST);
+return (timestring);
}
+
#endif
/*
- * tintervalin - converts an interval string to an internal format
+ * tintervalin - converts an interval string to an internal format
*/
-TimeInterval tintervalin(char *intervalstr)
-{
- int error;
- AbsoluteTime i_start, i_end, t1, t2;
- TimeInterval interval;
-
- interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
- error = istinterval(intervalstr, &t1, &t2);
- if (error == 0)
- interval->status = T_INTERVAL_INVAL;
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- interval->status = T_INTERVAL_INVAL; /* undefined */
- else {
- i_start = ABSTIMEMIN(t1, t2);
- i_end = ABSTIMEMAX(t1, t2);
- interval->data[0] = i_start;
- interval->data[1] = i_end;
- interval->status = T_INTERVAL_VALID;
- }
- return(interval);
+TimeInterval
+tintervalin(char *intervalstr)
+{
+ int error;
+ AbsoluteTime i_start,
+ i_end,
+ t1,
+ t2;
+ TimeInterval interval;
+
+ interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
+ error = istinterval(intervalstr, &t1, &t2);
+ if (error == 0)
+ interval->status = T_INTERVAL_INVAL;
+ if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
+ interval->status = T_INTERVAL_INVAL; /* undefined */
+ else
+ {
+ i_start = ABSTIMEMIN(t1, t2);
+ i_end = ABSTIMEMAX(t1, t2);
+ interval->data[0] = i_start;
+ interval->data[1] = i_end;
+ interval->status = T_INTERVAL_VALID;
+ }
+ return (interval);
}
/*
- * tintervalout - converts an internal interval format to a string
+ * tintervalout - converts an internal interval format to a string
*
*/
-char *tintervalout(TimeInterval interval)
-{
- char *i_str, *p;
-
- i_str = (char *) palloc( T_INTERVAL_LEN ); /* ['...' '...'] */
- strcpy(i_str,"[\"");
- if (interval->status == T_INTERVAL_INVAL)
- strcat(i_str,INVALID_INTERVAL_STR);
- else {
- p = nabstimeout(interval->data[0]);
- strcat(i_str,p);
- pfree(p);
- strcat(i_str,"\" \"");
- p = nabstimeout(interval->data[1]);
- strcat(i_str,p);
- pfree(p);
- }
- strcat(i_str,"\"]\0");
- return(i_str);
-}
-
-
-/*****************************************************************************
- * PUBLIC ROUTINES *
+char *
+tintervalout(TimeInterval interval)
+{
+ char *i_str,
+ *p;
+
+ i_str = (char *) palloc(T_INTERVAL_LEN); /* ['...' '...'] */
+ strcpy(i_str, "[\"");
+ if (interval->status == T_INTERVAL_INVAL)
+ strcat(i_str, INVALID_INTERVAL_STR);
+ else
+ {
+ p = nabstimeout(interval->data[0]);
+ strcat(i_str, p);
+ pfree(p);
+ strcat(i_str, "\" \"");
+ p = nabstimeout(interval->data[1]);
+ strcat(i_str, p);
+ pfree(p);
+ }
+ strcat(i_str, "\"]\0");
+ return (i_str);
+}
+
+
+/*****************************************************************************
+ * PUBLIC ROUTINES *
*****************************************************************************/
RelativeTime
-timespan_reltime(TimeSpan *timespan)
+timespan_reltime(TimeSpan * timespan)
{
- RelativeTime time;
- int year, month;
- double span;
+ RelativeTime time;
+ int year,
+ month;
+ double span;
- if (!PointerIsValid(timespan))
- time = INVALID_RELTIME;
+ if (!PointerIsValid(timespan))
+ time = INVALID_RELTIME;
- if (TIMESPAN_IS_INVALID(*timespan)) {
- time = INVALID_RELTIME;
+ if (TIMESPAN_IS_INVALID(*timespan))
+ {
+ time = INVALID_RELTIME;
- } else {
- if (timespan->month == 0) {
- year = 0;
- month = 0;
+ }
+ else
+ {
+ if (timespan->month == 0)
+ {
+ year = 0;
+ month = 0;
- } else if (abs(timespan->month) >= 12) {
- year = (timespan->month / 12);
- month = (timespan->month % 12);
+ }
+ else if (abs(timespan->month) >= 12)
+ {
+ year = (timespan->month / 12);
+ month = (timespan->month % 12);
- } else {
- year = 0;
- month = timespan->month;
- }
+ }
+ else
+ {
+ year = 0;
+ month = timespan->month;
+ }
- span = (((((double) 365*year)+((double) 30*month))*86400) + timespan->time);
+ span = (((((double) 365 * year) + ((double) 30 * month)) * 86400) + timespan->time);
#ifdef DATEDEBUG
-printf( "timespan_reltime- convert m%d s%f to %f [%d %d]\n",
- timespan->month, timespan->time, span, INT_MIN, INT_MAX);
+ printf("timespan_reltime- convert m%d s%f to %f [%d %d]\n",
+ timespan->month, timespan->time, span, INT_MIN, INT_MAX);
#endif
- time = (((span > INT_MIN) && (span < INT_MAX))? span: INVALID_RELTIME);
- }
+ time = (((span > INT_MIN) && (span < INT_MAX)) ? span : INVALID_RELTIME);
+ }
- return(time);
-} /* timespan_reltime() */
+ return (time);
+} /* timespan_reltime() */
-TimeSpan *
+TimeSpan *
reltime_timespan(RelativeTime reltime)
{
- TimeSpan *result;
- int year, month;
+ TimeSpan *result;
+ int year,
+ month;
- if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
- elog(WARN,"Memory allocation failed, can't convert reltime to timespan",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
+ elog(WARN, "Memory allocation failed, can't convert reltime to timespan", NULL);
- switch(reltime) {
- case INVALID_RELTIME:
- TIMESPAN_INVALID(*result);
- break;
+ switch (reltime)
+ {
+ case INVALID_RELTIME:
+ TIMESPAN_INVALID(*result);
+ break;
- default:
- TMODULO(reltime, year, 31536000);
- TMODULO(reltime, month, 2592000);
+ default:
+ TMODULO(reltime, year, 31536000);
+ TMODULO(reltime, month, 2592000);
- result->time = reltime;
- result->month = ((12*year)+month);
- }
+ result->time = reltime;
+ result->month = ((12 * year) + month);
+ }
- return(result);
-} /* reltime_timespan() */
+ return (result);
+} /* reltime_timespan() */
/*
- * mktinterval - creates a time interval with endpoints t1 and t2
+ * mktinterval - creates a time interval with endpoints t1 and t2
*/
-TimeInterval mktinterval(AbsoluteTime t1, AbsoluteTime t2)
+TimeInterval
+mktinterval(AbsoluteTime t1, AbsoluteTime t2)
{
- AbsoluteTime tstart = ABSTIMEMIN(t1, t2), tend = ABSTIMEMAX(t1, t2);
- TimeInterval interval;
-
- interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- interval->status = T_INTERVAL_INVAL;
- else {
- interval->status = T_INTERVAL_VALID;
- interval->data[0] = tstart;
- interval->data[1] = tend;
- }
-
- return interval;
+ AbsoluteTime tstart = ABSTIMEMIN(t1, t2),
+ tend = ABSTIMEMAX(t1, t2);
+ TimeInterval interval;
+
+ interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
+ if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
+ interval->status = T_INTERVAL_INVAL;
+ else
+ {
+ interval->status = T_INTERVAL_VALID;
+ interval->data[0] = tstart;
+ interval->data[1] = tend;
+ }
+
+ return interval;
}
/*
- * timepl, timemi and abstimemi use the formula
- * abstime + reltime = abstime
- * so abstime - reltime = abstime
- * and abstime - abstime = reltime
+ * timepl, timemi and abstimemi use the formula
+ * abstime + reltime = abstime
+ * so abstime - reltime = abstime
+ * and abstime - abstime = reltime
*/
/*
- * timepl - returns the value of (abstime t1 + relime t2)
+ * timepl - returns the value of (abstime t1 + relime t2)
*/
-AbsoluteTime timepl(AbsoluteTime t1, RelativeTime t2)
+AbsoluteTime
+timepl(AbsoluteTime t1, RelativeTime t2)
{
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
-
- if (AbsoluteTimeIsReal(t1) &&
- RelativeTimeIsValid(t2) &&
- ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
- : (t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
- return (t1 + t2);
-
- return(INVALID_ABSTIME);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+
+ if (AbsoluteTimeIsReal(t1) &&
+ RelativeTimeIsValid(t2) &&
+ ((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
+ : (t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
+ return (t1 + t2);
+
+ return (INVALID_ABSTIME);
}
/*
- * timemi - returns the value of (abstime t1 - reltime t2)
+ * timemi - returns the value of (abstime t1 - reltime t2)
*/
-AbsoluteTime timemi(AbsoluteTime t1, RelativeTime t2)
+AbsoluteTime
+timemi(AbsoluteTime t1, RelativeTime t2)
{
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
-
- if (AbsoluteTimeIsReal(t1) &&
- RelativeTimeIsValid(t2) &&
- ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
- : (t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
- return (t1 - t2);
-
- return(INVALID_ABSTIME);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+
+ if (AbsoluteTimeIsReal(t1) &&
+ RelativeTimeIsValid(t2) &&
+ ((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
+ : (t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
+ return (t1 - t2);
+
+ return (INVALID_ABSTIME);
}
/*
- * abstimemi - returns the value of (abstime t1 - abstime t2)
+ * abstimemi - returns the value of (abstime t1 - abstime t2)
*/
-static RelativeTime abstimemi(AbsoluteTime t1, AbsoluteTime t2)
+static RelativeTime
+abstimemi(AbsoluteTime t1, AbsoluteTime t2)
{
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- if (AbsoluteTimeIsReal(t1) &&
- AbsoluteTimeIsReal(t2))
- return (t1 - t2);
-
- return(INVALID_RELTIME);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+ if (t2 == CURRENT_ABSTIME)
+ t2 = GetCurrentTransactionStartTime();
+
+ if (AbsoluteTimeIsReal(t1) &&
+ AbsoluteTimeIsReal(t2))
+ return (t1 - t2);
+
+ return (INVALID_RELTIME);
}
/*
- * ininterval - returns 1, iff absolute date is in the interval
+ * ininterval - returns 1, iff absolute date is in the interval
*/
-int ininterval(AbsoluteTime t, TimeInterval interval)
+int
+ininterval(AbsoluteTime t, TimeInterval interval)
{
- if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
- return (abstimege(t, interval->data[0]) &&
- abstimele(t, interval->data[1]));
- return(0);
+ if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
+ return (abstimege(t, interval->data[0]) &&
+ abstimele(t, interval->data[1]));
+ return (0);
}
/*
- * intervalrel - returns relative time corresponding to interval
+ * intervalrel - returns relative time corresponding to interval
*/
-RelativeTime intervalrel(TimeInterval interval)
+RelativeTime
+intervalrel(TimeInterval interval)
{
- if (interval->status == T_INTERVAL_VALID)
- return(abstimemi(interval->data[1], interval->data[0]));
- else
- return(INVALID_RELTIME);
+ if (interval->status == T_INTERVAL_VALID)
+ return (abstimemi(interval->data[1], interval->data[0]));
+ else
+ return (INVALID_RELTIME);
}
/*
- * timenow - returns time "now", internal format
+ * timenow - returns time "now", internal format
*
- * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
+ * Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
*/
-AbsoluteTime timenow()
+AbsoluteTime
+timenow()
{
- time_t sec;
- if (time(&sec) < 0)
- return(INVALID_ABSTIME);
- return((AbsoluteTime) sec);
+ time_t sec;
+
+ if (time(&sec) < 0)
+ return (INVALID_ABSTIME);
+ return ((AbsoluteTime) sec);
}
/*
- * reltimeeq - returns 1, iff arguments are equal
- * reltimene - returns 1, iff arguments are not equal
- * reltimelt - returns 1, iff t1 less than t2
- * reltimegt - returns 1, iff t1 greater than t2
- * reltimele - returns 1, iff t1 less than or equal to t2
- * reltimege - returns 1, iff t1 greater than or equal to t2
+ * reltimeeq - returns 1, iff arguments are equal
+ * reltimene - returns 1, iff arguments are not equal
+ * reltimelt - returns 1, iff t1 less than t2
+ * reltimegt - returns 1, iff t1 greater than t2
+ * reltimele - returns 1, iff t1 less than or equal to t2
+ * reltimege - returns 1, iff t1 greater than or equal to t2
*/
-bool reltimeeq(RelativeTime t1, RelativeTime t2)
+bool
+reltimeeq(RelativeTime t1, RelativeTime t2)
{
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- return 0;
- return(t1 == t2);
+ if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
+ return 0;
+ return (t1 == t2);
}
-bool reltimene(RelativeTime t1, RelativeTime t2)
+bool
+reltimene(RelativeTime t1, RelativeTime t2)
{
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- return 0;
- return(t1 != t2);
+ if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
+ return 0;
+ return (t1 != t2);
}
-bool reltimelt(RelativeTime t1, RelativeTime t2)
+bool
+reltimelt(RelativeTime t1, RelativeTime t2)
{
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- return 0;
- return(t1 < t2);
+ if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
+ return 0;
+ return (t1 < t2);
}
-bool reltimegt(RelativeTime t1, RelativeTime t2)
+bool
+reltimegt(RelativeTime t1, RelativeTime t2)
{
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- return 0;
- return(t1 > t2);
+ if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
+ return 0;
+ return (t1 > t2);
}
-bool reltimele(RelativeTime t1, RelativeTime t2)
+bool
+reltimele(RelativeTime t1, RelativeTime t2)
{
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- return 0;
- return(t1 <= t2);
+ if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
+ return 0;
+ return (t1 <= t2);
}
-bool reltimege(RelativeTime t1, RelativeTime t2)
+bool
+reltimege(RelativeTime t1, RelativeTime t2)
{
- if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
- return 0;
- return(t1 >= t2);
+ if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
+ return 0;
+ return (t1 >= t2);
}
/*
- * intervaleq - returns 1, iff interval i1 is equal to interval i2
+ * intervaleq - returns 1, iff interval i1 is equal to interval i2
*/
-bool intervaleq(TimeInterval i1, TimeInterval i2)
+bool
+intervaleq(TimeInterval i1, TimeInterval i2)
{
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- return(0); /* invalid interval */
- return(abstimeeq(i1->data[0], i2->data[0]) &&
- abstimeeq(i1->data[1], i2->data[1]));
+ if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
+ return (0); /* invalid interval */
+ return (abstimeeq(i1->data[0], i2->data[0]) &&
+ abstimeeq(i1->data[1], i2->data[1]));
}
/*
- * intervalleneq - returns 1, iff length of interval i is equal to
- * reltime t
+ * intervalleneq - returns 1, iff length of interval i is equal to
+ * reltime t
*/
-bool intervalleneq(TimeInterval i, RelativeTime t)
+bool
+intervalleneq(TimeInterval i, RelativeTime t)
{
- RelativeTime rt;
-
- if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
- return(0);
- rt = intervalrel(i);
- return (rt != INVALID_RELTIME && rt == t);
+ RelativeTime rt;
+
+ if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
+ return (0);
+ rt = intervalrel(i);
+ return (rt != INVALID_RELTIME && rt == t);
}
/*
- * intervallenne - returns 1, iff length of interval i is not equal
- * to reltime t
+ * intervallenne - returns 1, iff length of interval i is not equal
+ * to reltime t
*/
-bool intervallenne(TimeInterval i, RelativeTime t)
+bool
+intervallenne(TimeInterval i, RelativeTime t)
{
- RelativeTime rt;
-
- if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
- return(0);
- rt = intervalrel(i);
- return (rt != INVALID_RELTIME && rt != t);
+ RelativeTime rt;
+
+ if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
+ return (0);
+ rt = intervalrel(i);
+ return (rt != INVALID_RELTIME && rt != t);
}
/*
- * intervallenlt - returns 1, iff length of interval i is less than
- * reltime t
+ * intervallenlt - returns 1, iff length of interval i is less than
+ * reltime t
*/
-bool intervallenlt(TimeInterval i, RelativeTime t)
+bool
+intervallenlt(TimeInterval i, RelativeTime t)
{
- RelativeTime rt;
-
- if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
- return(0);
- rt = intervalrel(i);
- return (rt != INVALID_RELTIME && rt < t);
+ RelativeTime rt;
+
+ if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
+ return (0);
+ rt = intervalrel(i);
+ return (rt != INVALID_RELTIME && rt < t);
}
/*
- * intervallengt - returns 1, iff length of interval i is greater than
- * reltime t
+ * intervallengt - returns 1, iff length of interval i is greater than
+ * reltime t
*/
-bool intervallengt(TimeInterval i, RelativeTime t)
+bool
+intervallengt(TimeInterval i, RelativeTime t)
{
- RelativeTime rt;
-
- if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
- return(0);
- rt = intervalrel(i);
- return (rt != INVALID_RELTIME && rt > t);
+ RelativeTime rt;
+
+ if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
+ return (0);
+ rt = intervalrel(i);
+ return (rt != INVALID_RELTIME && rt > t);
}
/*
- * intervallenle - returns 1, iff length of interval i is less or equal
- * than reltime t
+ * intervallenle - returns 1, iff length of interval i is less or equal
+ * than reltime t
*/
-bool intervallenle(TimeInterval i, RelativeTime t)
-{
- RelativeTime rt;
-
- if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
- return(0);
- rt = intervalrel(i);
- return (rt != INVALID_RELTIME && rt <= t);
+bool
+intervallenle(TimeInterval i, RelativeTime t)
+{
+ RelativeTime rt;
+
+ if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
+ return (0);
+ rt = intervalrel(i);
+ return (rt != INVALID_RELTIME && rt <= t);
}
/*
- * intervallenge - returns 1, iff length of interval i is greater or
- * equal than reltime t
+ * intervallenge - returns 1, iff length of interval i is greater or
+ * equal than reltime t
*/
-bool intervallenge(TimeInterval i, RelativeTime t)
+bool
+intervallenge(TimeInterval i, RelativeTime t)
{
- RelativeTime rt;
-
- if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
- return(0);
- rt = intervalrel(i);
- return (rt != INVALID_RELTIME && rt >= t);
+ RelativeTime rt;
+
+ if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
+ return (0);
+ rt = intervalrel(i);
+ return (rt != INVALID_RELTIME && rt >= t);
}
/*
- * intervalct - returns 1, iff interval i1 contains interval i2
+ * intervalct - returns 1, iff interval i1 contains interval i2
*/
-bool intervalct(TimeInterval i1, TimeInterval i2)
+bool
+intervalct(TimeInterval i1, TimeInterval i2)
{
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- return(0);
- return(abstimele(i1->data[0], i2->data[0]) &&
- abstimege(i1->data[1], i2->data[1]));
+ if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
+ return (0);
+ return (abstimele(i1->data[0], i2->data[0]) &&
+ abstimege(i1->data[1], i2->data[1]));
}
/*
- * intervalov - returns 1, iff interval i1 (partially) overlaps i2
+ * intervalov - returns 1, iff interval i1 (partially) overlaps i2
*/
-bool intervalov(TimeInterval i1, TimeInterval i2)
+bool
+intervalov(TimeInterval i1, TimeInterval i2)
{
- if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
- return(0);
- return(! (abstimelt(i1->data[1], i2->data[0]) ||
- abstimegt(i1->data[0], i2->data[1])));
+ if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
+ return (0);
+ return (!(abstimelt(i1->data[1], i2->data[0]) ||
+ abstimegt(i1->data[0], i2->data[1])));
}
/*
- * intervalstart - returns the start of interval i
+ * intervalstart - returns the start of interval i
*/
-AbsoluteTime intervalstart(TimeInterval i)
+AbsoluteTime
+intervalstart(TimeInterval i)
{
- if (i->status == T_INTERVAL_INVAL)
- return INVALID_ABSTIME;
- return(i->data[0]);
+ if (i->status == T_INTERVAL_INVAL)
+ return INVALID_ABSTIME;
+ return (i->data[0]);
}
/*
- * intervalend - returns the end of interval i
+ * intervalend - returns the end of interval i
*/
-AbsoluteTime intervalend(TimeInterval i)
+AbsoluteTime
+intervalend(TimeInterval i)
{
- if (i->status == T_INTERVAL_INVAL)
- return INVALID_ABSTIME;
- return(i->data[1]);
+ if (i->status == T_INTERVAL_INVAL)
+ return INVALID_ABSTIME;
+ return (i->data[1]);
}
-/*****************************************************************************
- * PRIVATE ROUTINES *
+/*****************************************************************************
+ * PRIVATE ROUTINES *
*****************************************************************************/
/*
- * isreltime - returns 1, iff datestring is of type reltime
- * 2, iff datestring is 'invalid time' identifier
- * 0, iff datestring contains a syntax error
- * VALID time less or equal +/- `@ 68 years'
+ * isreltime - returns 1, iff datestring is of type reltime
+ * 2, iff datestring is 'invalid time' identifier
+ * 0, iff datestring contains a syntax error
+ * VALID time less or equal +/- `@ 68 years'
*
*/
-int isreltime(char *str)
+int
+isreltime(char *str)
{
- struct tm tt, *tm = &tt;
- double fsec;
- int dtype;
- char *field[MAXDATEFIELDS];
- int nf, ftype[MAXDATEFIELDS];
- char lowstr[MAXDATELEN+1];
-
- if (!PointerIsValid(str))
- return 0;
-
- if (strlen(str) > MAXDATELEN)
- return 0;
-
- if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateDelta( field, ftype, nf, &dtype, tm, &fsec) != 0))
- return 0;
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
+ int dtype;
+ char *field[MAXDATEFIELDS];
+ int nf,
+ ftype[MAXDATEFIELDS];
+ char lowstr[MAXDATELEN + 1];
+
+ if (!PointerIsValid(str))
+ return 0;
+
+ if (strlen(str) > MAXDATELEN)
+ return 0;
+
+ if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
+ return 0;
+
+ switch (dtype)
+ {
+ case (DTK_DELTA):
+ return ((abs(tm->tm_year) <= 68) ? 1 : 0);
+ break;
- switch (dtype) {
- case (DTK_DELTA):
- return((abs(tm->tm_year) <= 68)? 1: 0);
- break;
+ case (DTK_INVALID):
+ return 2;
+ break;
- case (DTK_INVALID):
- return 2;
- break;
+ default:
+ return 0;
+ break;
+ }
- default:
return 0;
- break;
- }
-
- return 0;
-} /* isreltime() */
+} /* isreltime() */
#if FALSE
- register char *p;
- register char c;
- int i;
- char unit[UNITMAXLEN] ;
- char direction[DIRMAXLEN];
- int localSign;
- int localUnitNumber;
- long localQuantity;
-
- if (!PointerIsValid(sign)) {
+register char *p;
+register char c;
+int i;
+char unit[UNITMAXLEN];
+char direction[DIRMAXLEN];
+int localSign;
+int localUnitNumber;
+long localQuantity;
+
+if (!PointerIsValid(sign))
+{
sign = &localSign;
- }
- if (!PointerIsValid(unitnr)) {
+}
+
+if (!PointerIsValid(unitnr))
+{
unitnr = &localUnitNumber;
- }
- if (!PointerIsValid(quantity)) {
+}
+
+if (!PointerIsValid(quantity))
+{
quantity = &localQuantity;
- }
- unit[0] = '\0';
- direction[0] = '\0';
- p = timestring;
- /* skip leading blanks */
- while ((c = *p) != '\0') {
+}
+
+unit[0] = '\0';
+direction[0] = '\0';
+p = timestring;
+ /* skip leading blanks */
+while ((c = *p) != '\0')
+{
if (c != ' ')
- break;
+ break;
p++;
- }
- /* Test whether 'invalid time' identifier or not */
- if (!strncmp(INVALID_RELTIME_STR,p,strlen(INVALID_RELTIME_STR) + 1))
- return(2); /* correct 'invalid time' identifier found */
-
- /* handle label of relative time */
- if (c != RELTIME_LABEL)
- return(0); /*syntax error*/
- c = *++p;
- if (c != ' ') return(0); /*syntax error*/
- p++;
- /* handle the quantity */
- *quantity = 0;
- for (;;) {
+}
+
+ /* Test whether 'invalid time' identifier or not */
+if (!strncmp(INVALID_RELTIME_STR, p, strlen(INVALID_RELTIME_STR) + 1))
+ return (2); /* correct 'invalid time' identifier found */
+
+ /* handle label of relative time */
+if (c != RELTIME_LABEL)
+ return (0); /* syntax error */
+c = *++p;
+if (c != ' ')
+ return (0); /* syntax error */
+p++;
+ /* handle the quantity */
+*quantity = 0;
+for (;;)
+{
c = *p;
- if (isdigit(c)) {
- *quantity = *quantity * 10 + (c -'0');
- p++;
- } else {
- if (c == ' ' )
- break; /* correct quantity found */
- else
- return(0); /* syntax error */
+ if (isdigit(c))
+ {
+ *quantity = *quantity * 10 + (c - '0');
+ p++;
+ }
+ else
+ {
+ if (c == ' ')
+ break; /* correct quantity found */
+ else
+ return (0); /* syntax error */
}
- }
- /* handle unit */
- p++;
- i = 0;
- for (;;) {
+}
+
+ /* handle unit */
+p++;
+i = 0;
+for (;;)
+{
c = *p;
- if (c >= 'a' && c <= 'z' && i <= (UNITMAXLEN - 1)) {
- unit[i] = c;
- p++;
- i++;
- } else {
- if ((c == ' ' || c == '\0')
- && correct_unit(unit, unitnr))
- break; /* correct unit found */
- else
- return(0); /* syntax error */
+ if (c >= 'a' && c <= 'z' && i <= (UNITMAXLEN - 1))
+ {
+ unit[i] = c;
+ p++;
+ i++;
+ }
+ else
+ {
+ if ((c == ' ' || c == '\0')
+ && correct_unit(unit, unitnr))
+ break; /* correct unit found */
+ else
+ return (0); /* syntax error */
}
- }
- /* handle optional direction */
- if (c == ' ')
+}
+
+ /* handle optional direction */
+if (c == ' ')
p++;
- i = 0;
- *sign = 1;
- for (;;) {
+i = 0;
+*sign = 1;
+for (;;)
+{
c = *p;
- if (c >= 'a' && c <= 'z' && i <= (DIRMAXLEN - 1)) {
- direction[i] = c;
- p++;
- i++;
- } else {
- if ((c == ' ' || c == '\0') && i == 0) {
- *sign = 1;
- break; /* no direction specified */
- }
- if ((c == ' ' || c == '\0') && i != 0)
+ if (c >= 'a' && c <= 'z' && i <= (DIRMAXLEN - 1))
+ {
+ direction[i] = c;
+ p++;
+ i++;
+ }
+ else
+ {
+ if ((c == ' ' || c == '\0') && i == 0)
{
- direction[i] = '\0';
- correct_dir(direction, sign);
- break; /* correct direction found */
+ *sign = 1;
+ break; /* no direction specified */
}
- else
- return(0); /* syntax error*/
+ if ((c == ' ' || c == '\0') && i != 0)
+ {
+ direction[i] = '\0';
+ correct_dir(direction, sign);
+ break; /* correct direction found */
+ }
+ else
+ return (0); /* syntax error */
}
- }
- return(1);
+}
+
+return (1);
}
/*
- * correct_unit - returns 1, iff unit is a correct unit description
+ * correct_unit - returns 1, iff unit is a correct unit description
*
- * output parameter:
- * unptr: points to an integer which is the appropriate unit number
- * (see function isreltime())
- */
-static int correct_unit(char unit[], int *unptr)
-{
- int j = 0;
-
- while (j < NUNITS) {
- if (strncmp(unit, unit_tab[j], strlen(unit_tab[j])) == 0) {
- *unptr = j;
- return(1);
+ * output parameter:
+ * unptr: points to an integer which is the appropriate unit number
+ * (see function isreltime())
+ */
+static int
+correct_unit(char unit[], int *unptr)
+{
+ int j = 0;
+
+ while (j < NUNITS)
+ {
+ if (strncmp(unit, unit_tab[j], strlen(unit_tab[j])) == 0)
+ {
+ *unptr = j;
+ return (1);
+ }
+ j++;
}
- j++;
- }
- return (0); /* invalid unit descriptor */
+ return (0); /* invalid unit descriptor */
}
/*
- * correct_dir - returns 1, iff direction is a correct identifier
+ * correct_dir - returns 1, iff direction is a correct identifier
*
- * output parameter:
- * signptr: points to -1 if dir corresponds to past tense
- * else to 1
- */
-static int correct_dir(char direction[], int *signptr)
-{
- *signptr = 1;
- if (strncmp(RELTIME_PAST, direction, strlen(RELTIME_PAST)+1) == 0)
+ * output parameter:
+ * signptr: points to -1 if dir corresponds to past tense
+ * else to 1
+ */
+static int
+correct_dir(char direction[], int *signptr)
+{
+ *signptr = 1;
+ if (strncmp(RELTIME_PAST, direction, strlen(RELTIME_PAST) + 1) == 0)
{
- *signptr = -1;
- return(1);
- } else
- return (0); /* invalid direction descriptor */
+ *signptr = -1;
+ return (1);
+ }
+ else
+ return (0); /* invalid direction descriptor */
}
+
#endif
/*
- * istinterval - returns 1, iff i_string is a valid interval descr.
- * 0, iff i_string is NOT a valid interval desc.
- * 2, iff any time is INVALID_ABSTIME
+ * istinterval - returns 1, iff i_string is a valid interval descr.
+ * 0, iff i_string is NOT a valid interval desc.
+ * 2, iff any time is INVALID_ABSTIME
*
- * output parameter:
- * i_start, i_end: interval margins
+ * output parameter:
+ * i_start, i_end: interval margins
*
- * Time interval:
- * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
+ * Time interval:
+ * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
*
- * OR `Undefined Range' (see also INVALID_INTERVAL_STR)
+ * OR `Undefined Range' (see also INVALID_INTERVAL_STR)
*
- * where <AbsTime> satisfies the syntax of absolute time.
+ * where <AbsTime> satisfies the syntax of absolute time.
*
- * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970']
- */
-static int istinterval(char *i_string,
- AbsoluteTime *i_start,
- AbsoluteTime *i_end)
-{
- register char *p,*p1;
- register char c;
-
- p = i_string;
- /* skip leading blanks up to '[' */
- while ((c = *p) != '\0') {
- if ( IsSpace(c))
- p++;
- else if (c != '[')
- return(0); /* syntax error */
- else
- break;
- }
- p++;
- /* skip leading blanks up to "'" */
- while ((c = *p) != '\0') {
- if (IsSpace(c))
- p++;
- else if (c != '"')
- return (0); /* syntax error */
- else
- break;
- }
- p++;
- if (strncmp(INVALID_INTERVAL_STR,p,strlen(INVALID_INTERVAL_STR)) == 0)
- return(0); /* undefined range, handled like a syntax err.*/
- /* search for the end of the first date and change it to a NULL*/
- p1 = p;
- while ((c = *p1) != '\0') {
- if ( c == '"') {
- *p1 = '\0';
- break;
+ * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970']
+ */
+static int
+istinterval(char *i_string,
+ AbsoluteTime * i_start,
+ AbsoluteTime * i_end)
+{
+ register char *p,
+ *p1;
+ register char c;
+
+ p = i_string;
+ /* skip leading blanks up to '[' */
+ while ((c = *p) != '\0')
+ {
+ if (IsSpace(c))
+ p++;
+ else if (c != '[')
+ return (0); /* syntax error */
+ else
+ break;
}
- p1++;
- }
- /* get the first date */
- *i_start = nabstimein(p); /* first absolute date */
- /* rechange NULL at the end of the first date to a "'" */
- *p1 = '"';
- p = ++p1;
- /* skip blanks up to "'", beginning of second date*/
- while ((c = *p) != '\0') {
- if (IsSpace(c))
- p++;
- else if (c != '"')
- return (0); /* syntax error */
- else
- break;
- }
- p++;
- /* search for the end of the second date and change it to a NULL*/
- p1 = p;
- while ((c = *p1) != '\0') {
- if ( c == '"') {
- *p1 = '\0';
- break;
+ p++;
+ /* skip leading blanks up to "'" */
+ while ((c = *p) != '\0')
+ {
+ if (IsSpace(c))
+ p++;
+ else if (c != '"')
+ return (0); /* syntax error */
+ else
+ break;
}
- p1++;
- }
- /* get the second date */
- *i_end = nabstimein(p); /* second absolute date */
- /* rechange NULL at the end of the first date to a ''' */
- *p1 = '"';
- p = ++p1;
- /* skip blanks up to ']'*/
- while ((c = *p) != '\0') {
- if ( IsSpace(c))
- p++;
- else if (c != ']')
- return(0); /*syntax error */
- else
- break;
- }
- p++;
- c = *p;
- if ( c != '\0' )
- return (0); /* syntax error */
- /* it seems to be a valid interval */
- return(1);
+ p++;
+ if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0)
+ return (0); /* undefined range, handled like a syntax
+ * err. */
+ /* search for the end of the first date and change it to a NULL */
+ p1 = p;
+ while ((c = *p1) != '\0')
+ {
+ if (c == '"')
+ {
+ *p1 = '\0';
+ break;
+ }
+ p1++;
+ }
+ /* get the first date */
+ *i_start = nabstimein(p); /* first absolute date */
+ /* rechange NULL at the end of the first date to a "'" */
+ *p1 = '"';
+ p = ++p1;
+ /* skip blanks up to "'", beginning of second date */
+ while ((c = *p) != '\0')
+ {
+ if (IsSpace(c))
+ p++;
+ else if (c != '"')
+ return (0); /* syntax error */
+ else
+ break;
+ }
+ p++;
+ /* search for the end of the second date and change it to a NULL */
+ p1 = p;
+ while ((c = *p1) != '\0')
+ {
+ if (c == '"')
+ {
+ *p1 = '\0';
+ break;
+ }
+ p1++;
+ }
+ /* get the second date */
+ *i_end = nabstimein(p); /* second absolute date */
+ /* rechange NULL at the end of the first date to a ''' */
+ *p1 = '"';
+ p = ++p1;
+ /* skip blanks up to ']' */
+ while ((c = *p) != '\0')
+ {
+ if (IsSpace(c))
+ p++;
+ else if (c != ']')
+ return (0); /* syntax error */
+ else
+ break;
+ }
+ p++;
+ c = *p;
+ if (c != '\0')
+ return (0); /* syntax error */
+ /* it seems to be a valid interval */
+ return (1);
}
@@ -946,30 +1053,30 @@ static int istinterval(char *i_string,
/*
* timeofday -
- * returns the current time as a text. similar to timenow() but returns
- * seconds with more precision (up to microsecs). (I need this to compare
- * the Wisconsin benchmark with Illustra whose TimeNow() shows current
- * time with precision up to microsecs.) - ay 3/95
+ * returns the current time as a text. similar to timenow() but returns
+ * seconds with more precision (up to microsecs). (I need this to compare
+ * the Wisconsin benchmark with Illustra whose TimeNow() shows current
+ * time with precision up to microsecs.) - ay 3/95
*/
-text *
+text *
timeofday(void)
{
- struct timeval tp;
- struct timezone tpz;
- char templ[500];
- char buf[500];
- text *tm;
- int len = 0;
-
- gettimeofday(&tp, &tpz);
- strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%d %Y %Z",
- localtime((time_t *) &tp.tv_sec));
- sprintf(buf, templ, tp.tv_usec);
-
- len = VARHDRSZ + strlen(buf);
- tm = (text *)palloc(len);
- VARSIZE(tm) = len;
- strncpy(VARDATA(tm), buf, strlen(buf));
- return tm;
+ struct timeval tp;
+ struct timezone tpz;
+ char templ[500];
+ char buf[500];
+ text *tm;
+ int len = 0;
+
+ gettimeofday(&tp, &tpz);
+ strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%d %Y %Z",
+ localtime((time_t *) & tp.tv_sec));
+ sprintf(buf, templ, tp.tv_usec);
+
+ len = VARHDRSZ + strlen(buf);
+ tm = (text *) palloc(len);
+ VARSIZE(tm) = len;
+ strncpy(VARDATA(tm), buf, strlen(buf));
+ return tm;
}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 9809ebf5f11..a88bea36e9c 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* datetime.c--
- * implements DATE and TIME data types specified in SQL-92 standard
+ * implements DATE and TIME data types specified in SQL-92 standard
*
* Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.13 1997/09/05 18:11:10 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datetime.c,v 1.14 1997/09/07 04:50:08 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <limits.h>
@@ -25,12 +25,12 @@
#include "utils/datetime.h"
#include "access/xact.h"
-static int date2tm(DateADT dateVal, int *tzp, struct tm *tm, double *fsec, char **tzn);
+static int date2tm(DateADT dateVal, int *tzp, struct tm * tm, double *fsec, char **tzn);
-static int day_tab[2][12] = {
- {31,28,31,30,31,30,31,31,30,31,30,31},
- {31,29,31,30,31,30,31,31,30,31,30,31} };
+static int day_tab[2][12] = {
+ {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
#define isleap(y) (((y % 4) == 0 && (y % 100) != 0) || (y % 400) == 0)
@@ -49,7 +49,7 @@ static int day_tab[2][12] = {
|| ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
/*****************************************************************************
- * Date ADT
+ * Date ADT
*****************************************************************************/
@@ -59,234 +59,250 @@ static int day_tab[2][12] = {
DateADT
date_in(char *str)
{
- DateADT date;
- double fsec;
- struct tm tt, *tm = &tt;
- int tzp;
- int dtype;
- int nf;
- char *field[MAXDATEFIELDS];
- int ftype[MAXDATEFIELDS];
- char lowstr[MAXDATELEN+1];
-
- if (!PointerIsValid(str))
- elog(WARN,"Bad (null) date external representation",NULL);
+ DateADT date;
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
+ int tzp;
+ int dtype;
+ int nf;
+ char *field[MAXDATEFIELDS];
+ int ftype[MAXDATEFIELDS];
+ char lowstr[MAXDATELEN + 1];
+
+ if (!PointerIsValid(str))
+ elog(WARN, "Bad (null) date external representation", NULL);
#ifdef DATEDEBUG
-printf( "date_in- input string is %s\n", str);
+ printf("date_in- input string is %s\n", str);
#endif
- if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateTime( field, ftype, nf, &dtype, tm, &fsec, &tzp) != 0))
- elog(WARN,"Bad date external representation %s",str);
-
- switch (dtype) {
- case DTK_DATE:
- break;
-
- case DTK_CURRENT:
- GetCurrentTime(tm);
- break;
-
- case DTK_EPOCH:
- tm->tm_year = 1970;
- tm->tm_mon = 1;
- tm->tm_mday = 1;
- break;
-
- default:
- elog(WARN,"Unrecognized date external representation %s",str);
- }
+ if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tzp) != 0))
+ elog(WARN, "Bad date external representation %s", str);
+
+ switch (dtype)
+ {
+ case DTK_DATE:
+ break;
+
+ case DTK_CURRENT:
+ GetCurrentTime(tm);
+ break;
+
+ case DTK_EPOCH:
+ tm->tm_year = 1970;
+ tm->tm_mon = 1;
+ tm->tm_mday = 1;
+ break;
+
+ default:
+ elog(WARN, "Unrecognized date external representation %s", str);
+ }
- if (tm->tm_year < 0 || tm->tm_year > 32767)
- elog(WARN, "date_in: year must be limited to values 0 through 32767 in '%s'", str);
- if (tm->tm_mon < 1 || tm->tm_mon > 12)
- elog(WARN, "date_in: month must be limited to values 1 through 12 in '%s'", str);
- if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon-1])
- elog(WARN, "date_in: day must be limited to values 1 through %d in '%s'",
- day_tab[isleap(tm->tm_year)][tm->tm_mon-1], str);
+ if (tm->tm_year < 0 || tm->tm_year > 32767)
+ elog(WARN, "date_in: year must be limited to values 0 through 32767 in '%s'", str);
+ if (tm->tm_mon < 1 || tm->tm_mon > 12)
+ elog(WARN, "date_in: month must be limited to values 1 through 12 in '%s'", str);
+ if (tm->tm_mday < 1 || tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
+ elog(WARN, "date_in: day must be limited to values 1 through %d in '%s'",
+ day_tab[isleap(tm->tm_year)][tm->tm_mon - 1], str);
- date = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000,1,1));
+ date = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
- return(date);
-} /* date_in() */
+ return (date);
+} /* date_in() */
/* date_out()
* Given internal format date, convert to text string.
*/
-char *
+char *
date_out(DateADT date)
{
- char *result;
- struct tm tt, *tm = &tt;
- char buf[MAXDATELEN+1];
+ char *result;
+ struct tm tt,
+ *tm = &tt;
+ char buf[MAXDATELEN + 1];
#if FALSE
- int year, month, day;
+ int year,
+ month,
+ day;
+
#endif
- j2date( (date + date2j(2000,1,1)),
- &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+ j2date((date + date2j(2000, 1, 1)),
+ &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
- EncodeDateOnly( tm, DateStyle, buf);
+ EncodeDateOnly(tm, DateStyle, buf);
#if FALSE
- if (EuroDates == 1) /* Output European-format dates */
- sprintf(buf, "%02d-%02d-%04d", day, month, year);
- else
- sprintf(buf, "%02d-%02d-%04d", month, day, year);
+ if (EuroDates == 1) /* Output European-format dates */
+ sprintf(buf, "%02d-%02d-%04d", day, month, year);
+ else
+ sprintf(buf, "%02d-%02d-%04d", month, day, year);
#endif
- result = PALLOC(strlen(buf)+1);
+ result = PALLOC(strlen(buf) + 1);
- strcpy( result, buf);
+ strcpy(result, buf);
- return(result);
-} /* date_out() */
+ return (result);
+} /* date_out() */
bool
date_eq(DateADT dateVal1, DateADT dateVal2)
{
- return(dateVal1 == dateVal2);
+ return (dateVal1 == dateVal2);
}
bool
date_ne(DateADT dateVal1, DateADT dateVal2)
{
- return(dateVal1 != dateVal2);
+ return (dateVal1 != dateVal2);
}
bool
date_lt(DateADT dateVal1, DateADT dateVal2)
{
- return(dateVal1 < dateVal2);
-} /* date_lt() */
+ return (dateVal1 < dateVal2);
+} /* date_lt() */
bool
date_le(DateADT dateVal1, DateADT dateVal2)
{
- return(dateVal1 <= dateVal2);
-} /* date_le() */
+ return (dateVal1 <= dateVal2);
+} /* date_le() */
bool
date_gt(DateADT dateVal1, DateADT dateVal2)
{
- return(dateVal1 > dateVal2);
-} /* date_gt() */
+ return (dateVal1 > dateVal2);
+} /* date_gt() */
bool
date_ge(DateADT dateVal1, DateADT dateVal2)
{
- return(dateVal1 >= dateVal2);
-} /* date_ge() */
+ return (dateVal1 >= dateVal2);
+} /* date_ge() */
int
date_cmp(DateADT dateVal1, DateADT dateVal2)
{
- if (dateVal1 < dateVal2) {
- return -1;
- } else if (dateVal1 > dateVal2) {
- return 1;
- }
- return 0;
-} /* date_cmp() */
+ if (dateVal1 < dateVal2)
+ {
+ return -1;
+ }
+ else if (dateVal1 > dateVal2)
+ {
+ return 1;
+ }
+ return 0;
+} /* date_cmp() */
DateADT
date_larger(DateADT dateVal1, DateADT dateVal2)
{
- return(date_gt(dateVal1, dateVal2) ? dateVal1 : dateVal2);
-} /* date_larger() */
+ return (date_gt(dateVal1, dateVal2) ? dateVal1 : dateVal2);
+} /* date_larger() */
DateADT
date_smaller(DateADT dateVal1, DateADT dateVal2)
{
- return(date_lt(dateVal1, dateVal2) ? dateVal1 : dateVal2);
-} /* date_smaller() */
+ return (date_lt(dateVal1, dateVal2) ? dateVal1 : dateVal2);
+} /* date_smaller() */
/* Compute difference between two dates in days. */
int4
date_mi(DateADT dateVal1, DateADT dateVal2)
{
- return(dateVal1-dateVal2);
-} /* date_mi() */
+ return (dateVal1 - dateVal2);
+} /* date_mi() */
/* Add a number of days to a date, giving a new date.
- Must handle both positive and negative numbers of days. */
+ Must handle both positive and negative numbers of days. */
DateADT
date_pli(DateADT dateVal, int4 days)
{
- return(dateVal+days);
-} /* date_pli() */
+ return (dateVal + days);
+} /* date_pli() */
/* Subtract a number of days from a date, giving a new date. */
DateADT
date_mii(DateADT dateVal, int4 days)
{
- return(date_pli(dateVal, -days));
-} /* date_mii() */
+ return (date_pli(dateVal, -days));
+} /* date_mii() */
/* date_datetime()
* Convert date to datetime data type.
*/
-DateTime *
+DateTime *
date_datetime(DateADT dateVal)
{
- DateTime *result;
- struct tm tt, *tm = &tt;
- int tz;
- double fsec = 0;
- char *tzn;
+ DateTime *result;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+ double fsec = 0;
+ char *tzn;
- result = PALLOCTYPE(DateTime);
+ result = PALLOCTYPE(DateTime);
- if (date2tm( dateVal, &tz, tm, &fsec, &tzn) != 0)
- elog(WARN,"Unable to convert date to datetime",NULL);
+ if (date2tm(dateVal, &tz, tm, &fsec, &tzn) != 0)
+ elog(WARN, "Unable to convert date to datetime", NULL);
#ifdef DATEDEBUG
-printf( "date_datetime- date is %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
-printf( "date_datetime- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
+ printf("date_datetime- date is %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
+ printf("date_datetime- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
#endif
- if (tm2datetime( tm, fsec, &tz, result) != 0)
- elog(WARN,"Datetime out of range",NULL);
+ if (tm2datetime(tm, fsec, &tz, result) != 0)
+ elog(WARN, "Datetime out of range", NULL);
- return(result);
-} /* date_datetime() */
+ return (result);
+} /* date_datetime() */
/* datetime_date()
* Convert datetime to date data type.
*/
DateADT
-datetime_date(DateTime *datetime)
+datetime_date(DateTime * datetime)
{
- DateADT result;
- struct tm tt, *tm = &tt;
- int tz;
- double fsec;
- char *tzn;
+ DateADT result;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+ double fsec;
+ char *tzn;
- if (!PointerIsValid(datetime))
- elog(WARN,"Unable to convert null datetime to date",NULL);
+ if (!PointerIsValid(datetime))
+ elog(WARN, "Unable to convert null datetime to date", NULL);
- if (DATETIME_NOT_FINITE(*datetime))
- elog(WARN,"Unable to convert datetime to date",NULL);
+ if (DATETIME_NOT_FINITE(*datetime))
+ elog(WARN, "Unable to convert datetime to date", NULL);
- if (DATETIME_IS_EPOCH(*datetime)) {
- datetime2tm( SetDateTime(*datetime), NULL, tm, &fsec, NULL);
+ if (DATETIME_IS_EPOCH(*datetime))
+ {
+ datetime2tm(SetDateTime(*datetime), NULL, tm, &fsec, NULL);
- } else if (DATETIME_IS_CURRENT(*datetime)) {
- datetime2tm( SetDateTime(*datetime), &tz, tm, &fsec, &tzn);
+ }
+ else if (DATETIME_IS_CURRENT(*datetime))
+ {
+ datetime2tm(SetDateTime(*datetime), &tz, tm, &fsec, &tzn);
- } else {
- if (datetime2tm( *datetime, &tz, tm, &fsec, &tzn) != 0)
- elog(WARN,"Unable to convert datetime to date",NULL);
- }
+ }
+ else
+ {
+ if (datetime2tm(*datetime, &tz, tm, &fsec, &tzn) != 0)
+ elog(WARN, "Unable to convert datetime to date", NULL);
+ }
- result = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 2000, 1, 1));
+ result = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1));
- return(result);
-} /* datetime_date() */
+ return (result);
+} /* datetime_date() */
/* abstime_date()
@@ -295,289 +311,320 @@ datetime_date(DateTime *datetime)
DateADT
abstime_date(AbsoluteTime abstime)
{
- DateADT result;
- struct tm tt, *tm = &tt;
- int tz;
-
- switch (abstime) {
- case INVALID_ABSTIME:
- case NOSTART_ABSTIME:
- case NOEND_ABSTIME:
- elog(WARN,"Unable to convert reserved abstime value to date",NULL);
- /* pretend to drop through to make compiler think that result will be set */
-
- case EPOCH_ABSTIME:
- result = date2j(1970,1,1) - date2j(2000,1,1);
- break;
-
- case CURRENT_ABSTIME:
- GetCurrentTime(tm);
- result = date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000,1,1);
- break;
-
- default:
- abstime2tm(abstime, &tz, tm, NULL);
- result = date2j(tm->tm_year,tm->tm_mon,tm->tm_mday) - date2j(2000,1,1);
- break;
- }
+ DateADT result;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+
+ switch (abstime)
+ {
+ case INVALID_ABSTIME:
+ case NOSTART_ABSTIME:
+ case NOEND_ABSTIME:
+ elog(WARN, "Unable to convert reserved abstime value to date", NULL);
+
+ /*
+ * pretend to drop through to make compiler think that result will
+ * be set
+ */
+
+ case EPOCH_ABSTIME:
+ result = date2j(1970, 1, 1) - date2j(2000, 1, 1);
+ break;
+
+ case CURRENT_ABSTIME:
+ GetCurrentTime(tm);
+ result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+ break;
+
+ default:
+ abstime2tm(abstime, &tz, tm, NULL);
+ result = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+ break;
+ }
- return(result);
-} /* abstime_date() */
+ return (result);
+} /* abstime_date() */
/* date2tm()
* Convert date to time structure.
* Note that date is an implicit local time, but the system calls assume
- * that everything is GMT. So, convert to GMT, rotate to local time,
- * and then convert again to try to get the time zones correct.
+ * that everything is GMT. So, convert to GMT, rotate to local time,
+ * and then convert again to try to get the time zones correct.
*/
static int
-date2tm(DateADT dateVal, int *tzp, struct tm *tm, double *fsec, char **tzn)
+date2tm(DateADT dateVal, int *tzp, struct tm * tm, double *fsec, char **tzn)
{
- struct tm *tx;
- time_t utime;
- *fsec = 0;
+ struct tm *tx;
+ time_t utime;
- j2date( (dateVal + date2j( 2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- tm->tm_isdst = -1;
+ *fsec = 0;
- if (IS_VALID_UTIME( tm->tm_year, tm->tm_mon, tm->tm_mday)) {
+ j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ tm->tm_isdst = -1;
+
+ if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
+ {
- /* convert to system time */
- utime = ((dateVal + (date2j(2000,1,1)-date2j(1970,1,1)))*86400);
- utime += (12*60*60); /* rotate to noon to get the right day in time zone */
+ /* convert to system time */
+ utime = ((dateVal + (date2j(2000, 1, 1) - date2j(1970, 1, 1))) * 86400);
+ utime += (12 * 60 * 60);/* rotate to noon to get the right day in
+ * time zone */
#ifdef USE_POSIX_TIME
- tx = localtime(&utime);
+ tx = localtime(&utime);
#ifdef DATEDEBUG
#ifdef HAVE_INT_TIMEZONE
-printf( "date2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s %s dst=%d\n",
- tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, (double) tm->tm_sec,
- tzname[0], tzname[1], tx->tm_isdst);
+ printf("date2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s %s dst=%d\n",
+ tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, (double) tm->tm_sec,
+ tzname[0], tzname[1], tx->tm_isdst);
#endif
#endif
- tm->tm_year = tx->tm_year + 1900;
- tm->tm_mon = tx->tm_mon + 1;
- tm->tm_mday = tx->tm_mday;
+ tm->tm_year = tx->tm_year + 1900;
+ tm->tm_mon = tx->tm_mon + 1;
+ tm->tm_mday = tx->tm_mday;
#if FALSE
- tm->tm_hour = tx->tm_hour;
- tm->tm_min = tx->tm_min;
- tm->tm_sec = tx->tm_sec;
+ tm->tm_hour = tx->tm_hour;
+ tm->tm_min = tx->tm_min;
+ tm->tm_sec = tx->tm_sec;
#endif
- tm->tm_isdst = tx->tm_isdst;
+ tm->tm_isdst = tx->tm_isdst;
#ifdef HAVE_INT_TIMEZONE
- *tzp = (tm->tm_isdst? (timezone - 3600): timezone);
- if (tzn != NULL) *tzn = tzname[(tm->tm_isdst > 0)];
-
-#else /* !HAVE_INT_TIMEZONE */
- tm->tm_gmtoff = tx->tm_gmtoff;
- tm->tm_zone = tx->tm_zone;
-
- *tzp = (tm->tm_isdst? (tm->tm_gmtoff - 3600): tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
- if (tzn != NULL) *tzn = tm->tm_zone;
+ *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
+ if (tzn != NULL)
+ *tzn = tzname[(tm->tm_isdst > 0)];
+
+#else /* !HAVE_INT_TIMEZONE */
+ tm->tm_gmtoff = tx->tm_gmtoff;
+ tm->tm_zone = tx->tm_zone;
+
+ *tzp = (tm->tm_isdst ? (tm->tm_gmtoff - 3600) : tm->tm_gmtoff); /* tm_gmtoff is
+ * Sun/DEC-ism */
+ if (tzn != NULL)
+ *tzn = tm->tm_zone;
#endif
-#else /* !USE_POSIX_TIME */
- *tzp = CTimeZone; /* V7 conventions; don't know timezone? */
- if (tzn != NULL) *tzn = CTZName;
+#else /* !USE_POSIX_TIME */
+ *tzp = CTimeZone; /* V7 conventions; don't know timezone? */
+ if (tzn != NULL)
+ *tzn = CTZName;
#endif
- /* otherwise, outside of timezone range so convert to GMT... */
- } else {
+ /* otherwise, outside of timezone range so convert to GMT... */
+ }
+ else
+ {
#if FALSE
- j2date( (dateVal + date2j( 2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
+ j2date((dateVal + date2j(2000, 1, 1)), &(tm->tm_year), &(tm->tm_mon), &(tm->tm_mday));
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
#endif
#ifdef DATEDEBUG
-printf( "date2tm- convert %d-%d-%d %d:%d%d to datetime\n",
- tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ printf("date2tm- convert %d-%d-%d %d:%d%d to datetime\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
#endif
- *tzp = 0;
- tm->tm_isdst = 0;
- if (tzn != NULL) *tzn = NULL;
- }
+ *tzp = 0;
+ tm->tm_isdst = 0;
+ if (tzn != NULL)
+ *tzn = NULL;
+ }
- return 0;
-} /* date2tm() */
+ return 0;
+} /* date2tm() */
/*****************************************************************************
- * Time ADT
+ * Time ADT
*****************************************************************************/
-TimeADT *
+TimeADT *
time_in(char *str)
{
- TimeADT *time;
+ TimeADT *time;
- double fsec;
- struct tm tt, *tm = &tt;
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
- int nf;
- char lowstr[MAXDATELEN+1];
- char *field[MAXDATEFIELDS];
- int dtype;
- int ftype[MAXDATEFIELDS];
+ int nf;
+ char lowstr[MAXDATELEN + 1];
+ char *field[MAXDATEFIELDS];
+ int dtype;
+ int ftype[MAXDATEFIELDS];
- if (!PointerIsValid(str))
- elog(WARN,"Bad (null) time external representation",NULL);
+ if (!PointerIsValid(str))
+ elog(WARN, "Bad (null) time external representation", NULL);
- if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeTimeOnly( field, ftype, nf, &dtype, tm, &fsec) != 0))
- elog(WARN,"Bad time external representation '%s'",str);
+ if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeTimeOnly(field, ftype, nf, &dtype, tm, &fsec) != 0))
+ elog(WARN, "Bad time external representation '%s'", str);
- if ((tm->tm_hour < 0) || (tm->tm_hour > 23))
- elog(WARN,"Hour must be limited to values 0 through 23 in '%s'",str);
- if ((tm->tm_min < 0) || (tm->tm_min > 59))
- elog(WARN,"Minute must be limited to values 0 through 59 in '%s'",str);
- if ((tm->tm_sec < 0) || ((tm->tm_sec + fsec) >= 60))
- elog(WARN,"Second must be limited to values 0 through < 60 in '%s'",str);
+ if ((tm->tm_hour < 0) || (tm->tm_hour > 23))
+ elog(WARN, "Hour must be limited to values 0 through 23 in '%s'", str);
+ if ((tm->tm_min < 0) || (tm->tm_min > 59))
+ elog(WARN, "Minute must be limited to values 0 through 59 in '%s'", str);
+ if ((tm->tm_sec < 0) || ((tm->tm_sec + fsec) >= 60))
+ elog(WARN, "Second must be limited to values 0 through < 60 in '%s'", str);
- time = PALLOCTYPE(TimeADT);
+ time = PALLOCTYPE(TimeADT);
- *time = ((((tm->tm_hour*60)+tm->tm_min)*60)+tm->tm_sec+fsec);
+ *time = ((((tm->tm_hour * 60) + tm->tm_min) * 60) + tm->tm_sec + fsec);
- return(time);
-} /* time_in() */
+ return (time);
+} /* time_in() */
-char *
-time_out(TimeADT *time)
+char *
+time_out(TimeADT * time)
{
- char *result;
- struct tm tt, *tm = &tt;
+ char *result;
+ struct tm tt,
+ *tm = &tt;
+
#if FALSE
- int hour, min, sec;
+ int hour,
+ min,
+ sec;
+
#endif
- double fsec;
- char buf[MAXDATELEN+1];
+ double fsec;
+ char buf[MAXDATELEN + 1];
- if (!PointerIsValid(time))
- return NULL;
+ if (!PointerIsValid(time))
+ return NULL;
- tm->tm_hour = (*time / (60*60));
- tm->tm_min = (((int) (*time / 60)) % 60);
- tm->tm_sec = (((int) *time) % 60);
+ tm->tm_hour = (*time / (60 * 60));
+ tm->tm_min = (((int) (*time / 60)) % 60);
+ tm->tm_sec = (((int) *time) % 60);
- fsec = 0;
+ fsec = 0;
- EncodeTimeOnly( tm, fsec, DateStyle, buf);
+ EncodeTimeOnly(tm, fsec, DateStyle, buf);
#if FALSE
- if (sec == 0.0) {
- sprintf(buf, "%02d:%02d", hour, min);
-
- } else {
- if (fsec == 0) {
- sprintf(buf, "%02d:%02d:%02d", hour, min, sec);
- } else {
- sprintf(buf, "%02d:%02d:%05.2f", hour, min, (sec+fsec));
+ if (sec == 0.0)
+ {
+ sprintf(buf, "%02d:%02d", hour, min);
+
+ }
+ else
+ {
+ if (fsec == 0)
+ {
+ sprintf(buf, "%02d:%02d:%02d", hour, min, sec);
+ }
+ else
+ {
+ sprintf(buf, "%02d:%02d:%05.2f", hour, min, (sec + fsec));
+ }
}
- }
#endif
- result = PALLOC(strlen(buf)+1);
+ result = PALLOC(strlen(buf) + 1);
- strcpy( result, buf);
+ strcpy(result, buf);
- return(result);
-} /* time_out() */
+ return (result);
+} /* time_out() */
bool
-time_eq(TimeADT *time1, TimeADT *time2)
+time_eq(TimeADT * time1, TimeADT * time2)
{
- if (!PointerIsValid(time1) || !PointerIsValid(time2))
- return(FALSE);
+ if (!PointerIsValid(time1) || !PointerIsValid(time2))
+ return (FALSE);
- return(*time1 == *time2);
-} /* time_eq() */
+ return (*time1 == *time2);
+} /* time_eq() */
bool
-time_ne(TimeADT *time1, TimeADT *time2)
+time_ne(TimeADT * time1, TimeADT * time2)
{
- if (!PointerIsValid(time1) || !PointerIsValid(time2))
- return(FALSE);
+ if (!PointerIsValid(time1) || !PointerIsValid(time2))
+ return (FALSE);
- return(*time1 != *time2);
-} /* time_eq() */
+ return (*time1 != *time2);
+} /* time_eq() */
bool
-time_lt(TimeADT *time1, TimeADT *time2)
+time_lt(TimeADT * time1, TimeADT * time2)
{
- if (!PointerIsValid(time1) || !PointerIsValid(time2))
- return(FALSE);
+ if (!PointerIsValid(time1) || !PointerIsValid(time2))
+ return (FALSE);
- return(*time1 < *time2);
-} /* time_eq() */
+ return (*time1 < *time2);
+} /* time_eq() */
bool
-time_le(TimeADT *time1, TimeADT *time2)
+time_le(TimeADT * time1, TimeADT * time2)
{
- if (!PointerIsValid(time1) || !PointerIsValid(time2))
- return(FALSE);
+ if (!PointerIsValid(time1) || !PointerIsValid(time2))
+ return (FALSE);
- return(*time1 <= *time2);
-} /* time_eq() */
+ return (*time1 <= *time2);
+} /* time_eq() */
bool
-time_gt(TimeADT *time1, TimeADT *time2)
+time_gt(TimeADT * time1, TimeADT * time2)
{
- if (!PointerIsValid(time1) || !PointerIsValid(time2))
- return(FALSE);
+ if (!PointerIsValid(time1) || !PointerIsValid(time2))
+ return (FALSE);
- return(*time1 > *time2);
-} /* time_eq() */
+ return (*time1 > *time2);
+} /* time_eq() */
bool
-time_ge(TimeADT *time1, TimeADT *time2)
+time_ge(TimeADT * time1, TimeADT * time2)
{
- if (!PointerIsValid(time1) || !PointerIsValid(time2))
- return(FALSE);
+ if (!PointerIsValid(time1) || !PointerIsValid(time2))
+ return (FALSE);
- return(*time1 >= *time2);
-} /* time_eq() */
+ return (*time1 >= *time2);
+} /* time_eq() */
int
-time_cmp(TimeADT *time1, TimeADT *time2)
+time_cmp(TimeADT * time1, TimeADT * time2)
{
- return((*time1 < *time2)? -1: (((*time1 > *time2)? 1: 0)));
-} /* time_cmp() */
+ return ((*time1 < *time2) ? -1 : (((*time1 > *time2) ? 1 : 0)));
+} /* time_cmp() */
/* datetime_datetime()
* Convert date and time to datetime data type.
*/
-DateTime *
-datetime_datetime(DateADT date, TimeADT *time)
+DateTime *
+datetime_datetime(DateADT date, TimeADT * time)
{
- DateTime *result;
+ DateTime *result;
- if (!PointerIsValid(time)) {
- result = PALLOCTYPE(DateTime);
- DATETIME_INVALID(*result);
+ if (!PointerIsValid(time))
+ {
+ result = PALLOCTYPE(DateTime);
+ DATETIME_INVALID(*result);
- } else {
- result = date_datetime(date);
- *result += *time;
- }
+ }
+ else
+ {
+ result = date_datetime(date);
+ *result += *time;
+ }
- return(result);
-} /* datetime_datetime() */
+ return (result);
+} /* datetime_datetime() */
-int32 /* RelativeTime */
+int32 /* RelativeTime */
int42reltime(int32 timevalue)
{
- return(timevalue);
+ return (timevalue);
}
diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c
index 493843071cd..eb314176bab 100644
--- a/src/backend/utils/adt/datum.c
+++ b/src/backend/utils/adt/datum.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.5 1997/08/19 21:34:33 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.6 1997/09/07 04:50:09 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -49,39 +49,51 @@
Size
datumGetSize(Datum value, Oid type, bool byVal, Size len)
{
-
- struct varlena *s;
- Size size = 0;
-
- if (byVal) {
- if (len <= sizeof(Datum)) {
- size = len;
- } else {
- elog(WARN,
- "datumGetSize: Error: type=%ld, byVaL with len=%d",
- (long) type, len);
+
+ struct varlena *s;
+ Size size = 0;
+
+ if (byVal)
+ {
+ if (len <= sizeof(Datum))
+ {
+ size = len;
+ }
+ else
+ {
+ elog(WARN,
+ "datumGetSize: Error: type=%ld, byVaL with len=%d",
+ (long) type, len);
+ }
}
- } else { /* not byValue */
- if (len == -1) {
- /*
- * variable length type
- * Look at the varlena struct for its real length...
- */
- s = (struct varlena *) DatumGetPointer(value);
- if (!PointerIsValid(s)) {
- elog(WARN,
- "datumGetSize: Invalid Datum Pointer");
- }
- size = (Size) VARSIZE(s);
- } else {
- /*
- * fixed length type
- */
- size = len;
+ else
+ { /* not byValue */
+ if (len == -1)
+ {
+
+ /*
+ * variable length type Look at the varlena struct for its
+ * real length...
+ */
+ s = (struct varlena *) DatumGetPointer(value);
+ if (!PointerIsValid(s))
+ {
+ elog(WARN,
+ "datumGetSize: Invalid Datum Pointer");
+ }
+ size = (Size) VARSIZE(s);
+ }
+ else
+ {
+
+ /*
+ * fixed length type
+ */
+ size = len;
+ }
}
- }
-
- return(size);
+
+ return (size);
}
/*-------------------------------------------------------------------------
@@ -97,29 +109,35 @@ datumGetSize(Datum value, Oid type, bool byVal, Size len)
Datum
datumCopy(Datum value, Oid type, bool byVal, Size len)
{
-
- Size realSize;
- Datum res;
- char *s;
-
-
- if (byVal) {
- res = value;
- } else {
- if (value == 0) return((Datum)NULL);
- realSize = datumGetSize(value, type, byVal, len);
- /*
- * the value is a pointer. Allocate enough space
- * and copy the pointed data.
- */
- s = (char *) palloc(realSize);
- if (s == NULL) {
- elog(WARN,"datumCopy: out of memory\n");
+
+ Size realSize;
+ Datum res;
+ char *s;
+
+
+ if (byVal)
+ {
+ res = value;
}
- memmove(s, DatumGetPointer(value), realSize);
- res = (Datum)s;
- }
- return(res);
+ else
+ {
+ if (value == 0)
+ return ((Datum) NULL);
+ realSize = datumGetSize(value, type, byVal, len);
+
+ /*
+ * the value is a pointer. Allocate enough space and copy the
+ * pointed data.
+ */
+ s = (char *) palloc(realSize);
+ if (s == NULL)
+ {
+ elog(WARN, "datumCopy: out of memory\n");
+ }
+ memmove(s, DatumGetPointer(value), realSize);
+ res = (Datum) s;
+ }
+ return (res);
}
/*-------------------------------------------------------------------------
@@ -135,20 +153,23 @@ datumCopy(Datum value, Oid type, bool byVal, Size len)
void
datumFree(Datum value, Oid type, bool byVal, Size len)
{
-
- Size realSize;
- Pointer s;
-
- realSize = datumGetSize(value, type, byVal, len);
-
- if (!byVal) {
- /*
- * free the space palloced by "datumCopy()"
- */
- s = DatumGetPointer(value);
- pfree(s);
- }
+
+ Size realSize;
+ Pointer s;
+
+ realSize = datumGetSize(value, type, byVal, len);
+
+ if (!byVal)
+ {
+
+ /*
+ * free the space palloced by "datumCopy()"
+ */
+ s = DatumGetPointer(value);
+ pfree(s);
+ }
}
+
#endif
/*-------------------------------------------------------------------------
@@ -167,36 +188,40 @@ datumFree(Datum value, Oid type, bool byVal, Size len)
bool
datumIsEqual(Datum value1, Datum value2, Oid type, bool byVal, Size len)
{
- Size size1, size2;
- char *s1, *s2;
-
- if (byVal) {
- /*
- * just compare the two datums.
- * NOTE: just comparing "len" bytes will not do the
- * work, because we do not know how these bytes
- * are aligned inside the "Datum".
- */
- if (value1 == value2)
- return(true);
- else
- return(false);
- } else {
- /*
- * byVal = false
- * Compare the bytes pointed by the pointers stored in the
- * datums.
- */
- size1 = datumGetSize(value1, type, byVal, len);
- size2 = datumGetSize(value2, type, byVal, len);
- if (size1 != size2)
- return(false);
- s1 = (char *) DatumGetPointer(value1);
- s2 = (char *) DatumGetPointer(value2);
- if (!memcmp(s1, s2, size1))
- return(true);
+ Size size1,
+ size2;
+ char *s1,
+ *s2;
+
+ if (byVal)
+ {
+
+ /*
+ * just compare the two datums. NOTE: just comparing "len" bytes
+ * will not do the work, because we do not know how these bytes
+ * are aligned inside the "Datum".
+ */
+ if (value1 == value2)
+ return (true);
+ else
+ return (false);
+ }
else
- return(false);
- }
-}
+ {
+ /*
+ * byVal = false Compare the bytes pointed by the pointers stored
+ * in the datums.
+ */
+ size1 = datumGetSize(value1, type, byVal, len);
+ size2 = datumGetSize(value2, type, byVal, len);
+ if (size1 != size2)
+ return (false);
+ s1 = (char *) DatumGetPointer(value1);
+ s2 = (char *) DatumGetPointer(value2);
+ if (!memcmp(s1, s2, size1))
+ return (true);
+ else
+ return (false);
+ }
+}
diff --git a/src/backend/utils/adt/dt.c b/src/backend/utils/adt/dt.c
index 803f0d63669..b3eca30144c 100644
--- a/src/backend/utils/adt/dt.c
+++ b/src/backend/utils/adt/dt.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* dt.c--
- * Functions for the built-in type "dt".
+ * Functions for the built-in type "dt".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.37 1997/09/06 00:22:44 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.38 1997/09/07 04:50:11 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,54 +21,57 @@
#include "postgres.h"
#include "miscadmin.h"
#ifdef HAVE_FLOAT_H
-# include <float.h>
+#include <float.h>
#endif
#ifdef HAVE_LIMITS_H
-# include <limits.h>
+#include <limits.h>
#endif
#ifndef USE_POSIX_TIME
#include <sys/timeb.h>
#endif
#include "utils/builtins.h"
-static int DecodeDate(char *str, int fmask, int *tmask, struct tm *tm);
-static int DecodeNumber( int flen, char *field,
- int fmask, int *tmask, struct tm *tm, double *fsec);
-static int DecodeNumberField( int len, char *str,
- int fmask, int *tmask, struct tm *tm, double *fsec);
-static int DecodeSpecial(int field, char *lowtoken, int *val);
-static int DecodeTime(char *str, int fmask, int *tmask,
- struct tm *tm, double *fsec);
-static int DecodeTimezone( char *str, int *tzp);
-static int DecodeUnits(int field, char *lowtoken, int *val);
-static int EncodeSpecialDateTime(DateTime dt, char *str);
-static datetkn *datebsearch(char *key, datetkn *base, unsigned int nel);
-static DateTime dt2local( DateTime dt, int timezone);
-static void dt2time(DateTime dt, int *hour, int *min, double *sec);
-static int j2day( int jd);
-static int timespan2tm(TimeSpan span, struct tm *tm, float8 *fsec);
-static int tm2timespan(struct tm *tm, double fsec, TimeSpan *span);
+static int DecodeDate(char *str, int fmask, int *tmask, struct tm * tm);
+static int
+DecodeNumber(int flen, char *field,
+ int fmask, int *tmask, struct tm * tm, double *fsec);
+static int
+DecodeNumberField(int len, char *str,
+ int fmask, int *tmask, struct tm * tm, double *fsec);
+static int DecodeSpecial(int field, char *lowtoken, int *val);
+static int
+DecodeTime(char *str, int fmask, int *tmask,
+ struct tm * tm, double *fsec);
+static int DecodeTimezone(char *str, int *tzp);
+static int DecodeUnits(int field, char *lowtoken, int *val);
+static int EncodeSpecialDateTime(DateTime dt, char *str);
+static datetkn *datebsearch(char *key, datetkn * base, unsigned int nel);
+static DateTime dt2local(DateTime dt, int timezone);
+static void dt2time(DateTime dt, int *hour, int *min, double *sec);
+static int j2day(int jd);
+static int timespan2tm(TimeSpan span, struct tm * tm, float8 * fsec);
+static int tm2timespan(struct tm * tm, double fsec, TimeSpan * span);
#define USE_DATE_CACHE 1
#define ROUND_ALL 0
#define isleap(y) (((y % 4) == 0) && (((y % 100) != 0) || ((y % 400) == 0)))
-int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
+int mdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0};
-char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
+char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
-char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
- "Thursday", "Friday", "Saturday", NULL};
+char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
+"Thursday", "Friday", "Saturday", NULL};
/* TMODULO()
* Macro to replace modf(), which is broken on some platforms.
*/
#define TMODULO(t,q,u) {q = ((t < 0)? ceil(t / u): floor(t / u)); \
- if (q != 0) t -= rint(q * u);}
+ if (q != 0) t -= rint(q * u);}
-static void GetEpochTime( struct tm *tm);
+static void GetEpochTime(struct tm * tm);
#define UTIME_MINYEAR (1901)
#define UTIME_MINMONTH (12)
@@ -85,1728 +88,1975 @@ static void GetEpochTime( struct tm *tm);
|| ((m == UTIME_MAXMONTH) && (d <= UTIME_MAXDAY))))))
-/*****************************************************************************
- * USER I/O ROUTINES *
+/*****************************************************************************
+ * USER I/O ROUTINES *
*****************************************************************************/
/* datetime_in()
* Convert a string to internal form.
*/
-DateTime *
+DateTime *
datetime_in(char *str)
{
- DateTime *result;
+ DateTime *result;
- double fsec;
- struct tm tt, *tm = &tt;
- int tz;
- int dtype;
- int nf;
- char *field[MAXDATEFIELDS];
- int ftype[MAXDATEFIELDS];
- char lowstr[MAXDATELEN+1];
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
+ int tz;
+ int dtype;
+ int nf;
+ char *field[MAXDATEFIELDS];
+ int ftype[MAXDATEFIELDS];
+ char lowstr[MAXDATELEN + 1];
- if (!PointerIsValid(str))
- elog(WARN,"Bad (null) datetime external representation",NULL);
+ if (!PointerIsValid(str))
+ elog(WARN, "Bad (null) datetime external representation", NULL);
- if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateTime( field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
- elog(WARN,"Bad datetime external representation %s",str);
+ if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
+ elog(WARN, "Bad datetime external representation %s", str);
- result = PALLOCTYPE(DateTime);
+ result = PALLOCTYPE(DateTime);
- switch (dtype) {
- case DTK_DATE:
- if (tm2datetime( tm, fsec, &tz, result) != 0)
- elog(WARN,"Datetime out of range %s",str);
+ switch (dtype)
+ {
+ case DTK_DATE:
+ if (tm2datetime(tm, fsec, &tz, result) != 0)
+ elog(WARN, "Datetime out of range %s", str);
#ifdef DATEDEBUG
-printf( "datetime_in- date is %f\n", *result);
+ printf("datetime_in- date is %f\n", *result);
#endif
- break;
+ break;
- case DTK_EPOCH:
- DATETIME_EPOCH(*result);
- break;
+ case DTK_EPOCH:
+ DATETIME_EPOCH(*result);
+ break;
- case DTK_CURRENT:
- DATETIME_CURRENT(*result);
- break;
+ case DTK_CURRENT:
+ DATETIME_CURRENT(*result);
+ break;
- case DTK_LATE:
- DATETIME_NOEND(*result);
- break;
+ case DTK_LATE:
+ DATETIME_NOEND(*result);
+ break;
- case DTK_EARLY:
- DATETIME_NOBEGIN(*result);
- break;
+ case DTK_EARLY:
+ DATETIME_NOBEGIN(*result);
+ break;
- case DTK_INVALID:
- DATETIME_INVALID(*result);
- break;
+ case DTK_INVALID:
+ DATETIME_INVALID(*result);
+ break;
- default:
- elog(WARN,"Internal coding error, can't input datetime '%s'",str);
- }
+ default:
+ elog(WARN, "Internal coding error, can't input datetime '%s'", str);
+ }
- return(result);
-} /* datetime_in() */
+ return (result);
+} /* datetime_in() */
/* datetime_out()
* Convert a datetime to external form.
*/
-char *
-datetime_out(DateTime *dt)
+char *
+datetime_out(DateTime * dt)
{
- char *result;
- int tz;
- struct tm tt, *tm = &tt;
- double fsec;
- char *tzn;
- char buf[MAXDATELEN+1];
+ char *result;
+ int tz;
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
+ char *tzn;
+ char buf[MAXDATELEN + 1];
- if (!PointerIsValid(dt))
- return(NULL);
+ if (!PointerIsValid(dt))
+ return (NULL);
- if (DATETIME_IS_RESERVED(*dt)) {
- EncodeSpecialDateTime(*dt, buf);
+ if (DATETIME_IS_RESERVED(*dt))
+ {
+ EncodeSpecialDateTime(*dt, buf);
- } else if (datetime2tm( *dt, &tz, tm, &fsec, &tzn) == 0) {
- EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
+ }
+ else if (datetime2tm(*dt, &tz, tm, &fsec, &tzn) == 0)
+ {
+ EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
- } else {
- EncodeSpecialDateTime(DT_INVALID, buf);
- }
+ }
+ else
+ {
+ EncodeSpecialDateTime(DT_INVALID, buf);
+ }
- result = PALLOC(strlen(buf)+1);
+ result = PALLOC(strlen(buf) + 1);
- strcpy( result, buf);
+ strcpy(result, buf);
- return( result);
-} /* datetime_out() */
+ return (result);
+} /* datetime_out() */
/* timespan_in()
* Convert a string to internal form.
*
* External format(s):
- * Uses the generic date/time parsing and decoding routines.
+ * Uses the generic date/time parsing and decoding routines.
*/
-TimeSpan *
+TimeSpan *
timespan_in(char *str)
{
- TimeSpan *span;
+ TimeSpan *span;
- double fsec;
- struct tm tt, *tm = &tt;
- int dtype;
- int nf;
- char *field[MAXDATEFIELDS];
- int ftype[MAXDATEFIELDS];
- char lowstr[MAXDATELEN+1];
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
+ int dtype;
+ int nf;
+ char *field[MAXDATEFIELDS];
+ int ftype[MAXDATEFIELDS];
+ char lowstr[MAXDATELEN + 1];
- tm->tm_year = 0;
- tm->tm_mon = 0;
- tm->tm_mday = 0;
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- fsec = 0;
+ tm->tm_year = 0;
+ tm->tm_mon = 0;
+ tm->tm_mday = 0;
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ fsec = 0;
- if (!PointerIsValid(str))
- elog(WARN,"Bad (null) timespan external representation",NULL);
+ if (!PointerIsValid(str))
+ elog(WARN, "Bad (null) timespan external representation", NULL);
- if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateDelta( field, ftype, nf, &dtype, tm, &fsec) != 0))
- elog(WARN,"Bad timespan external representation '%s'",str);
+ if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeDateDelta(field, ftype, nf, &dtype, tm, &fsec) != 0))
+ elog(WARN, "Bad timespan external representation '%s'", str);
- span = PALLOCTYPE(TimeSpan);
+ span = PALLOCTYPE(TimeSpan);
- switch (dtype) {
- case DTK_DELTA:
- if (tm2timespan(tm, fsec, span) != 0) {
+ switch (dtype)
+ {
+ case DTK_DELTA:
+ if (tm2timespan(tm, fsec, span) != 0)
+ {
#if FALSE
- TIMESPAN_INVALID(span);
+ TIMESPAN_INVALID(span);
#endif
- elog(WARN,"Bad timespan external representation %s",str);
- }
- break;
+ elog(WARN, "Bad timespan external representation %s", str);
+ }
+ break;
- default:
- elog(WARN,"Internal coding error, can't input timespan '%s'",str);
- }
+ default:
+ elog(WARN, "Internal coding error, can't input timespan '%s'", str);
+ }
- return(span);
-} /* timespan_in() */
+ return (span);
+} /* timespan_in() */
/* timespan_out()
* Convert a time span to external form.
*/
-char *
-timespan_out(TimeSpan *span)
+char *
+timespan_out(TimeSpan * span)
{
- char *result;
+ char *result;
- struct tm tt, *tm = &tt;
- double fsec;
- char buf[MAXDATELEN+1];
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
+ char buf[MAXDATELEN + 1];
- if (!PointerIsValid(span))
- return(NULL);
+ if (!PointerIsValid(span))
+ return (NULL);
- if (timespan2tm(*span, tm, &fsec) != 0)
- return(NULL);
+ if (timespan2tm(*span, tm, &fsec) != 0)
+ return (NULL);
- if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0)
- elog(WARN,"Unable to format timespan",NULL);
+ if (EncodeTimeSpan(tm, fsec, DateStyle, buf) != 0)
+ elog(WARN, "Unable to format timespan", NULL);
- result = PALLOC(strlen(buf)+1);
+ result = PALLOC(strlen(buf) + 1);
- strcpy( result, buf);
- return( result);
-} /* timespan_out() */
+ strcpy(result, buf);
+ return (result);
+} /* timespan_out() */
-/*****************************************************************************
- * PUBLIC ROUTINES *
+/*****************************************************************************
+ * PUBLIC ROUTINES *
*****************************************************************************/
bool
-datetime_finite(DateTime *datetime)
+datetime_finite(DateTime * datetime)
{
- if (!PointerIsValid(datetime))
- return FALSE;
+ if (!PointerIsValid(datetime))
+ return FALSE;
- return(! DATETIME_NOT_FINITE(*datetime));
-} /* datetime_finite() */
+ return (!DATETIME_NOT_FINITE(*datetime));
+} /* datetime_finite() */
#ifdef NOT_USED
bool
-timespan_finite(TimeSpan *timespan)
+timespan_finite(TimeSpan * timespan)
{
- if (!PointerIsValid(timespan))
- return FALSE;
+ if (!PointerIsValid(timespan))
+ return FALSE;
+
+ return (!TIMESPAN_NOT_FINITE(*timespan));
+} /* timespan_finite() */
- return(! TIMESPAN_NOT_FINITE(*timespan));
-} /* timespan_finite() */
#endif
/*----------------------------------------------------------
- * Relational operators for datetime.
+ * Relational operators for datetime.
*---------------------------------------------------------*/
static void
-GetEpochTime( struct tm *tm)
+GetEpochTime(struct tm * tm)
{
- struct tm *t0;
- time_t epoch = 0;
+ struct tm *t0;
+ time_t epoch = 0;
- t0 = gmtime( &epoch);
+ t0 = gmtime(&epoch);
- tm->tm_year = t0->tm_year;
- tm->tm_mon = t0->tm_mon;
- tm->tm_mday = t0->tm_mday;
- tm->tm_hour = t0->tm_hour;
- tm->tm_min = t0->tm_min;
- tm->tm_sec = t0->tm_sec;
+ tm->tm_year = t0->tm_year;
+ tm->tm_mon = t0->tm_mon;
+ tm->tm_mday = t0->tm_mday;
+ tm->tm_hour = t0->tm_hour;
+ tm->tm_min = t0->tm_min;
+ tm->tm_sec = t0->tm_sec;
- if (tm->tm_year < 1900) tm->tm_year += 1900;
- tm->tm_mon++;
+ if (tm->tm_year < 1900)
+ tm->tm_year += 1900;
+ tm->tm_mon++;
#ifdef DATEDEBUG
-printf( "GetEpochTime- %04d-%02d-%02d %02d:%02d:%02d\n",
- tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ printf("GetEpochTime- %04d-%02d-%02d %02d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
#endif
- return;
-} /* GetEpochTime() */
+ return;
+} /* GetEpochTime() */
DateTime
-SetDateTime( DateTime dt) {
- struct tm tt;
+SetDateTime(DateTime dt)
+{
+ struct tm tt;
- if (DATETIME_IS_CURRENT(dt)) {
- GetCurrentTime(&tt);
- tm2datetime( &tt, 0, NULL, &dt);
- dt = dt2local( dt, -CTimeZone);
+ if (DATETIME_IS_CURRENT(dt))
+ {
+ GetCurrentTime(&tt);
+ tm2datetime(&tt, 0, NULL, &dt);
+ dt = dt2local(dt, -CTimeZone);
#ifdef DATEDEBUG
-printf( "SetDateTime- current time is %f\n", dt);
+ printf("SetDateTime- current time is %f\n", dt);
#endif
- } else { /* if (DATETIME_IS_EPOCH(dt1)) */
- GetEpochTime(&tt);
- tm2datetime( &tt, 0, NULL, &dt);
+ }
+ else
+ { /* if (DATETIME_IS_EPOCH(dt1)) */
+ GetEpochTime(&tt);
+ tm2datetime(&tt, 0, NULL, &dt);
#ifdef DATEDEBUG
-printf( "SetDateTime- epoch time is %f\n", dt);
+ printf("SetDateTime- epoch time is %f\n", dt);
#endif
- }
+ }
- return(dt);
-} /* SetDateTime() */
+ return (dt);
+} /* SetDateTime() */
-/* datetime_relop - is datetime1 relop datetime2
+/* datetime_relop - is datetime1 relop datetime2
*/
bool
-datetime_eq(DateTime *datetime1, DateTime *datetime2)
+datetime_eq(DateTime * datetime1, DateTime * datetime2)
{
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return FALSE;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return FALSE;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
- return FALSE;
+ if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
+ return FALSE;
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
- return( dt1 == dt2);
-} /* datetime_eq() */
+ return (dt1 == dt2);
+} /* datetime_eq() */
bool
-datetime_ne(DateTime *datetime1, DateTime *datetime2)
+datetime_ne(DateTime * datetime1, DateTime * datetime2)
{
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return FALSE;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return FALSE;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
- return FALSE;
+ if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
+ return FALSE;
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
- return( dt1 != dt2);
-} /* datetime_ne() */
+ return (dt1 != dt2);
+} /* datetime_ne() */
bool
-datetime_lt(DateTime *datetime1, DateTime *datetime2)
+datetime_lt(DateTime * datetime1, DateTime * datetime2)
{
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return FALSE;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return FALSE;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
- return FALSE;
+ if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
+ return FALSE;
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
- return( dt1 < dt2);
-} /* datetime_lt() */
+ return (dt1 < dt2);
+} /* datetime_lt() */
bool
-datetime_gt(DateTime *datetime1, DateTime *datetime2)
+datetime_gt(DateTime * datetime1, DateTime * datetime2)
{
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return FALSE;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return FALSE;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
- return FALSE;
+ if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
+ return FALSE;
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
#ifdef DATEDEBUG
-printf( "datetime_gt- %f %s greater than %f\n", dt1, ((dt1 > dt2)? "is": "is not"), dt2);
+ printf("datetime_gt- %f %s greater than %f\n", dt1, ((dt1 > dt2) ? "is" : "is not"), dt2);
#endif
- return( dt1 > dt2);
-} /* datetime_gt() */
+ return (dt1 > dt2);
+} /* datetime_gt() */
bool
-datetime_le(DateTime *datetime1, DateTime *datetime2)
+datetime_le(DateTime * datetime1, DateTime * datetime2)
{
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return FALSE;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return FALSE;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
- return FALSE;
+ if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
+ return FALSE;
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
- return( dt1 <= dt2);
-} /* datetime_le() */
+ return (dt1 <= dt2);
+} /* datetime_le() */
bool
-datetime_ge(DateTime *datetime1, DateTime *datetime2)
+datetime_ge(DateTime * datetime1, DateTime * datetime2)
{
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return FALSE;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return FALSE;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
- return FALSE;
+ if (DATETIME_IS_INVALID(dt1) || DATETIME_IS_INVALID(dt2))
+ return FALSE;
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
- return( dt1 >= dt2);
-} /* datetime_ge() */
+ return (dt1 >= dt2);
+} /* datetime_ge() */
-/* datetime_cmp - 3-state comparison for datetime
- * collate invalid datetime at the end
+/* datetime_cmp - 3-state comparison for datetime
+ * collate invalid datetime at the end
*/
int
-datetime_cmp(DateTime *datetime1, DateTime *datetime2)
+datetime_cmp(DateTime * datetime1, DateTime * datetime2)
{
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return 0;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return 0;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- if (DATETIME_IS_INVALID(dt1)) {
- return( (DATETIME_IS_INVALID(dt2)? 0: 1));
+ if (DATETIME_IS_INVALID(dt1))
+ {
+ return ((DATETIME_IS_INVALID(dt2) ? 0 : 1));
- } else if (DATETIME_IS_INVALID(dt2)) {
- return( -1);
+ }
+ else if (DATETIME_IS_INVALID(dt2))
+ {
+ return (-1);
- } else {
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
- }
+ }
+ else
+ {
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
+ }
- return( ((dt1 < dt2)? -1: ((dt1 > dt2)? 1: 0)));
-} /* datetime_cmp() */
+ return (((dt1 < dt2) ? -1 : ((dt1 > dt2) ? 1 : 0)));
+} /* datetime_cmp() */
-/* timespan_relop - is timespan1 relop timespan2
+/* timespan_relop - is timespan1 relop timespan2
*/
bool
-timespan_eq(TimeSpan *timespan1, TimeSpan *timespan2)
+timespan_eq(TimeSpan * timespan1, TimeSpan * timespan2)
{
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return FALSE;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return FALSE;
- if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
- return FALSE;
+ if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
+ return FALSE;
- return( (timespan1->time == timespan2->time)
- && (timespan1->month == timespan2->month));
-} /* timespan_eq() */
+ return ((timespan1->time == timespan2->time)
+ && (timespan1->month == timespan2->month));
+} /* timespan_eq() */
bool
-timespan_ne(TimeSpan *timespan1, TimeSpan *timespan2)
+timespan_ne(TimeSpan * timespan1, TimeSpan * timespan2)
{
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return FALSE;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return FALSE;
- if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
- return FALSE;
+ if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
+ return FALSE;
- return( (timespan1->time != timespan2->time)
- || (timespan1->month != timespan2->month));
-} /* timespan_ne() */
+ return ((timespan1->time != timespan2->time)
+ || (timespan1->month != timespan2->month));
+} /* timespan_ne() */
bool
-timespan_lt(TimeSpan *timespan1, TimeSpan *timespan2)
+timespan_lt(TimeSpan * timespan1, TimeSpan * timespan2)
{
- double span1, span2;
+ double span1,
+ span2;
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return FALSE;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return FALSE;
- if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
- return FALSE;
+ if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
+ return FALSE;
- span1 = timespan1->time;
- if (timespan1->month != 0) span1 += (timespan1->month * (30.0*86400));
- span2 = timespan2->time;
- if (timespan2->month != 0) span2 += (timespan2->month * (30.0*86400));
+ span1 = timespan1->time;
+ if (timespan1->month != 0)
+ span1 += (timespan1->month * (30.0 * 86400));
+ span2 = timespan2->time;
+ if (timespan2->month != 0)
+ span2 += (timespan2->month * (30.0 * 86400));
- return( span1 < span2);
-} /* timespan_lt() */
+ return (span1 < span2);
+} /* timespan_lt() */
bool
-timespan_gt(TimeSpan *timespan1, TimeSpan *timespan2)
+timespan_gt(TimeSpan * timespan1, TimeSpan * timespan2)
{
- double span1, span2;
+ double span1,
+ span2;
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return FALSE;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return FALSE;
- if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
- return FALSE;
+ if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
+ return FALSE;
- span1 = timespan1->time;
- if (timespan1->month != 0) span1 += (timespan1->month * (30.0*86400));
- span2 = timespan2->time;
- if (timespan2->month != 0) span2 += (timespan2->month * (30.0*86400));
+ span1 = timespan1->time;
+ if (timespan1->month != 0)
+ span1 += (timespan1->month * (30.0 * 86400));
+ span2 = timespan2->time;
+ if (timespan2->month != 0)
+ span2 += (timespan2->month * (30.0 * 86400));
- return( span1 > span2);
-} /* timespan_gt() */
+ return (span1 > span2);
+} /* timespan_gt() */
bool
-timespan_le(TimeSpan *timespan1, TimeSpan *timespan2)
+timespan_le(TimeSpan * timespan1, TimeSpan * timespan2)
{
- double span1, span2;
+ double span1,
+ span2;
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return FALSE;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return FALSE;
- if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
- return FALSE;
+ if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
+ return FALSE;
- span1 = timespan1->time;
- if (timespan1->month != 0) span1 += (timespan1->month * (30.0*86400));
- span2 = timespan2->time;
- if (timespan2->month != 0) span2 += (timespan2->month * (30.0*86400));
+ span1 = timespan1->time;
+ if (timespan1->month != 0)
+ span1 += (timespan1->month * (30.0 * 86400));
+ span2 = timespan2->time;
+ if (timespan2->month != 0)
+ span2 += (timespan2->month * (30.0 * 86400));
- return( span1 <= span2);
-} /* timespan_le() */
+ return (span1 <= span2);
+} /* timespan_le() */
bool
-timespan_ge(TimeSpan *timespan1, TimeSpan *timespan2)
+timespan_ge(TimeSpan * timespan1, TimeSpan * timespan2)
{
- double span1, span2;
+ double span1,
+ span2;
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return FALSE;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return FALSE;
- if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
- return FALSE;
+ if (TIMESPAN_IS_INVALID(*timespan1) || TIMESPAN_IS_INVALID(*timespan2))
+ return FALSE;
- span1 = timespan1->time;
- if (timespan1->month != 0) span1 += (timespan1->month * (30.0*86400));
- span2 = timespan2->time;
- if (timespan2->month != 0) span2 += (timespan2->month * (30.0*86400));
+ span1 = timespan1->time;
+ if (timespan1->month != 0)
+ span1 += (timespan1->month * (30.0 * 86400));
+ span2 = timespan2->time;
+ if (timespan2->month != 0)
+ span2 += (timespan2->month * (30.0 * 86400));
- return( span1 >= span2);
-} /* timespan_ge() */
+ return (span1 >= span2);
+} /* timespan_ge() */
-/* timespan_cmp - 3-state comparison for timespan
+/* timespan_cmp - 3-state comparison for timespan
*/
int
-timespan_cmp(TimeSpan *timespan1, TimeSpan *timespan2)
+timespan_cmp(TimeSpan * timespan1, TimeSpan * timespan2)
{
- double span1, span2;
+ double span1,
+ span2;
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return 0;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return 0;
- if (TIMESPAN_IS_INVALID(*timespan1)) {
- return( TIMESPAN_IS_INVALID(*timespan2)? 0: 1);
+ if (TIMESPAN_IS_INVALID(*timespan1))
+ {
+ return (TIMESPAN_IS_INVALID(*timespan2) ? 0 : 1);
- } else if (TIMESPAN_IS_INVALID(*timespan2)) {
- return( -1);
- }
+ }
+ else if (TIMESPAN_IS_INVALID(*timespan2))
+ {
+ return (-1);
+ }
- span1 = timespan1->time;
- if (timespan1->month != 0) span1 += (timespan1->month * (30.0*86400));
- span2 = timespan2->time;
- if (timespan2->month != 0) span2 += (timespan2->month * (30.0*86400));
+ span1 = timespan1->time;
+ if (timespan1->month != 0)
+ span1 += (timespan1->month * (30.0 * 86400));
+ span2 = timespan2->time;
+ if (timespan2->month != 0)
+ span2 += (timespan2->month * (30.0 * 86400));
- return( (span1 < span2)? -1: (span1 > span2)? 1: 0);
-} /* timespan_cmp() */
+ return ((span1 < span2) ? -1 : (span1 > span2) ? 1 : 0);
+} /* timespan_cmp() */
/*----------------------------------------------------------
- * "Arithmetic" operators on date/times.
- * datetime_foo returns foo as an object (pointer) that
- * can be passed between languages.
- * datetime_xx is an internal routine which returns the
- * actual value.
+ * "Arithmetic" operators on date/times.
+ * datetime_foo returns foo as an object (pointer) that
+ * can be passed between languages.
+ * datetime_xx is an internal routine which returns the
+ * actual value.
*---------------------------------------------------------*/
-DateTime *
-datetime_smaller(DateTime *datetime1, DateTime *datetime2)
+DateTime *
+datetime_smaller(DateTime * datetime1, DateTime * datetime2)
{
- DateTime *result;
+ DateTime *result;
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return NULL;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return NULL;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- result = PALLOCTYPE(DateTime);
+ result = PALLOCTYPE(DateTime);
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
- if (DATETIME_IS_INVALID(dt1)) {
- *result = dt2;
- } else if (DATETIME_IS_INVALID(dt2)) {
- *result = dt1;
- } else {
- *result = ((dt2 < dt1)? dt2: dt1);
- }
+ if (DATETIME_IS_INVALID(dt1))
+ {
+ *result = dt2;
+ }
+ else if (DATETIME_IS_INVALID(dt2))
+ {
+ *result = dt1;
+ }
+ else
+ {
+ *result = ((dt2 < dt1) ? dt2 : dt1);
+ }
- return(result);
-} /* datetime_smaller() */
+ return (result);
+} /* datetime_smaller() */
-DateTime *
-datetime_larger(DateTime *datetime1, DateTime *datetime2)
+DateTime *
+datetime_larger(DateTime * datetime1, DateTime * datetime2)
{
- DateTime *result;
+ DateTime *result;
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return NULL;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return NULL;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- result = PALLOCTYPE(DateTime);
+ result = PALLOCTYPE(DateTime);
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
- if (DATETIME_IS_INVALID(dt1)) {
- *result = dt2;
- } else if (DATETIME_IS_INVALID(dt2)) {
- *result = dt1;
- } else {
- *result = ((dt2 > dt1)? dt2: dt1);
- }
+ if (DATETIME_IS_INVALID(dt1))
+ {
+ *result = dt2;
+ }
+ else if (DATETIME_IS_INVALID(dt2))
+ {
+ *result = dt1;
+ }
+ else
+ {
+ *result = ((dt2 > dt1) ? dt2 : dt1);
+ }
- return(result);
-} /* datetime_larger() */
+ return (result);
+} /* datetime_larger() */
-TimeSpan *
-datetime_mi(DateTime *datetime1, DateTime *datetime2)
+TimeSpan *
+datetime_mi(DateTime * datetime1, DateTime * datetime2)
{
- TimeSpan *result;
+ TimeSpan *result;
- DateTime dt1, dt2;
+ DateTime dt1,
+ dt2;
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return NULL;
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return NULL;
- dt1 = *datetime1;
- dt2 = *datetime2;
+ dt1 = *datetime1;
+ dt2 = *datetime2;
- result = PALLOCTYPE(TimeSpan);
+ result = PALLOCTYPE(TimeSpan);
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
#ifdef DATEDEBUG
-printf( "datetime_mi- evaluate %f - %f\n", dt1, dt2);
+ printf("datetime_mi- evaluate %f - %f\n", dt1, dt2);
#endif
- if (DATETIME_IS_INVALID(dt1)
- || DATETIME_IS_INVALID(dt2)) {
- DATETIME_INVALID( result->time);
+ if (DATETIME_IS_INVALID(dt1)
+ || DATETIME_IS_INVALID(dt2))
+ {
+ DATETIME_INVALID(result->time);
- } else {
- result->time = JROUND(dt1 - dt2);
- }
- result->month = 0;
+ }
+ else
+ {
+ result->time = JROUND(dt1 - dt2);
+ }
+ result->month = 0;
- return(result);
-} /* datetime_mi() */
+ return (result);
+} /* datetime_mi() */
/* datetime_pl_span()
* Add a timespan to a datetime data type.
* Note that timespan has provisions for qualitative year/month
- * units, so try to do the right thing with them.
+ * units, so try to do the right thing with them.
* To add a month, increment the month, and use the same day of month.
* Then, if the next month has fewer days, set the day of month
- * to the last day of month.
+ * to the last day of month.
*/
-DateTime *
-datetime_pl_span(DateTime *datetime, TimeSpan *span)
+DateTime *
+datetime_pl_span(DateTime * datetime, TimeSpan * span)
{
- DateTime *result;
- DateTime dt;
- int tz;
- char *tzn;
+ DateTime *result;
+ DateTime dt;
+ int tz;
+ char *tzn;
- if ((!PointerIsValid(datetime)) || (!PointerIsValid(span)))
- return NULL;
+ if ((!PointerIsValid(datetime)) || (!PointerIsValid(span)))
+ return NULL;
- result = PALLOCTYPE(DateTime);
+ result = PALLOCTYPE(DateTime);
#ifdef DATEDEBUG
-printf( "datetime_pl_span- add %f to %d %f\n", *datetime, span->month, span->time);
+ printf("datetime_pl_span- add %f to %d %f\n", *datetime, span->month, span->time);
#endif
- if (DATETIME_NOT_FINITE(*datetime)) {
- *result = *datetime;
+ if (DATETIME_NOT_FINITE(*datetime))
+ {
+ *result = *datetime;
- } else if (TIMESPAN_IS_INVALID(*span)) {
- DATETIME_INVALID(*result);
+ }
+ else if (TIMESPAN_IS_INVALID(*span))
+ {
+ DATETIME_INVALID(*result);
- } else {
- dt = (DATETIME_IS_RELATIVE(*datetime)? SetDateTime(*datetime): *datetime);
+ }
+ else
+ {
+ dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
#ifdef ROUND_ALL
- dt = JROUND(dt + span->time);
+ dt = JROUND(dt + span->time);
#else
- dt += span->time;
+ dt += span->time;
#endif
- if (span->month != 0) {
- struct tm tt, *tm = &tt;
- double fsec;
+ if (span->month != 0)
+ {
+ struct tm tt,
+ *tm = &tt;
+ double fsec;
- if (datetime2tm( dt, &tz, tm, &fsec, &tzn) == 0) {
+ if (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0)
+ {
#ifdef DATEDEBUG
-printf( "datetime_pl_span- date was %04d-%02d-%02d %02d:%02d:%02d\n",
- tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ printf("datetime_pl_span- date was %04d-%02d-%02d %02d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
#endif
- tm->tm_mon += span->month;
- if (tm->tm_mon > 12) {
- tm->tm_year += ((tm->tm_mon-1) / 12);
- tm->tm_mon = (((tm->tm_mon-1) % 12) + 1);
- } else if (tm->tm_mon < 1) {
- tm->tm_year += ((tm->tm_mon / 12) - 1);
- tm->tm_mon = ((tm->tm_mon % 12) + 12);
- }
-
- /* adjust for end of month boundary problems... */
- if (tm->tm_mday > mdays[ tm->tm_mon-1]) {
- if ((tm->tm_mon == 2) && isleap( tm->tm_year)) {
- tm->tm_mday = (mdays[ tm->tm_mon-1]+1);
- } else {
- tm->tm_mday = mdays[ tm->tm_mon-1];
- }
- }
+ tm->tm_mon += span->month;
+ if (tm->tm_mon > 12)
+ {
+ tm->tm_year += ((tm->tm_mon - 1) / 12);
+ tm->tm_mon = (((tm->tm_mon - 1) % 12) + 1);
+ }
+ else if (tm->tm_mon < 1)
+ {
+ tm->tm_year += ((tm->tm_mon / 12) - 1);
+ tm->tm_mon = ((tm->tm_mon % 12) + 12);
+ }
+
+ /* adjust for end of month boundary problems... */
+ if (tm->tm_mday > mdays[tm->tm_mon - 1])
+ {
+ if ((tm->tm_mon == 2) && isleap(tm->tm_year))
+ {
+ tm->tm_mday = (mdays[tm->tm_mon - 1] + 1);
+ }
+ else
+ {
+ tm->tm_mday = mdays[tm->tm_mon - 1];
+ }
+ }
#ifdef DATEDEBUG
-printf( "datetime_pl_span- date becomes %04d-%02d-%02d %02d:%02d:%02d\n",
- tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ printf("datetime_pl_span- date becomes %04d-%02d-%02d %02d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
#endif
- if (tm2datetime( tm, fsec, &tz, &dt) != 0)
- elog(WARN,"Unable to add datetime and timespan",NULL);
+ if (tm2datetime(tm, fsec, &tz, &dt) != 0)
+ elog(WARN, "Unable to add datetime and timespan", NULL);
+
+ }
+ else
+ {
+ DATETIME_INVALID(dt);
+ }
+ }
- } else {
- DATETIME_INVALID(dt);
- }
+ *result = dt;
}
- *result = dt;
- }
-
- return(result);
-} /* datetime_pl_span() */
+ return (result);
+} /* datetime_pl_span() */
-DateTime *
-datetime_mi_span(DateTime *datetime, TimeSpan *span)
+DateTime *
+datetime_mi_span(DateTime * datetime, TimeSpan * span)
{
- DateTime *result;
- TimeSpan tspan;
+ DateTime *result;
+ TimeSpan tspan;
- if (!PointerIsValid(datetime) || !PointerIsValid(span))
- return NULL;
+ if (!PointerIsValid(datetime) || !PointerIsValid(span))
+ return NULL;
- tspan.month = -span->month;
- tspan.time = -span->time;
+ tspan.month = -span->month;
+ tspan.time = -span->time;
- result = datetime_pl_span( datetime, &tspan);
+ result = datetime_pl_span(datetime, &tspan);
- return(result);
-} /* datetime_mi_span() */
+ return (result);
+} /* datetime_mi_span() */
-TimeSpan *
-timespan_um(TimeSpan *timespan)
+TimeSpan *
+timespan_um(TimeSpan * timespan)
{
- TimeSpan *result;
+ TimeSpan *result;
- if (!PointerIsValid(timespan))
- return NULL;
+ if (!PointerIsValid(timespan))
+ return NULL;
- result = PALLOCTYPE(TimeSpan);
+ result = PALLOCTYPE(TimeSpan);
- result->time = -(timespan->time);
- result->month = -(timespan->month);
+ result->time = -(timespan->time);
+ result->month = -(timespan->month);
- return(result);
-} /* timespan_um() */
+ return (result);
+} /* timespan_um() */
-TimeSpan *
-timespan_smaller(TimeSpan *timespan1, TimeSpan *timespan2)
+TimeSpan *
+timespan_smaller(TimeSpan * timespan1, TimeSpan * timespan2)
{
- TimeSpan *result;
+ TimeSpan *result;
- double span1, span2;
+ double span1,
+ span2;
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return NULL;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return NULL;
- result = PALLOCTYPE(TimeSpan);
+ result = PALLOCTYPE(TimeSpan);
- if (TIMESPAN_IS_INVALID(*timespan1)) {
- result->time = timespan2->time;
- result->month = timespan2->month;
+ if (TIMESPAN_IS_INVALID(*timespan1))
+ {
+ result->time = timespan2->time;
+ result->month = timespan2->month;
- } else if (TIMESPAN_IS_INVALID(*timespan2)) {
- result->time = timespan1->time;
- result->month = timespan1->month;
+ }
+ else if (TIMESPAN_IS_INVALID(*timespan2))
+ {
+ result->time = timespan1->time;
+ result->month = timespan1->month;
- } else {
- span1 = timespan1->time;
- if (timespan1->month != 0) span1 += (timespan1->month * (30.0*86400));
- span2 = timespan2->time;
- if (timespan2->month != 0) span2 += (timespan2->month * (30.0*86400));
+ }
+ else
+ {
+ span1 = timespan1->time;
+ if (timespan1->month != 0)
+ span1 += (timespan1->month * (30.0 * 86400));
+ span2 = timespan2->time;
+ if (timespan2->month != 0)
+ span2 += (timespan2->month * (30.0 * 86400));
#ifdef DATEDEBUG
-printf( "timespan_smaller- months %d %d times %f %f spans %f %f\n",
- timespan1->month, timespan2->month, timespan1->time, timespan2->time, span1, span2);
+ printf("timespan_smaller- months %d %d times %f %f spans %f %f\n",
+ timespan1->month, timespan2->month, timespan1->time, timespan2->time, span1, span2);
#endif
- if (span2 < span1) {
- result->time = timespan2->time;
- result->month = timespan2->month;
+ if (span2 < span1)
+ {
+ result->time = timespan2->time;
+ result->month = timespan2->month;
- } else {
- result->time = timespan1->time;
- result->month = timespan1->month;
+ }
+ else
+ {
+ result->time = timespan1->time;
+ result->month = timespan1->month;
+ }
}
- }
- return(result);
-} /* timespan_smaller() */
+ return (result);
+} /* timespan_smaller() */
-TimeSpan *
-timespan_larger(TimeSpan *timespan1, TimeSpan *timespan2)
+TimeSpan *
+timespan_larger(TimeSpan * timespan1, TimeSpan * timespan2)
{
- TimeSpan *result;
+ TimeSpan *result;
- double span1, span2;
+ double span1,
+ span2;
- if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
- return NULL;
+ if (!PointerIsValid(timespan1) || !PointerIsValid(timespan2))
+ return NULL;
- result = PALLOCTYPE(TimeSpan);
+ result = PALLOCTYPE(TimeSpan);
- if (TIMESPAN_IS_INVALID(*timespan1)) {
- result->time = timespan2->time;
- result->month = timespan2->month;
+ if (TIMESPAN_IS_INVALID(*timespan1))
+ {
+ result->time = timespan2->time;
+ result->month = timespan2->month;
- } else if (TIMESPAN_IS_INVALID(*timespan2)) {
- result->time = timespan1->time;
- result->month = timespan1->month;
+ }
+ else if (TIMESPAN_IS_INVALID(*timespan2))
+ {
+ result->time = timespan1->time;
+ result->month = timespan1->month;
- } else {
- span1 = timespan1->time;
- if (timespan1->month != 0) span1 += (timespan1->month * (30.0*86400));
- span2 = timespan2->time;
- if (timespan2->month != 0) span2 += (timespan2->month * (30.0*86400));
+ }
+ else
+ {
+ span1 = timespan1->time;
+ if (timespan1->month != 0)
+ span1 += (timespan1->month * (30.0 * 86400));
+ span2 = timespan2->time;
+ if (timespan2->month != 0)
+ span2 += (timespan2->month * (30.0 * 86400));
#ifdef DATEDEBUG
-printf( "timespan_larger- months %d %d times %f %f spans %f %f\n",
- timespan1->month, timespan2->month, timespan1->time, timespan2->time, span1, span2);
+ printf("timespan_larger- months %d %d times %f %f spans %f %f\n",
+ timespan1->month, timespan2->month, timespan1->time, timespan2->time, span1, span2);
#endif
- if (span2 > span1) {
- result->time = timespan2->time;
- result->month = timespan2->month;
+ if (span2 > span1)
+ {
+ result->time = timespan2->time;
+ result->month = timespan2->month;
- } else {
- result->time = timespan1->time;
- result->month = timespan1->month;
+ }
+ else
+ {
+ result->time = timespan1->time;
+ result->month = timespan1->month;
+ }
}
- }
- return(result);
-} /* timespan_larger() */
+ return (result);
+} /* timespan_larger() */
-TimeSpan *
-timespan_pl(TimeSpan *span1, TimeSpan *span2)
+TimeSpan *
+timespan_pl(TimeSpan * span1, TimeSpan * span2)
{
- TimeSpan *result;
+ TimeSpan *result;
- if ((!PointerIsValid(span1)) || (!PointerIsValid(span2)))
- return NULL;
+ if ((!PointerIsValid(span1)) || (!PointerIsValid(span2)))
+ return NULL;
- result = PALLOCTYPE(TimeSpan);
+ result = PALLOCTYPE(TimeSpan);
- result->month = (span1->month + span2->month);
- result->time = JROUND(span1->time + span2->time);
+ result->month = (span1->month + span2->month);
+ result->time = JROUND(span1->time + span2->time);
- return(result);
-} /* timespan_pl() */
+ return (result);
+} /* timespan_pl() */
-TimeSpan *
-timespan_mi(TimeSpan *span1, TimeSpan *span2)
+TimeSpan *
+timespan_mi(TimeSpan * span1, TimeSpan * span2)
{
- TimeSpan *result;
+ TimeSpan *result;
- if ((!PointerIsValid(span1)) || (!PointerIsValid(span2)))
- return NULL;
+ if ((!PointerIsValid(span1)) || (!PointerIsValid(span2)))
+ return NULL;
- result = PALLOCTYPE(TimeSpan);
+ result = PALLOCTYPE(TimeSpan);
- result->month = (span1->month - span2->month);
- result->time = JROUND(span1->time - span2->time);
+ result->month = (span1->month - span2->month);
+ result->time = JROUND(span1->time - span2->time);
- return(result);
-} /* timespan_mi() */
+ return (result);
+} /* timespan_mi() */
-TimeSpan *
-timespan_div(TimeSpan *span1, float8 *arg2)
+TimeSpan *
+timespan_div(TimeSpan * span1, float8 * arg2)
{
- TimeSpan *result;
+ TimeSpan *result;
- if ((!PointerIsValid(span1)) || (!PointerIsValid(arg2)))
- return NULL;
+ if ((!PointerIsValid(span1)) || (!PointerIsValid(arg2)))
+ return NULL;
- if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
- elog(WARN,"Memory allocation failed, can't subtract timespans",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(TimeSpan)))
+ elog(WARN, "Memory allocation failed, can't subtract timespans", NULL);
- if (*arg2 == 0.0)
- elog(WARN,"timespan_div: divide by 0.0 error");
+ if (*arg2 == 0.0)
+ elog(WARN, "timespan_div: divide by 0.0 error");
- result->month = rint(span1->month / *arg2);
- result->time = JROUND(span1->time / *arg2);
+ result->month = rint(span1->month / *arg2);
+ result->time = JROUND(span1->time / *arg2);
- return(result);
-} /* timespan_div() */
+ return (result);
+} /* timespan_div() */
/* datetime_age()
* Calculate time difference while retaining year/month fields.
* Note that this does not result in an accurate absolute time span
- * since year and month are out of context once the arithmetic
- * is done.
+ * since year and month are out of context once the arithmetic
+ * is done.
*/
-TimeSpan *
-datetime_age(DateTime *datetime1, DateTime *datetime2)
+TimeSpan *
+datetime_age(DateTime * datetime1, DateTime * datetime2)
{
- TimeSpan *result;
-
- DateTime dt1, dt2;
- double fsec, fsec1, fsec2;
- struct tm tt, *tm = &tt;
- struct tm tt1, *tm1 = &tt1;
- struct tm tt2, *tm2 = &tt2;
+ TimeSpan *result;
+
+ DateTime dt1,
+ dt2;
+ double fsec,
+ fsec1,
+ fsec2;
+ struct tm tt,
+ *tm = &tt;
+ struct tm tt1,
+ *tm1 = &tt1;
+ struct tm tt2,
+ *tm2 = &tt2;
+
+ if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
+ return NULL;
+
+ result = PALLOCTYPE(TimeSpan);
+
+ dt1 = *datetime1;
+ dt2 = *datetime2;
+
+ if (DATETIME_IS_RELATIVE(dt1))
+ dt1 = SetDateTime(dt1);
+ if (DATETIME_IS_RELATIVE(dt2))
+ dt2 = SetDateTime(dt2);
+
+ if (DATETIME_IS_INVALID(dt1)
+ || DATETIME_IS_INVALID(dt2))
+ {
+ DATETIME_INVALID(result->time);
- if (!PointerIsValid(datetime1) || !PointerIsValid(datetime2))
- return NULL;
-
- result = PALLOCTYPE(TimeSpan);
-
- dt1 = *datetime1;
- dt2 = *datetime2;
-
- if (DATETIME_IS_RELATIVE(dt1)) dt1 = SetDateTime(dt1);
- if (DATETIME_IS_RELATIVE(dt2)) dt2 = SetDateTime(dt2);
-
- if (DATETIME_IS_INVALID(dt1)
- || DATETIME_IS_INVALID(dt2)) {
- DATETIME_INVALID( result->time);
-
- } else if ((datetime2tm( dt1, NULL, tm1, &fsec1, NULL) == 0)
- &&(datetime2tm( dt2, NULL, tm2, &fsec2, NULL) == 0)) {
- fsec = (fsec1 - fsec2);
- tm->tm_sec = (tm1->tm_sec - tm2->tm_sec);
- tm->tm_min = (tm1->tm_min - tm2->tm_min);
- tm->tm_hour = (tm1->tm_hour - tm2->tm_hour);
- tm->tm_mday = (tm1->tm_mday - tm2->tm_mday);
- tm->tm_mon = (tm1->tm_mon - tm2->tm_mon);
- tm->tm_year = (tm1->tm_year - tm2->tm_year);
-
- /* flip sign if necessary... */
- if (dt1 < dt2) {
- fsec = -fsec;
- tm->tm_sec = -tm->tm_sec;
- tm->tm_min = -tm->tm_min;
- tm->tm_hour = -tm->tm_hour;
- tm->tm_mday = -tm->tm_mday;
- tm->tm_mon = -tm->tm_mon;
- tm->tm_year = -tm->tm_year;
}
+ else if ((datetime2tm(dt1, NULL, tm1, &fsec1, NULL) == 0)
+ && (datetime2tm(dt2, NULL, tm2, &fsec2, NULL) == 0))
+ {
+ fsec = (fsec1 - fsec2);
+ tm->tm_sec = (tm1->tm_sec - tm2->tm_sec);
+ tm->tm_min = (tm1->tm_min - tm2->tm_min);
+ tm->tm_hour = (tm1->tm_hour - tm2->tm_hour);
+ tm->tm_mday = (tm1->tm_mday - tm2->tm_mday);
+ tm->tm_mon = (tm1->tm_mon - tm2->tm_mon);
+ tm->tm_year = (tm1->tm_year - tm2->tm_year);
+
+ /* flip sign if necessary... */
+ if (dt1 < dt2)
+ {
+ fsec = -fsec;
+ tm->tm_sec = -tm->tm_sec;
+ tm->tm_min = -tm->tm_min;
+ tm->tm_hour = -tm->tm_hour;
+ tm->tm_mday = -tm->tm_mday;
+ tm->tm_mon = -tm->tm_mon;
+ tm->tm_year = -tm->tm_year;
+ }
- if (tm->tm_sec < 0) {
- tm->tm_sec += 60;
- tm->tm_min--;
- }
+ if (tm->tm_sec < 0)
+ {
+ tm->tm_sec += 60;
+ tm->tm_min--;
+ }
- if (tm->tm_min < 0) {
- tm->tm_min += 60;
- tm->tm_hour--;
- }
+ if (tm->tm_min < 0)
+ {
+ tm->tm_min += 60;
+ tm->tm_hour--;
+ }
- if (tm->tm_hour < 0) {
- tm->tm_hour += 24;
- tm->tm_mday--;
- }
+ if (tm->tm_hour < 0)
+ {
+ tm->tm_hour += 24;
+ tm->tm_mday--;
+ }
- if (tm->tm_mday < 0) {
- if (dt1 < dt2) {
- tm->tm_mday += mdays[tm1->tm_mon-1];
- if (isleap(tm1->tm_year) && (tm1->tm_mon == 2)) tm->tm_mday++;
- tm->tm_mon--;
- } else {
- tm->tm_mday += mdays[tm2->tm_mon-1];
- if (isleap(tm2->tm_year) && (tm2->tm_mon == 2)) tm->tm_mday++;
- tm->tm_mon--;
- }
- }
+ if (tm->tm_mday < 0)
+ {
+ if (dt1 < dt2)
+ {
+ tm->tm_mday += mdays[tm1->tm_mon - 1];
+ if (isleap(tm1->tm_year) && (tm1->tm_mon == 2))
+ tm->tm_mday++;
+ tm->tm_mon--;
+ }
+ else
+ {
+ tm->tm_mday += mdays[tm2->tm_mon - 1];
+ if (isleap(tm2->tm_year) && (tm2->tm_mon == 2))
+ tm->tm_mday++;
+ tm->tm_mon--;
+ }
+ }
- if (tm->tm_mon < 0) {
- tm->tm_mon += 12;
- tm->tm_year--;
- }
+ if (tm->tm_mon < 0)
+ {
+ tm->tm_mon += 12;
+ tm->tm_year--;
+ }
- /* recover sign if necessary... */
- if (dt1 < dt2) {
- fsec = -fsec;
- tm->tm_sec = -tm->tm_sec;
- tm->tm_min = -tm->tm_min;
- tm->tm_hour = -tm->tm_hour;
- tm->tm_mday = -tm->tm_mday;
- tm->tm_mon = -tm->tm_mon;
- tm->tm_year = -tm->tm_year;
- }
+ /* recover sign if necessary... */
+ if (dt1 < dt2)
+ {
+ fsec = -fsec;
+ tm->tm_sec = -tm->tm_sec;
+ tm->tm_min = -tm->tm_min;
+ tm->tm_hour = -tm->tm_hour;
+ tm->tm_mday = -tm->tm_mday;
+ tm->tm_mon = -tm->tm_mon;
+ tm->tm_year = -tm->tm_year;
+ }
- if (tm2timespan(tm, fsec, result) != 0) {
- elog(WARN,"Unable to decode datetime",NULL);
- }
+ if (tm2timespan(tm, fsec, result) != 0)
+ {
+ elog(WARN, "Unable to decode datetime", NULL);
+ }
#if FALSE
- result->time = (fsec2 - fsec1);
- result->time += (tm2->tm_sec - tm1->tm_sec);
- result->time += 60*(tm2->tm_min - tm1->tm_min);
- result->time += 3600*(tm2->tm_hour - tm1->tm_hour);
- result->time += 86400*(tm2->tm_mday - tm1->tm_mday);
-
- result->month = 12*(tm2->tm_year - tm1->tm_year);
- result->month += (tm2->tm_mon - tm1->tm_mon);
+ result->time = (fsec2 - fsec1);
+ result->time += (tm2->tm_sec - tm1->tm_sec);
+ result->time += 60 * (tm2->tm_min - tm1->tm_min);
+ result->time += 3600 * (tm2->tm_hour - tm1->tm_hour);
+ result->time += 86400 * (tm2->tm_mday - tm1->tm_mday);
+
+ result->month = 12 * (tm2->tm_year - tm1->tm_year);
+ result->month += (tm2->tm_mon - tm1->tm_mon);
#endif
- } else {
- elog(WARN,"Unable to decode datetime",NULL);
- }
+ }
+ else
+ {
+ elog(WARN, "Unable to decode datetime", NULL);
+ }
- return(result);
-} /* datetime_age() */
+ return (result);
+} /* datetime_age() */
/*----------------------------------------------------------
- * Conversion operators.
+ * Conversion operators.
*---------------------------------------------------------*/
/* datetime_text()
* Convert datetime to text data type.
*/
-text *
-datetime_text(DateTime *datetime)
+text *
+datetime_text(DateTime * datetime)
{
- text *result;
- char *str;
- int len;
+ text *result;
+ char *str;
+ int len;
- if (!PointerIsValid(datetime))
- return NULL;
+ if (!PointerIsValid(datetime))
+ return NULL;
- str = datetime_out(datetime);
+ str = datetime_out(datetime);
- if (!PointerIsValid(str))
- return NULL;
+ if (!PointerIsValid(str))
+ return NULL;
- len = (strlen(str)+VARHDRSZ);
+ len = (strlen(str) + VARHDRSZ);
- result = PALLOC(len);
+ result = PALLOC(len);
- VARSIZE(result) = len;
- memmove(VARDATA(result), str, (len-VARHDRSZ));
+ VARSIZE(result) = len;
+ memmove(VARDATA(result), str, (len - VARHDRSZ));
- PFREE(str);
+ PFREE(str);
- return(result);
-} /* datetime_text() */
+ return (result);
+} /* datetime_text() */
/* text_datetime()
* Convert text string to datetime.
* Text type is not null terminated, so use temporary string
- * then call the standard input routine.
+ * then call the standard input routine.
*/
-DateTime *
-text_datetime(text *str)
+DateTime *
+text_datetime(text * str)
{
- DateTime *result;
- int i;
- char *sp, *dp, dstr[MAXDATELEN+1];
+ DateTime *result;
+ int i;
+ char *sp,
+ *dp,
+ dstr[MAXDATELEN + 1];
- if (!PointerIsValid(str))
- return NULL;
+ if (!PointerIsValid(str))
+ return NULL;
- sp = VARDATA(str);
- dp = dstr;
- for (i = 0; i < (VARSIZE(str)-VARHDRSZ); i++) *dp++ = *sp++;
- *dp = '\0';
+ sp = VARDATA(str);
+ dp = dstr;
+ for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
+ *dp++ = *sp++;
+ *dp = '\0';
- result = datetime_in(dstr);
+ result = datetime_in(dstr);
- return(result);
-} /* text_datetime() */
+ return (result);
+} /* text_datetime() */
/* timespan_text()
* Convert timespan to text data type.
*/
-text *
-timespan_text(TimeSpan *timespan)
+text *
+timespan_text(TimeSpan * timespan)
{
- text *result;
- char *str;
- int len;
+ text *result;
+ char *str;
+ int len;
- if (!PointerIsValid(timespan))
- return NULL;
+ if (!PointerIsValid(timespan))
+ return NULL;
- str = timespan_out(timespan);
+ str = timespan_out(timespan);
- if (!PointerIsValid(str))
- return NULL;
+ if (!PointerIsValid(str))
+ return NULL;
- len = (strlen(str)+VARHDRSZ);
+ len = (strlen(str) + VARHDRSZ);
- result = PALLOC(len);
+ result = PALLOC(len);
- VARSIZE(result) = len;
- memmove(VARDATA(result), str, (len-VARHDRSZ));
+ VARSIZE(result) = len;
+ memmove(VARDATA(result), str, (len - VARHDRSZ));
- PFREE(str);
+ PFREE(str);
- return(result);
-} /* timespan_text() */
+ return (result);
+} /* timespan_text() */
/* text_timespan()
* Convert text string to timespan.
* Text type may not be null terminated, so copy to temporary string
- * then call the standard input routine.
+ * then call the standard input routine.
*/
#ifdef NOT_USED
-TimeSpan *
-text_timespan(text *str)
+TimeSpan *
+text_timespan(text * str)
{
- TimeSpan *result;
- int i;
- char *sp, *dp, dstr[MAXDATELEN+1];
+ TimeSpan *result;
+ int i;
+ char *sp,
+ *dp,
+ dstr[MAXDATELEN + 1];
- if (!PointerIsValid(str))
- return NULL;
+ if (!PointerIsValid(str))
+ return NULL;
+
+ sp = VARDATA(str);
+ dp = dstr;
+ for (i = 0; i < (VARSIZE(str) - VARHDRSZ); i++)
+ *dp++ = *sp++;
+ *dp = '\0';
- sp = VARDATA(str);
- dp = dstr;
- for (i = 0; i < (VARSIZE(str)-VARHDRSZ); i++) *dp++ = *sp++;
- *dp = '\0';
+ result = timespan_in(dstr);
- result = timespan_in(dstr);
+ return (result);
+} /* text_timespan() */
- return(result);
-} /* text_timespan() */
#endif
/* datetime_trunc()
* Extract specified field from datetime.
*/
-DateTime *
-datetime_trunc(text *units, DateTime *datetime)
+DateTime *
+datetime_trunc(text * units, DateTime * datetime)
{
- DateTime *result;
-
- DateTime dt;
- int tz;
- int type, val;
- int i;
- char *up, *lp, lowunits[MAXDATELEN+1];
- double fsec;
- char *tzn;
- struct tm tt, *tm = &tt;
-
- if ((!PointerIsValid(units)) || (!PointerIsValid(datetime)))
- return NULL;
-
- result = PALLOCTYPE(DateTime);
-
- up = VARDATA(units);
- lp = lowunits;
- for (i = 0; i < (VARSIZE(units)-VARHDRSZ); i++) *lp++ = tolower( *up++);
- *lp = '\0';
-
- type = DecodeUnits( 0, lowunits, &val);
+ DateTime *result;
+
+ DateTime dt;
+ int tz;
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowunits[MAXDATELEN + 1];
+ double fsec;
+ char *tzn;
+ struct tm tt,
+ *tm = &tt;
+
+ if ((!PointerIsValid(units)) || (!PointerIsValid(datetime)))
+ return NULL;
+
+ result = PALLOCTYPE(DateTime);
+
+ up = VARDATA(units);
+ lp = lowunits;
+ for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
+ *lp++ = tolower(*up++);
+ *lp = '\0';
+
+ type = DecodeUnits(0, lowunits, &val);
#if FALSE
- if (type == IGNORE) {
- type = DecodeSpecial( 0, lowunits, &val);
- }
+ if (type == IGNORE)
+ {
+ type = DecodeSpecial(0, lowunits, &val);
+ }
#endif
#ifdef DATEDEBUG
-if (type == IGNORE) strcpy(lowunits, "(unknown)");
-printf( "datetime_trunc- units %s type=%d value=%d\n", lowunits, type, val);
+ if (type == IGNORE)
+ strcpy(lowunits, "(unknown)");
+ printf("datetime_trunc- units %s type=%d value=%d\n", lowunits, type, val);
#endif
- if (DATETIME_NOT_FINITE(*datetime)) {
+ if (DATETIME_NOT_FINITE(*datetime))
+ {
#if FALSE
/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */
- elog(WARN,"Datetime is not finite",NULL);
-#endif
- *result = 0;
-
- } else {
- dt = (DATETIME_IS_RELATIVE(*datetime)? SetDateTime(*datetime): *datetime);
-
- if ((type == UNITS) && (datetime2tm( dt, &tz, tm, &fsec, &tzn) == 0)) {
- switch (val) {
- case DTK_MILLENIUM:
- tm->tm_year = (tm->tm_year/1000)*1000;
- case DTK_CENTURY:
- tm->tm_year = (tm->tm_year/100)*100;
- case DTK_DECADE:
- tm->tm_year = (tm->tm_year/10)*10;
- case DTK_YEAR:
- tm->tm_mon = 1;
- case DTK_QUARTER:
- tm->tm_mon = (3*(tm->tm_mon/4))+1;
- case DTK_MONTH:
- tm->tm_mday = 1;
- case DTK_DAY:
- tm->tm_hour = 0;
- case DTK_HOUR:
- tm->tm_min = 0;
- case DTK_MINUTE:
- tm->tm_sec = 0;
- case DTK_SECOND:
- fsec = 0;
- break;
-
- case DTK_MILLISEC:
- fsec = rint(fsec*1000)/1000;
- break;
-
- case DTK_MICROSEC:
- fsec = rint(fsec*1000)/1000;
- break;
-
- default:
- elog(WARN,"Datetime units %s not supported",lowunits);
- result = NULL;
- }
+ elog(WARN, "Datetime is not finite", NULL);
+#endif
+ *result = 0;
- if (IS_VALID_UTIME( tm->tm_year, tm->tm_mon, tm->tm_mday)) {
+ }
+ else
+ {
+ dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
+
+ if ((type == UNITS) && (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0))
+ {
+ switch (val)
+ {
+ case DTK_MILLENIUM:
+ tm->tm_year = (tm->tm_year / 1000) * 1000;
+ case DTK_CENTURY:
+ tm->tm_year = (tm->tm_year / 100) * 100;
+ case DTK_DECADE:
+ tm->tm_year = (tm->tm_year / 10) * 10;
+ case DTK_YEAR:
+ tm->tm_mon = 1;
+ case DTK_QUARTER:
+ tm->tm_mon = (3 * (tm->tm_mon / 4)) + 1;
+ case DTK_MONTH:
+ tm->tm_mday = 1;
+ case DTK_DAY:
+ tm->tm_hour = 0;
+ case DTK_HOUR:
+ tm->tm_min = 0;
+ case DTK_MINUTE:
+ tm->tm_sec = 0;
+ case DTK_SECOND:
+ fsec = 0;
+ break;
+
+ case DTK_MILLISEC:
+ fsec = rint(fsec * 1000) / 1000;
+ break;
+
+ case DTK_MICROSEC:
+ fsec = rint(fsec * 1000) / 1000;
+ break;
+
+ default:
+ elog(WARN, "Datetime units %s not supported", lowunits);
+ result = NULL;
+ }
+
+ if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
+ {
#ifdef USE_POSIX_TIME
- tm->tm_isdst = -1;
- tm->tm_year -= 1900;
- tm->tm_mon -= 1;
- tm->tm_isdst = -1;
- mktime(tm);
- tm->tm_year += 1900;
- tm->tm_mon += 1;
+ tm->tm_isdst = -1;
+ tm->tm_year -= 1900;
+ tm->tm_mon -= 1;
+ tm->tm_isdst = -1;
+ mktime(tm);
+ tm->tm_year += 1900;
+ tm->tm_mon += 1;
#ifdef HAVE_INT_TIMEZONE
- tz = ((tm->tm_isdst > 0)? (timezone - 3600): timezone);
+ tz = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
-#else /* !HAVE_INT_TIMEZONE */
- tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
+#else /* !HAVE_INT_TIMEZONE */
+ tz = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
#endif
-#else /* !USE_POSIX_TIME */
- tz = CTimeZone;
+#else /* !USE_POSIX_TIME */
+ tz = CTimeZone;
#endif
- } else {
- tm->tm_isdst = 0;
- tz = 0;
- }
+ }
+ else
+ {
+ tm->tm_isdst = 0;
+ tz = 0;
+ }
- if (tm2datetime( tm, fsec, &tz, result) != 0)
- elog(WARN,"Unable to truncate datetime to %s",lowunits);
+ if (tm2datetime(tm, fsec, &tz, result) != 0)
+ elog(WARN, "Unable to truncate datetime to %s", lowunits);
#if FALSE
- } else if ((type == RESERV) && (val == DTK_EPOCH)) {
- DATETIME_EPOCH(*result);
- *result = dt - SetDateTime(*result);
+ }
+ else if ((type == RESERV) && (val == DTK_EPOCH))
+ {
+ DATETIME_EPOCH(*result);
+ *result = dt - SetDateTime(*result);
#endif
- } else {
- elog(WARN,"Datetime units %s not recognized",lowunits);
- result = NULL;
+ }
+ else
+ {
+ elog(WARN, "Datetime units %s not recognized", lowunits);
+ result = NULL;
+ }
}
- }
- return(result);
-} /* datetime_trunc() */
+ return (result);
+} /* datetime_trunc() */
/* timespan_trunc()
* Extract specified field from timespan.
*/
-TimeSpan *
-timespan_trunc(text *units, TimeSpan *timespan)
+TimeSpan *
+timespan_trunc(text * units, TimeSpan * timespan)
{
- TimeSpan *result;
-
- int type, val;
- int i;
- char *up, *lp, lowunits[MAXDATELEN+1];
- double fsec;
- struct tm tt, *tm = &tt;
-
- if ((!PointerIsValid(units)) || (!PointerIsValid(timespan)))
- return NULL;
-
- result = PALLOCTYPE(TimeSpan);
-
- up = VARDATA(units);
- lp = lowunits;
- for (i = 0; i < (VARSIZE(units)-VARHDRSZ); i++) *lp++ = tolower( *up++);
- *lp = '\0';
-
- type = DecodeUnits( 0, lowunits, &val);
+ TimeSpan *result;
+
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowunits[MAXDATELEN + 1];
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
+
+ if ((!PointerIsValid(units)) || (!PointerIsValid(timespan)))
+ return NULL;
+
+ result = PALLOCTYPE(TimeSpan);
+
+ up = VARDATA(units);
+ lp = lowunits;
+ for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
+ *lp++ = tolower(*up++);
+ *lp = '\0';
+
+ type = DecodeUnits(0, lowunits, &val);
#if FALSE
- if (type == IGNORE) {
- type = DecodeSpecial( 0, lowunits, &val);
- }
+ if (type == IGNORE)
+ {
+ type = DecodeSpecial(0, lowunits, &val);
+ }
#endif
#ifdef DATEDEBUG
-if (type == IGNORE) strcpy(lowunits, "(unknown)");
-printf( "timespan_trunc- units %s type=%d value=%d\n", lowunits, type, val);
+ if (type == IGNORE)
+ strcpy(lowunits, "(unknown)");
+ printf("timespan_trunc- units %s type=%d value=%d\n", lowunits, type, val);
#endif
- if (TIMESPAN_IS_INVALID(*timespan)) {
+ if (TIMESPAN_IS_INVALID(*timespan))
+ {
#if FALSE
- elog(WARN,"Timespan is not finite",NULL);
+ elog(WARN, "Timespan is not finite", NULL);
#endif
- result = NULL;
-
- } else if (type == UNITS) {
-
- if (timespan2tm(*timespan, tm, &fsec) == 0) {
- switch (val) {
- case DTK_MILLENIUM:
- tm->tm_year = (tm->tm_year/1000)*1000;
- case DTK_CENTURY:
- tm->tm_year = (tm->tm_year/100)*100;
- case DTK_DECADE:
- tm->tm_year = (tm->tm_year/10)*10;
- case DTK_YEAR:
- tm->tm_mon = 0;
- case DTK_QUARTER:
- tm->tm_mon = (3*(tm->tm_mon/4));
- case DTK_MONTH:
- tm->tm_mday = 0;
- case DTK_DAY:
- tm->tm_hour = 0;
- case DTK_HOUR:
- tm->tm_min = 0;
- case DTK_MINUTE:
- tm->tm_sec = 0;
- case DTK_SECOND:
- fsec = 0;
- break;
-
- case DTK_MILLISEC:
- fsec = rint(fsec*1000)/1000;
- break;
-
- case DTK_MICROSEC:
- fsec = rint(fsec*1000)/1000;
- break;
-
- default:
- elog(WARN,"Timespan units %s not supported",lowunits);
result = NULL;
- }
-
- if (tm2timespan(tm, fsec, result) != 0)
- elog(WARN,"Unable to truncate timespan to %s",lowunits);
- } else {
- elog(NOTICE,"Timespan out of range",NULL);
- result = NULL;
}
+ else if (type == UNITS)
+ {
+
+ if (timespan2tm(*timespan, tm, &fsec) == 0)
+ {
+ switch (val)
+ {
+ case DTK_MILLENIUM:
+ tm->tm_year = (tm->tm_year / 1000) * 1000;
+ case DTK_CENTURY:
+ tm->tm_year = (tm->tm_year / 100) * 100;
+ case DTK_DECADE:
+ tm->tm_year = (tm->tm_year / 10) * 10;
+ case DTK_YEAR:
+ tm->tm_mon = 0;
+ case DTK_QUARTER:
+ tm->tm_mon = (3 * (tm->tm_mon / 4));
+ case DTK_MONTH:
+ tm->tm_mday = 0;
+ case DTK_DAY:
+ tm->tm_hour = 0;
+ case DTK_HOUR:
+ tm->tm_min = 0;
+ case DTK_MINUTE:
+ tm->tm_sec = 0;
+ case DTK_SECOND:
+ fsec = 0;
+ break;
+
+ case DTK_MILLISEC:
+ fsec = rint(fsec * 1000) / 1000;
+ break;
+
+ case DTK_MICROSEC:
+ fsec = rint(fsec * 1000) / 1000;
+ break;
+
+ default:
+ elog(WARN, "Timespan units %s not supported", lowunits);
+ result = NULL;
+ }
+
+ if (tm2timespan(tm, fsec, result) != 0)
+ elog(WARN, "Unable to truncate timespan to %s", lowunits);
+
+ }
+ else
+ {
+ elog(NOTICE, "Timespan out of range", NULL);
+ result = NULL;
+ }
#if FALSE
- } else if ((type == RESERV) && (val == DTK_EPOCH)) {
- *result = timespan->time;
- if (timespan->month != 0) {
- *result += ((365.25*86400)*(timespan->month / 12));
- *result += ((30*86400)*(timespan->month % 12));
}
+ else if ((type == RESERV) && (val == DTK_EPOCH))
+ {
+ *result = timespan->time;
+ if (timespan->month != 0)
+ {
+ *result += ((365.25 * 86400) * (timespan->month / 12));
+ *result += ((30 * 86400) * (timespan->month % 12));
+ }
#endif
- } else {
- elog(WARN,"Timespan units %s not recognized",units);
- result = NULL;
- }
+ }
+ else
+ {
+ elog(WARN, "Timespan units %s not recognized", units);
+ result = NULL;
+ }
- return(result);
-} /* timespan_trunc() */
+ return (result);
+} /* timespan_trunc() */
/* datetime_part()
* Extract specified field from datetime.
*/
float64
-datetime_part(text *units, DateTime *datetime)
+datetime_part(text * units, DateTime * datetime)
{
- float64 result;
-
- DateTime dt;
- int tz;
- int type, val;
- int i;
- char *up, *lp, lowunits[MAXDATELEN+1];
- double fsec;
- char *tzn;
- struct tm tt, *tm = &tt;
-
- if ((!PointerIsValid(units)) || (!PointerIsValid(datetime)))
- return NULL;
-
- result = PALLOCTYPE(float64data);
-
- up = VARDATA(units);
- lp = lowunits;
- for (i = 0; i < (VARSIZE(units)-VARHDRSZ); i++) *lp++ = tolower( *up++);
- *lp = '\0';
-
- type = DecodeUnits( 0, lowunits, &val);
- if (type == IGNORE) {
- type = DecodeSpecial( 0, lowunits, &val);
- }
+ float64 result;
+
+ DateTime dt;
+ int tz;
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowunits[MAXDATELEN + 1];
+ double fsec;
+ char *tzn;
+ struct tm tt,
+ *tm = &tt;
+
+ if ((!PointerIsValid(units)) || (!PointerIsValid(datetime)))
+ return NULL;
+
+ result = PALLOCTYPE(float64data);
+
+ up = VARDATA(units);
+ lp = lowunits;
+ for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
+ *lp++ = tolower(*up++);
+ *lp = '\0';
+
+ type = DecodeUnits(0, lowunits, &val);
+ if (type == IGNORE)
+ {
+ type = DecodeSpecial(0, lowunits, &val);
+ }
#ifdef DATEDEBUG
-if (type == IGNORE) strcpy(lowunits, "(unknown)");
-printf( "datetime_part- units %s type=%d value=%d\n", lowunits, type, val);
+ if (type == IGNORE)
+ strcpy(lowunits, "(unknown)");
+ printf("datetime_part- units %s type=%d value=%d\n", lowunits, type, val);
#endif
- if (DATETIME_NOT_FINITE(*datetime)) {
+ if (DATETIME_NOT_FINITE(*datetime))
+ {
#if FALSE
/* should return null but Postgres doesn't like that currently. - tgl 97/06/12 */
- elog(WARN,"Datetime is not finite",NULL);
+ elog(WARN, "Datetime is not finite", NULL);
#endif
- *result = 0;
-
- } else {
- dt = (DATETIME_IS_RELATIVE(*datetime)? SetDateTime(*datetime): *datetime);
-
- if ((type == UNITS) && (datetime2tm( dt, &tz, tm, &fsec, &tzn) == 0)) {
- switch (val) {
- case DTK_TZ:
- *result = tz;
- break;
-
- case DTK_MICROSEC:
- *result = (fsec*1000000);
- break;
-
- case DTK_MILLISEC:
- *result = (fsec*1000);
- break;
-
- case DTK_SECOND:
- *result = (tm->tm_sec + fsec);
- break;
-
- case DTK_MINUTE:
- *result = tm->tm_min;
- break;
-
- case DTK_HOUR:
- *result = tm->tm_hour;
- break;
-
- case DTK_DAY:
- *result = tm->tm_mday;
- break;
-
- case DTK_MONTH:
- *result = tm->tm_mon;
- break;
-
- case DTK_QUARTER:
- *result = (tm->tm_mon/4)+1;
- break;
-
- case DTK_YEAR:
- *result = tm->tm_year;
- break;
-
- case DTK_DECADE:
- *result = (tm->tm_year/10)+1;
- break;
-
- case DTK_CENTURY:
- *result = (tm->tm_year/100)+1;
- break;
-
- case DTK_MILLENIUM:
- *result = (tm->tm_year/1000)+1;
- break;
-
- default:
- elog(WARN,"Datetime units %s not supported",lowunits);
*result = 0;
- }
-
- } else if (type == RESERV) {
- switch (val) {
- case DTK_EPOCH:
- DATETIME_EPOCH(*result);
- *result = dt - SetDateTime(*result);
- break;
- case DTK_DOW:
- if (datetime2tm( dt, &tz, tm, &fsec, &tzn) != 0)
- elog(WARN,"Unable to encode datetime",NULL);
-
- *result = j2day( date2j( tm->tm_year, tm->tm_mon, tm->tm_mday));
- break;
+ }
+ else
+ {
+ dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
+
+ if ((type == UNITS) && (datetime2tm(dt, &tz, tm, &fsec, &tzn) == 0))
+ {
+ switch (val)
+ {
+ case DTK_TZ:
+ *result = tz;
+ break;
+
+ case DTK_MICROSEC:
+ *result = (fsec * 1000000);
+ break;
+
+ case DTK_MILLISEC:
+ *result = (fsec * 1000);
+ break;
+
+ case DTK_SECOND:
+ *result = (tm->tm_sec + fsec);
+ break;
+
+ case DTK_MINUTE:
+ *result = tm->tm_min;
+ break;
+
+ case DTK_HOUR:
+ *result = tm->tm_hour;
+ break;
+
+ case DTK_DAY:
+ *result = tm->tm_mday;
+ break;
+
+ case DTK_MONTH:
+ *result = tm->tm_mon;
+ break;
+
+ case DTK_QUARTER:
+ *result = (tm->tm_mon / 4) + 1;
+ break;
+
+ case DTK_YEAR:
+ *result = tm->tm_year;
+ break;
+
+ case DTK_DECADE:
+ *result = (tm->tm_year / 10) + 1;
+ break;
+
+ case DTK_CENTURY:
+ *result = (tm->tm_year / 100) + 1;
+ break;
+
+ case DTK_MILLENIUM:
+ *result = (tm->tm_year / 1000) + 1;
+ break;
+
+ default:
+ elog(WARN, "Datetime units %s not supported", lowunits);
+ *result = 0;
+ }
- default:
- elog(WARN,"Datetime units %s not supported",lowunits);
- *result = 0;
- }
+ }
+ else if (type == RESERV)
+ {
+ switch (val)
+ {
+ case DTK_EPOCH:
+ DATETIME_EPOCH(*result);
+ *result = dt - SetDateTime(*result);
+ break;
+
+ case DTK_DOW:
+ if (datetime2tm(dt, &tz, tm, &fsec, &tzn) != 0)
+ elog(WARN, "Unable to encode datetime", NULL);
+
+ *result = j2day(date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
+ break;
+
+ default:
+ elog(WARN, "Datetime units %s not supported", lowunits);
+ *result = 0;
+ }
- } else {
- elog(WARN,"Datetime units %s not recognized",lowunits);
- *result = 0;
+ }
+ else
+ {
+ elog(WARN, "Datetime units %s not recognized", lowunits);
+ *result = 0;
+ }
}
- }
- return(result);
-} /* datetime_part() */
+ return (result);
+} /* datetime_part() */
/* timespan_part()
* Extract specified field from timespan.
*/
float64
-timespan_part(text *units, TimeSpan *timespan)
+timespan_part(text * units, TimeSpan * timespan)
{
- float64 result;
-
- int type, val;
- int i;
- char *up, *lp, lowunits[MAXDATELEN+1];
- double fsec;
- struct tm tt, *tm = &tt;
-
- if ((!PointerIsValid(units)) || (!PointerIsValid(timespan)))
- return NULL;
-
- result = PALLOCTYPE(float64data);
-
- up = VARDATA(units);
- lp = lowunits;
- for (i = 0; i < (VARSIZE(units)-VARHDRSZ); i++) *lp++ = tolower( *up++);
- *lp = '\0';
-
- type = DecodeUnits( 0, lowunits, &val);
- if (type == IGNORE) {
- type = DecodeSpecial( 0, lowunits, &val);
- }
+ float64 result;
+
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowunits[MAXDATELEN + 1];
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
+
+ if ((!PointerIsValid(units)) || (!PointerIsValid(timespan)))
+ return NULL;
+
+ result = PALLOCTYPE(float64data);
+
+ up = VARDATA(units);
+ lp = lowunits;
+ for (i = 0; i < (VARSIZE(units) - VARHDRSZ); i++)
+ *lp++ = tolower(*up++);
+ *lp = '\0';
+
+ type = DecodeUnits(0, lowunits, &val);
+ if (type == IGNORE)
+ {
+ type = DecodeSpecial(0, lowunits, &val);
+ }
#ifdef DATEDEBUG
-if (type == IGNORE) strcpy(lowunits, "(unknown)");
-printf( "timespan_part- units %s type=%d value=%d\n", lowunits, type, val);
+ if (type == IGNORE)
+ strcpy(lowunits, "(unknown)");
+ printf("timespan_part- units %s type=%d value=%d\n", lowunits, type, val);
#endif
- if (TIMESPAN_IS_INVALID(*timespan)) {
+ if (TIMESPAN_IS_INVALID(*timespan))
+ {
#if FALSE
- elog(WARN,"Timespan is not finite",NULL);
+ elog(WARN, "Timespan is not finite", NULL);
#endif
- *result = 0;
-
- } else if (type == UNITS) {
-
- if (timespan2tm(*timespan, tm, &fsec) == 0) {
- switch (val) {
- case DTK_MICROSEC:
- *result = (fsec*1000000);
- break;
-
- case DTK_MILLISEC:
- *result = (fsec*1000);
- break;
-
- case DTK_SECOND:
- *result = (tm->tm_sec + fsec);
- break;
-
- case DTK_MINUTE:
- *result = tm->tm_min;
- break;
-
- case DTK_HOUR:
- *result = tm->tm_hour;
- break;
-
- case DTK_DAY:
- *result = tm->tm_mday;
- break;
-
- case DTK_MONTH:
- *result = tm->tm_mon;
- break;
-
- case DTK_QUARTER:
- *result = (tm->tm_mon/4)+1;
- break;
-
- case DTK_YEAR:
- *result = tm->tm_year;
- break;
-
- case DTK_DECADE:
- *result = (tm->tm_year/10)+1;
- break;
-
- case DTK_CENTURY:
- *result = (tm->tm_year/100)+1;
- break;
+ *result = 0;
- case DTK_MILLENIUM:
- *result = (tm->tm_year/1000)+1;
- break;
+ }
+ else if (type == UNITS)
+ {
+
+ if (timespan2tm(*timespan, tm, &fsec) == 0)
+ {
+ switch (val)
+ {
+ case DTK_MICROSEC:
+ *result = (fsec * 1000000);
+ break;
+
+ case DTK_MILLISEC:
+ *result = (fsec * 1000);
+ break;
+
+ case DTK_SECOND:
+ *result = (tm->tm_sec + fsec);
+ break;
+
+ case DTK_MINUTE:
+ *result = tm->tm_min;
+ break;
+
+ case DTK_HOUR:
+ *result = tm->tm_hour;
+ break;
+
+ case DTK_DAY:
+ *result = tm->tm_mday;
+ break;
+
+ case DTK_MONTH:
+ *result = tm->tm_mon;
+ break;
+
+ case DTK_QUARTER:
+ *result = (tm->tm_mon / 4) + 1;
+ break;
+
+ case DTK_YEAR:
+ *result = tm->tm_year;
+ break;
+
+ case DTK_DECADE:
+ *result = (tm->tm_year / 10) + 1;
+ break;
+
+ case DTK_CENTURY:
+ *result = (tm->tm_year / 100) + 1;
+ break;
+
+ case DTK_MILLENIUM:
+ *result = (tm->tm_year / 1000) + 1;
+ break;
+
+ default:
+ elog(WARN, "Timespan units %s not yet supported", units);
+ result = NULL;
+ }
- default:
- elog(WARN,"Timespan units %s not yet supported",units);
- result = NULL;
- }
+ }
+ else
+ {
+ elog(NOTICE, "Timespan out of range", NULL);
+ *result = 0;
+ }
- } else {
- elog(NOTICE,"Timespan out of range",NULL);
- *result = 0;
}
+ else if ((type == RESERV) && (val == DTK_EPOCH))
+ {
+ *result = timespan->time;
+ if (timespan->month != 0)
+ {
+ *result += ((365.25 * 86400) * (timespan->month / 12));
+ *result += ((30 * 86400) * (timespan->month % 12));
+ }
- } else if ((type == RESERV) && (val == DTK_EPOCH)) {
- *result = timespan->time;
- if (timespan->month != 0) {
- *result += ((365.25*86400)*(timespan->month / 12));
- *result += ((30*86400)*(timespan->month % 12));
+ }
+ else
+ {
+ elog(WARN, "Timespan units %s not recognized", units);
+ *result = 0;
}
- } else {
- elog(WARN,"Timespan units %s not recognized",units);
- *result = 0;
- }
-
- return(result);
-} /* timespan_part() */
+ return (result);
+} /* timespan_part() */
/* datetime_zone()
* Encode datetime type with specified time zone.
*/
-text *
-datetime_zone(text *zone, DateTime *datetime)
-{
- text *result;
-
- DateTime dt;
- int tz;
- int type, val;
- int i;
- char *up, *lp, lowzone[MAXDATELEN+1];
- char *tzn, upzone[MAXDATELEN+1];
- double fsec;
- struct tm tt, *tm = &tt;
- char buf[MAXDATELEN+1];
- int len;
-
- if ((!PointerIsValid(zone)) || (!PointerIsValid(datetime)))
- return NULL;
-
- up = VARDATA(zone);
- lp = lowzone;
- for (i = 0; i < (VARSIZE(zone)-VARHDRSZ); i++) *lp++ = tolower( *up++);
- *lp = '\0';
+text *
+datetime_zone(text * zone, DateTime * datetime)
+{
+ text *result;
+
+ DateTime dt;
+ int tz;
+ int type,
+ val;
+ int i;
+ char *up,
+ *lp,
+ lowzone[MAXDATELEN + 1];
+ char *tzn,
+ upzone[MAXDATELEN + 1];
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
+ char buf[MAXDATELEN + 1];
+ int len;
+
+ if ((!PointerIsValid(zone)) || (!PointerIsValid(datetime)))
+ return NULL;
+
+ up = VARDATA(zone);
+ lp = lowzone;
+ for (i = 0; i < (VARSIZE(zone) - VARHDRSZ); i++)
+ *lp++ = tolower(*up++);
+ *lp = '\0';
- type = DecodeSpecial( 0, lowzone, &val);
+ type = DecodeSpecial(0, lowzone, &val);
#ifdef DATEDEBUG
-if (type == IGNORE) strcpy(lowzone, "(unknown)");
-printf( "datetime_zone- zone %s type=%d value=%d\n", lowzone, type, val);
+ if (type == IGNORE)
+ strcpy(lowzone, "(unknown)");
+ printf("datetime_zone- zone %s type=%d value=%d\n", lowzone, type, val);
#endif
- if (DATETIME_NOT_FINITE(*datetime)) {
- /* could return null but Postgres doesn't like that currently. - tgl 97/06/12 */
- elog(WARN,"Datetime is not finite",NULL);
- result = NULL;
+ if (DATETIME_NOT_FINITE(*datetime))
+ {
- } else if ((type == TZ) || (type == DTZ)) {
- tm->tm_isdst = ((type == DTZ)? 1: 0);
- tz = val * 60;
+ /*
+ * could return null but Postgres doesn't like that currently. -
+ * tgl 97/06/12
+ */
+ elog(WARN, "Datetime is not finite", NULL);
+ result = NULL;
- dt = (DATETIME_IS_RELATIVE(*datetime)? SetDateTime(*datetime): *datetime);
- dt = dt2local( dt, tz);
+ }
+ else if ((type == TZ) || (type == DTZ))
+ {
+ tm->tm_isdst = ((type == DTZ) ? 1 : 0);
+ tz = val * 60;
- if (datetime2tm( dt, NULL, tm, &fsec, NULL) != 0)
- elog(WARN,"Datetime not legal",NULL);
+ dt = (DATETIME_IS_RELATIVE(*datetime) ? SetDateTime(*datetime) : *datetime);
+ dt = dt2local(dt, tz);
- up = upzone;
- lp = lowzone;
- for (i = 0; *lp != '\0'; i++) *up++ = toupper( *lp++);
- *up = '\0';
+ if (datetime2tm(dt, NULL, tm, &fsec, NULL) != 0)
+ elog(WARN, "Datetime not legal", NULL);
- tzn = upzone;
- EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
+ up = upzone;
+ lp = lowzone;
+ for (i = 0; *lp != '\0'; i++)
+ *up++ = toupper(*lp++);
+ *up = '\0';
- len = (strlen(buf)+VARHDRSZ);
+ tzn = upzone;
+ EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
- result = PALLOC(len);
+ len = (strlen(buf) + VARHDRSZ);
- VARSIZE(result) = len;
- memmove(VARDATA(result), buf, (len-VARHDRSZ));
+ result = PALLOC(len);
+
+ VARSIZE(result) = len;
+ memmove(VARDATA(result), buf, (len - VARHDRSZ));
- } else {
- elog(WARN,"Time zone %s not recognized",lowzone);
- result = NULL;
- }
+ }
+ else
+ {
+ elog(WARN, "Time zone %s not recognized", lowzone);
+ result = NULL;
+ }
- return(result);
-} /* datetime_zone() */
+ return (result);
+} /* datetime_zone() */
-/*****************************************************************************
- * PRIVATE ROUTINES *
+/*****************************************************************************
+ * PRIVATE ROUTINES *
*****************************************************************************/
/* definitions for squeezing values into "value" */
-#define ABS_SIGNBIT (char) 0200
-#define VALMASK (char) 0177
-#define NEG(n) ((n)|ABS_SIGNBIT)
+#define ABS_SIGNBIT (char) 0200
+#define VALMASK (char) 0177
+#define NEG(n) ((n)|ABS_SIGNBIT)
#define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
-#define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
+#define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
#define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10))
/*
@@ -1814,253 +2064,270 @@ printf( "datetime_zone- zone %s type=%d value=%d\n", lowzone, type, val);
* entries by 10 and truncate the text field at MAXTOKLEN characters.
* the text field is not guaranteed to be NULL-terminated.
*/
-static datetkn datetktbl[] = {
-/* text token lexval */
-{ EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
-{ "acsst", DTZ, 63}, /* Cent. Australia */
-{ "acst", TZ, 57}, /* Cent. Australia */
-{ DA_D, ADBC, AD}, /* "ad" for years >= 0 */
-{ "abstime", IGNORE, 0}, /* "abstime" for pre-v6.1 "Invalid Abstime" */
-{ "adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */
-{ "aesst", DTZ, 66}, /* E. Australia */
-{ "aest", TZ, 60}, /* Australia Eastern Std Time */
-{ "ahst", TZ, 60}, /* Alaska-Hawaii Std Time */
-{ "allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
-{ "am", AMPM, AM},
-{ "apr", MONTH, 4},
-{ "april", MONTH, 4},
-{ "ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */
-{ "at", IGNORE, 0}, /* "at" (throwaway) */
-{ "aug", MONTH, 8},
-{ "august", MONTH, 8},
-{ "awsst", DTZ, 54}, /* W. Australia */
-{ "awst", TZ, 48}, /* W. Australia */
-{ DB_C, ADBC, BC}, /* "bc" for years < 0 */
-{ "bst", TZ, 6}, /* British Summer Time */
-{ "bt", TZ, 18}, /* Baghdad Time */
-{ "cadt", DTZ, 63}, /* Central Australian DST */
-{ "cast", TZ, 57}, /* Central Australian ST */
-{ "cat", TZ, NEG(60)}, /* Central Alaska Time */
-{ "cct", TZ, 48}, /* China Coast */
-{ "cdt", DTZ, NEG(30)}, /* Central Daylight Time */
-{ "cet", TZ, 6}, /* Central European Time */
-{ "cetdst", DTZ, 12}, /* Central European Dayl.Time */
-{ "cst", TZ, NEG(36)}, /* Central Standard Time */
-{ DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
-{ "dec", MONTH, 12},
-{ "december", MONTH, 12},
-{ "dnt", TZ, 6}, /* Dansk Normal Tid */
-{ "dow", RESERV, DTK_DOW}, /* day of week */
-{ "dst", DTZMOD, 6},
-{ "east", TZ, NEG(60)}, /* East Australian Std Time */
-{ "edt", DTZ, NEG(24)}, /* Eastern Daylight Time */
-{ "eet", TZ, 12}, /* East. Europe, USSR Zone 1 */
-{ "eetdst", DTZ, 18}, /* Eastern Europe */
-{ EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
+static datetkn datetktbl[] = {
+/* text token lexval */
+ {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
+ {"acsst", DTZ, 63}, /* Cent. Australia */
+ {"acst", TZ, 57}, /* Cent. Australia */
+ {DA_D, ADBC, AD}, /* "ad" for years >= 0 */
+ {"abstime", IGNORE, 0}, /* "abstime" for pre-v6.1 "Invalid
+ * Abstime" */
+ {"adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */
+ {"aesst", DTZ, 66}, /* E. Australia */
+ {"aest", TZ, 60}, /* Australia Eastern Std Time */
+ {"ahst", TZ, 60}, /* Alaska-Hawaii Std Time */
+ {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
+ {"am", AMPM, AM},
+ {"apr", MONTH, 4},
+ {"april", MONTH, 4},
+ {"ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */
+ {"at", IGNORE, 0}, /* "at" (throwaway) */
+ {"aug", MONTH, 8},
+ {"august", MONTH, 8},
+ {"awsst", DTZ, 54}, /* W. Australia */
+ {"awst", TZ, 48}, /* W. Australia */
+ {DB_C, ADBC, BC}, /* "bc" for years < 0 */
+ {"bst", TZ, 6}, /* British Summer Time */
+ {"bt", TZ, 18}, /* Baghdad Time */
+ {"cadt", DTZ, 63}, /* Central Australian DST */
+ {"cast", TZ, 57}, /* Central Australian ST */
+ {"cat", TZ, NEG(60)}, /* Central Alaska Time */
+ {"cct", TZ, 48}, /* China Coast */
+ {"cdt", DTZ, NEG(30)}, /* Central Daylight Time */
+ {"cet", TZ, 6}, /* Central European Time */
+ {"cetdst", DTZ, 12}, /* Central European Dayl.Time */
+ {"cst", TZ, NEG(36)}, /* Central Standard Time */
+ {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
+ {"dec", MONTH, 12},
+ {"december", MONTH, 12},
+ {"dnt", TZ, 6}, /* Dansk Normal Tid */
+ {"dow", RESERV, DTK_DOW}, /* day of week */
+ {"dst", DTZMOD, 6},
+ {"east", TZ, NEG(60)}, /* East Australian Std Time */
+ {"edt", DTZ, NEG(24)}, /* Eastern Daylight Time */
+ {"eet", TZ, 12}, /* East. Europe, USSR Zone 1 */
+ {"eetdst", DTZ, 18}, /* Eastern Europe */
+ {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
#if USE_AUSTRALIAN_RULES
-{ "est", TZ, 60}, /* Australia Eastern Std Time */
+ {"est", TZ, 60}, /* Australia Eastern Std Time */
#else
-{ "est", TZ, NEG(30)}, /* Eastern Standard Time */
-#endif
-{ "feb", MONTH, 2},
-{ "february", MONTH, 2},
-{ "fri", DOW, 5},
-{ "friday", DOW, 5},
-{ "fst", TZ, 6}, /* French Summer Time */
-{ "fwt", DTZ, 12}, /* French Winter Time */
-{ "gmt", TZ, 0}, /* Greenwish Mean Time */
-{ "gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */
-{ "hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */
-{ "hmt", DTZ, 18}, /* Hellas ? ? */
-{ "hst", TZ, NEG(60)}, /* Hawaii Std Time */
-{ "idle", TZ, 72}, /* Intl. Date Line, East */
-{ "idlw", TZ, NEG(72)}, /* Intl. Date Line, West */
-{ LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */
-{ INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid time */
-{ "ist", TZ, 12}, /* Israel */
-{ "it", TZ, 22}, /* Iran Time */
-{ "jan", MONTH, 1},
-{ "january", MONTH, 1},
-{ "jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
-{ "jt", TZ, 45}, /* Java Time */
-{ "jul", MONTH, 7},
-{ "july", MONTH, 7},
-{ "jun", MONTH, 6},
-{ "june", MONTH, 6},
-{ "kst", TZ, 54}, /* Korea Standard Time */
-{ "ligt", TZ, 60}, /* From Melbourne, Australia */
-{ "mar", MONTH, 3},
-{ "march", MONTH, 3},
-{ "may", MONTH, 5},
-{ "mdt", DTZ, NEG(36)}, /* Mountain Daylight Time */
-{ "mest", DTZ, 12}, /* Middle Europe Summer Time */
-{ "met", TZ, 6}, /* Middle Europe Time */
-{ "metdst", DTZ, 12}, /* Middle Europe Daylight Time*/
-{ "mewt", TZ, 6}, /* Middle Europe Winter Time */
-{ "mez", TZ, 6}, /* Middle Europe Zone */
-{ "mon", DOW, 1},
-{ "monday", DOW, 1},
-{ "mst", TZ, NEG(42)}, /* Mountain Standard Time */
-{ "mt", TZ, 51}, /* Moluccas Time */
-{ "ndt", DTZ, NEG(15)}, /* Nfld. Daylight Time */
-{ "nft", TZ, NEG(21)}, /* Newfoundland Standard Time */
-{ "nor", TZ, 6}, /* Norway Standard Time */
-{ "nov", MONTH, 11},
-{ "november", MONTH, 11},
-{ NOW, RESERV, DTK_NOW}, /* current transaction time */
-{ "nst", TZ, NEG(21)}, /* Nfld. Standard Time */
-{ "nt", TZ, NEG(66)}, /* Nome Time */
-{ "nzdt", DTZ, 78}, /* New Zealand Daylight Time */
-{ "nzst", TZ, 72}, /* New Zealand Standard Time */
-{ "nzt", TZ, 72}, /* New Zealand Time */
-{ "oct", MONTH, 10},
-{ "october", MONTH, 10},
-{ "on", IGNORE, 0}, /* "on" (throwaway) */
-{ "pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */
-{ "pm", AMPM, PM},
-{ "pst", TZ, NEG(48)}, /* Pacific Standard Time */
-{ "sadt", DTZ, 63}, /* S. Australian Dayl. Time */
-{ "sast", TZ, 57}, /* South Australian Std Time */
-{ "sat", DOW, 6},
-{ "saturday", DOW, 6},
-{ "sep", MONTH, 9},
-{ "sept", MONTH, 9},
-{ "september", MONTH, 9},
-{ "set", TZ, NEG(6)}, /* Seychelles Time ?? */
-{ "sst", DTZ, 12}, /* Swedish Summer Time */
-{ "sun", DOW, 0},
-{ "sunday", DOW, 0},
-{ "swt", TZ, 6}, /* Swedish Winter Time */
-{ "thu", DOW, 4},
-{ "thur", DOW, 4},
-{ "thurs", DOW, 4},
-{ "thursday", DOW, 4},
-{ TODAY, RESERV, DTK_TODAY}, /* midnight */
-{ TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */
-{ "tue", DOW, 2},
-{ "tues", DOW, 2},
-{ "tuesday", DOW, 2},
-{ "undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid time */
-{ "ut", TZ, 0},
-{ "utc", TZ, 0},
-{ "wadt", DTZ, 48}, /* West Australian DST */
-{ "wast", TZ, 42}, /* West Australian Std Time */
-{ "wat", TZ, NEG(6)}, /* West Africa Time */
-{ "wdt", DTZ, 54}, /* West Australian DST */
-{ "wed", DOW, 3},
-{ "wednesday", DOW, 3},
-{ "weds", DOW, 3},
-{ "wet", TZ, 0}, /* Western Europe */
-{ "wetdst", DTZ, 6}, /* Western Europe */
-{ "wst", TZ, 48}, /* West Australian Std Time */
-{ "ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */
-{ YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
-{ "yst", TZ, NEG(54)}, /* Yukon Standard Time */
-{ "zp4", TZ, NEG(24)}, /* GMT +4 hours. */
-{ "zp5", TZ, NEG(30)}, /* GMT +5 hours. */
-{ "zp6", TZ, NEG(36)}, /* GMT +6 hours. */
-{ "z", RESERV, DTK_ZULU}, /* 00:00:00 */
-{ ZULU, RESERV, DTK_ZULU}, /* 00:00:00 */
+ {"est", TZ, NEG(30)}, /* Eastern Standard Time */
+#endif
+ {"feb", MONTH, 2},
+ {"february", MONTH, 2},
+ {"fri", DOW, 5},
+ {"friday", DOW, 5},
+ {"fst", TZ, 6}, /* French Summer Time */
+ {"fwt", DTZ, 12}, /* French Winter Time */
+ {"gmt", TZ, 0}, /* Greenwish Mean Time */
+ {"gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */
+ {"hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */
+ {"hmt", DTZ, 18}, /* Hellas ? ? */
+ {"hst", TZ, NEG(60)}, /* Hawaii Std Time */
+ {"idle", TZ, 72}, /* Intl. Date Line, East */
+ {"idlw", TZ, NEG(72)}, /* Intl. Date Line, West */
+ {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */
+ {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid
+ * time */
+ {"ist", TZ, 12}, /* Israel */
+ {"it", TZ, 22}, /* Iran Time */
+ {"jan", MONTH, 1},
+ {"january", MONTH, 1},
+ {"jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
+ {"jt", TZ, 45}, /* Java Time */
+ {"jul", MONTH, 7},
+ {"july", MONTH, 7},
+ {"jun", MONTH, 6},
+ {"june", MONTH, 6},
+ {"kst", TZ, 54}, /* Korea Standard Time */
+ {"ligt", TZ, 60}, /* From Melbourne, Australia */
+ {"mar", MONTH, 3},
+ {"march", MONTH, 3},
+ {"may", MONTH, 5},
+ {"mdt", DTZ, NEG(36)}, /* Mountain Daylight Time */
+ {"mest", DTZ, 12}, /* Middle Europe Summer Time */
+ {"met", TZ, 6}, /* Middle Europe Time */
+ {"metdst", DTZ, 12}, /* Middle Europe Daylight Time */
+ {"mewt", TZ, 6}, /* Middle Europe Winter Time */
+ {"mez", TZ, 6}, /* Middle Europe Zone */
+ {"mon", DOW, 1},
+ {"monday", DOW, 1},
+ {"mst", TZ, NEG(42)}, /* Mountain Standard Time */
+ {"mt", TZ, 51}, /* Moluccas Time */
+ {"ndt", DTZ, NEG(15)}, /* Nfld. Daylight Time */
+ {"nft", TZ, NEG(21)}, /* Newfoundland Standard Time */
+ {"nor", TZ, 6}, /* Norway Standard Time */
+ {"nov", MONTH, 11},
+ {"november", MONTH, 11},
+ {NOW, RESERV, DTK_NOW}, /* current transaction time */
+ {"nst", TZ, NEG(21)}, /* Nfld. Standard Time */
+ {"nt", TZ, NEG(66)}, /* Nome Time */
+ {"nzdt", DTZ, 78}, /* New Zealand Daylight Time */
+ {"nzst", TZ, 72}, /* New Zealand Standard Time */
+ {"nzt", TZ, 72}, /* New Zealand Time */
+ {"oct", MONTH, 10},
+ {"october", MONTH, 10},
+ {"on", IGNORE, 0}, /* "on" (throwaway) */
+ {"pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */
+ {"pm", AMPM, PM},
+ {"pst", TZ, NEG(48)}, /* Pacific Standard Time */
+ {"sadt", DTZ, 63}, /* S. Australian Dayl. Time */
+ {"sast", TZ, 57}, /* South Australian Std Time */
+ {"sat", DOW, 6},
+ {"saturday", DOW, 6},
+ {"sep", MONTH, 9},
+ {"sept", MONTH, 9},
+ {"september", MONTH, 9},
+ {"set", TZ, NEG(6)}, /* Seychelles Time ?? */
+ {"sst", DTZ, 12}, /* Swedish Summer Time */
+ {"sun", DOW, 0},
+ {"sunday", DOW, 0},
+ {"swt", TZ, 6}, /* Swedish Winter Time */
+ {"thu", DOW, 4},
+ {"thur", DOW, 4},
+ {"thurs", DOW, 4},
+ {"thursday", DOW, 4},
+ {TODAY, RESERV, DTK_TODAY}, /* midnight */
+ {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */
+ {"tue", DOW, 2},
+ {"tues", DOW, 2},
+ {"tuesday", DOW, 2},
+ {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid
+ * time */
+ {"ut", TZ, 0},
+ {"utc", TZ, 0},
+ {"wadt", DTZ, 48}, /* West Australian DST */
+ {"wast", TZ, 42}, /* West Australian Std Time */
+ {"wat", TZ, NEG(6)}, /* West Africa Time */
+ {"wdt", DTZ, 54}, /* West Australian DST */
+ {"wed", DOW, 3},
+ {"wednesday", DOW, 3},
+ {"weds", DOW, 3},
+ {"wet", TZ, 0}, /* Western Europe */
+ {"wetdst", DTZ, 6}, /* Western Europe */
+ {"wst", TZ, 48}, /* West Australian Std Time */
+ {"ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */
+ {YESTERDAY, RESERV, DTK_YESTERDAY}, /* yesterday midnight */
+ {"yst", TZ, NEG(54)}, /* Yukon Standard Time */
+ {"zp4", TZ, NEG(24)}, /* GMT +4 hours. */
+ {"zp5", TZ, NEG(30)}, /* GMT +5 hours. */
+ {"zp6", TZ, NEG(36)}, /* GMT +6 hours. */
+ {"z", RESERV, DTK_ZULU}, /* 00:00:00 */
+ {ZULU, RESERV, DTK_ZULU}, /* 00:00:00 */
};
static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
-static datetkn deltatktbl[] = {
-/* text token lexval */
-{ "@", IGNORE, 0}, /* postgres relative time prefix */
-{ DAGO, AGO, 0}, /* "ago" indicates negative time offset */
-{ "c", UNITS, DTK_CENTURY}, /* "century" relative time units */
-{ "cent", UNITS, DTK_CENTURY}, /* "century" relative time units */
-{ "centuries", UNITS, DTK_CENTURY}, /* "centuries" relative time units */
-{ DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative time units */
-{ "d", UNITS, DTK_DAY}, /* "day" relative time units */
-{ DDAY, UNITS, DTK_DAY}, /* "day" relative time units */
-{ "days", UNITS, DTK_DAY}, /* "days" relative time units */
-{ "dec", UNITS, DTK_DECADE}, /* "decade" relative time units */
-{ "decs", UNITS, DTK_DECADE}, /* "decades" relative time units */
-{ DDECADE, UNITS, DTK_DECADE}, /* "decade" relative time units */
-{ "decades", UNITS, DTK_DECADE}, /* "decades" relative time units */
-{ "h", UNITS, DTK_HOUR}, /* "hour" relative time units */
-{ DHOUR, UNITS, DTK_HOUR}, /* "hour" relative time units */
-{ "hours", UNITS, DTK_HOUR}, /* "hours" relative time units */
-{ "hr", UNITS, DTK_HOUR}, /* "hour" relative time units */
-{ "hrs", UNITS, DTK_HOUR}, /* "hours" relative time units */
-{ INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid time */
-{ "m", UNITS, DTK_MINUTE}, /* "minute" relative time units */
-{ "microsecon", UNITS, DTK_MILLISEC}, /* "microsecond" relative time units */
-{ "mil", UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */
-{ "mils", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */
-{ "millenia", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */
-{ DMILLENIUM, UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */
-{ "millisecon", UNITS, DTK_MILLISEC}, /* "millisecond" relative time units */
-{ "min", UNITS, DTK_MINUTE}, /* "minute" relative time units */
-{ "mins", UNITS, DTK_MINUTE}, /* "minutes" relative time units */
-{ "mins", UNITS, DTK_MINUTE}, /* "minutes" relative time units */
-{ DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative time units */
-{ "minutes", UNITS, DTK_MINUTE}, /* "minutes" relative time units */
-{ "mon", UNITS, DTK_MONTH}, /* "months" relative time units */
-{ "mons", UNITS, DTK_MONTH}, /* "months" relative time units */
-{ DMONTH, UNITS, DTK_MONTH}, /* "month" relative time units */
-{ "months", UNITS, DTK_MONTH}, /* "months" relative time units */
-{ "ms", UNITS, DTK_MILLISEC}, /* "millisecond" relative time units */
-{ "msec", UNITS, DTK_MILLISEC}, /* "millisecond" relative time units */
-{ DMILLISEC, UNITS, DTK_MILLISEC}, /* "millisecond" relative time units */
-{ "mseconds", UNITS, DTK_MILLISEC}, /* "milliseconds" relative time units */
-{ "msecs", UNITS, DTK_MILLISEC}, /* "milliseconds" relative time units */
-{ "qtr", UNITS, DTK_QUARTER}, /* "quarter" relative time units */
-{ DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative time units */
-{ "reltime", IGNORE, 0}, /* "reltime" for pre-v6.1 "Undefined Reltime" */
-{ "s", UNITS, DTK_SECOND}, /* "second" relative time units */
-{ "sec", UNITS, DTK_SECOND}, /* "second" relative time units */
-{ DSECOND, UNITS, DTK_SECOND}, /* "second" relative time units */
-{ "seconds", UNITS, DTK_SECOND}, /* "seconds" relative time units */
-{ "secs", UNITS, DTK_SECOND}, /* "seconds" relative time units */
-{ DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
-{ "tz", UNITS, DTK_TZ}, /* "timezone" time offset */
-{ "undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid time */
-{ "us", UNITS, DTK_MICROSEC}, /* "microsecond" relative time units */
-{ "usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative time units */
-{ DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative time units */
-{ "useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative time units */
-{ "usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative time units */
-{ "w", UNITS, DTK_WEEK}, /* "week" relative time units */
-{ DWEEK, UNITS, DTK_WEEK}, /* "week" relative time units */
-{ "weeks", UNITS, DTK_WEEK}, /* "weeks" relative time units */
-{ "y", UNITS, DTK_YEAR}, /* "year" relative time units */
-{ DYEAR, UNITS, DTK_YEAR}, /* "year" relative time units */
-{ "years", UNITS, DTK_YEAR}, /* "years" relative time units */
-{ "yr", UNITS, DTK_YEAR}, /* "year" relative time units */
-{ "yrs", UNITS, DTK_YEAR}, /* "years" relative time units */
+static datetkn deltatktbl[] = {
+/* text token lexval */
+ {"@", IGNORE, 0}, /* postgres relative time prefix */
+ {DAGO, AGO, 0}, /* "ago" indicates negative time offset */
+ {"c", UNITS, DTK_CENTURY}, /* "century" relative time units */
+ {"cent", UNITS, DTK_CENTURY}, /* "century" relative time units */
+ {"centuries", UNITS, DTK_CENTURY}, /* "centuries" relative time units */
+ {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative time units */
+ {"d", UNITS, DTK_DAY}, /* "day" relative time units */
+ {DDAY, UNITS, DTK_DAY}, /* "day" relative time units */
+ {"days", UNITS, DTK_DAY}, /* "days" relative time units */
+ {"dec", UNITS, DTK_DECADE}, /* "decade" relative time units */
+ {"decs", UNITS, DTK_DECADE},/* "decades" relative time units */
+ {DDECADE, UNITS, DTK_DECADE}, /* "decade" relative time units */
+ {"decades", UNITS, DTK_DECADE}, /* "decades" relative time units */
+ {"h", UNITS, DTK_HOUR}, /* "hour" relative time units */
+ {DHOUR, UNITS, DTK_HOUR}, /* "hour" relative time units */
+ {"hours", UNITS, DTK_HOUR}, /* "hours" relative time units */
+ {"hr", UNITS, DTK_HOUR}, /* "hour" relative time units */
+ {"hrs", UNITS, DTK_HOUR}, /* "hours" relative time units */
+ {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for invalid
+ * time */
+ {"m", UNITS, DTK_MINUTE}, /* "minute" relative time units */
+ {"microsecon", UNITS, DTK_MILLISEC}, /* "microsecond" relative
+ * time units */
+ {"mil", UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */
+ {"mils", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */
+ {"millenia", UNITS, DTK_MILLENIUM}, /* "millenia" relative time units */
+ {DMILLENIUM, UNITS, DTK_MILLENIUM}, /* "millenium" relative time units */
+ {"millisecon", UNITS, DTK_MILLISEC}, /* "millisecond" relative
+ * time units */
+ {"min", UNITS, DTK_MINUTE}, /* "minute" relative time units */
+ {"mins", UNITS, DTK_MINUTE},/* "minutes" relative time units */
+ {"mins", UNITS, DTK_MINUTE},/* "minutes" relative time units */
+ {DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative time units */
+ {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative time units */
+ {"mon", UNITS, DTK_MONTH}, /* "months" relative time units */
+ {"mons", UNITS, DTK_MONTH}, /* "months" relative time units */
+ {DMONTH, UNITS, DTK_MONTH}, /* "month" relative time units */
+ {"months", UNITS, DTK_MONTH}, /* "months" relative time units */
+ {"ms", UNITS, DTK_MILLISEC},/* "millisecond" relative time units */
+ {"msec", UNITS, DTK_MILLISEC}, /* "millisecond" relative time
+ * units */
+ {DMILLISEC, UNITS, DTK_MILLISEC}, /* "millisecond" relative time
+ * units */
+ {"mseconds", UNITS, DTK_MILLISEC}, /* "milliseconds" relative time
+ * units */
+ {"msecs", UNITS, DTK_MILLISEC}, /* "milliseconds" relative time
+ * units */
+ {"qtr", UNITS, DTK_QUARTER},/* "quarter" relative time units */
+ {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative time units */
+ {"reltime", IGNORE, 0}, /* "reltime" for pre-v6.1 "Undefined
+ * Reltime" */
+ {"s", UNITS, DTK_SECOND}, /* "second" relative time units */
+ {"sec", UNITS, DTK_SECOND}, /* "second" relative time units */
+ {DSECOND, UNITS, DTK_SECOND}, /* "second" relative time units */
+ {"seconds", UNITS, DTK_SECOND}, /* "seconds" relative time units */
+ {"secs", UNITS, DTK_SECOND},/* "seconds" relative time units */
+ {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
+ {"tz", UNITS, DTK_TZ}, /* "timezone" time offset */
+ {"undefined", RESERV, DTK_INVALID}, /* "undefined" pre-v6.1 invalid
+ * time */
+ {"us", UNITS, DTK_MICROSEC},/* "microsecond" relative time units */
+ {"usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative time
+ * units */
+ {DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative time
+ * units */
+ {"useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative time
+ * units */
+ {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative time
+ * units */
+ {"w", UNITS, DTK_WEEK}, /* "week" relative time units */
+ {DWEEK, UNITS, DTK_WEEK}, /* "week" relative time units */
+ {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative time units */
+ {"y", UNITS, DTK_YEAR}, /* "year" relative time units */
+ {DYEAR, UNITS, DTK_YEAR}, /* "year" relative time units */
+ {"years", UNITS, DTK_YEAR}, /* "years" relative time units */
+ {"yr", UNITS, DTK_YEAR}, /* "year" relative time units */
+ {"yrs", UNITS, DTK_YEAR}, /* "years" relative time units */
};
static unsigned int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
#if USE_DATE_CACHE
-datetkn *datecache[MAXDATEFIELDS] = {NULL};
+datetkn *datecache[MAXDATEFIELDS] = {NULL};
+
+datetkn *deltacache[MAXDATEFIELDS] = {NULL};
-datetkn *deltacache[MAXDATEFIELDS] = {NULL};
#endif
/*
* Calendar time to Julian date conversions.
* Julian date is commonly used in astronomical applications,
- * since it is numerically accurate and computationally simple.
+ * since it is numerically accurate and computationally simple.
* The algorithms here will accurately convert between Julian day
- * and calendar date for all non-negative Julian days
- * (i.e. from Nov 23, -4713 on).
+ * and calendar date for all non-negative Julian days
+ * (i.e. from Nov 23, -4713 on).
*
* Ref: Explanatory Supplement to the Astronomical Almanac, 1992.
- * University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
+ * University Science Books, 20 Edgehill Rd. Mill Valley CA 94941.
*
* Use the algorithm by Henry Fliegel, a former NASA/JPL colleague
- * now at Aerospace Corp. (hi, Henry!)
+ * now at Aerospace Corp. (hi, Henry!)
*
* These routines will be used by other date/time packages - tgl 97/02/25
*/
/* Set the minimum year to one greater than the year of the first valid day
- * to avoid having to check year and day both. - tgl 97/05/08
+ * to avoid having to check year and day both. - tgl 97/05/08
*/
#define JULIAN_MINYEAR (-4713)
@@ -2074,45 +2341,50 @@ datetkn *deltacache[MAXDATEFIELDS] = {NULL};
int
date2j(int y, int m, int d)
{
- int m12 = (m-14)/12;
+ int m12 = (m - 14) / 12;
- return((1461*(y+4800+m12))/4 + (367*(m-2-12*(m12)))/12
- - (3*((y+4900+m12)/100))/4 + d - 32075);
-} /* date2j() */
+ return ((1461 * (y + 4800 + m12)) / 4 + (367 * (m - 2 - 12 * (m12))) / 12
+ - (3 * ((y + 4900 + m12) / 100)) / 4 + d - 32075);
+} /* date2j() */
void
-j2date( int jd, int *year, int *month, int *day)
+j2date(int jd, int *year, int *month, int *day)
{
- int j, y, m, d;
-
- int i, l, n;
-
- l = jd + 68569;
- n = (4*l)/146097;
- l -= (146097*n+3)/4;
- i = (4000*(l+1))/1461001;
- l += 31 - (1461*i)/4;
- j = (80*l)/2447;
- d = l - (2447*j)/80;
- l = j/11;
- m = (j+2) - (12*l);
- y = 100*(n-49)+i+l;
-
- *year = y;
- *month = m;
- *day = d;
- return;
-} /* j2date() */
+ int j,
+ y,
+ m,
+ d;
+
+ int i,
+ l,
+ n;
+
+ l = jd + 68569;
+ n = (4 * l) / 146097;
+ l -= (146097 * n + 3) / 4;
+ i = (4000 * (l + 1)) / 1461001;
+ l += 31 - (1461 * i) / 4;
+ j = (80 * l) / 2447;
+ d = l - (2447 * j) / 80;
+ l = j / 11;
+ m = (j + 2) - (12 * l);
+ y = 100 * (n - 49) + i + l;
+
+ *year = y;
+ *month = m;
+ *day = d;
+ return;
+} /* j2date() */
static int
-j2day( int date)
+j2day(int date)
{
- int day;
+ int day;
- day = (date+1) % 7;
+ day = (date + 1) % 7;
- return(day);
-} /* j2day() */
+ return (day);
+} /* j2day() */
/* datetime2tm()
@@ -2120,141 +2392,159 @@ j2day( int date)
* Note that year is _not_ 1900-based, but is an explicit full value.
* Also, month is one-based, _not_ zero-based.
* Returns:
- * 0 on success
- * -1 on out of range
+ * 0 on success
+ * -1 on out of range
*
* For dates within the system-supported time_t range, convert to the
- * local time zone. If out of this range, leave as GMT. - tgl 97/05/27
+ * local time zone. If out of this range, leave as GMT. - tgl 97/05/27
*/
int
-datetime2tm( DateTime dt, int *tzp, struct tm *tm, double *fsec, char **tzn)
+datetime2tm(DateTime dt, int *tzp, struct tm * tm, double *fsec, char **tzn)
{
- double date, date0, time, sec;
- time_t utime;
+ double date,
+ date0,
+ time,
+ sec;
+ time_t utime;
+
#ifdef USE_POSIX_TIME
- struct tm *tx;
+ struct tm *tx;
+
#endif
- date0 = date2j(2000,1,1);
+ date0 = date2j(2000, 1, 1);
- time = dt;
- TMODULO(time,date,86400e0);
+ time = dt;
+ TMODULO(time, date, 86400e0);
- if (time < 0) {
- time += 86400;
- date -= 1;
- }
+ if (time < 0)
+ {
+ time += 86400;
+ date -= 1;
+ }
- /* Julian day routine does not work for negative Julian days */
- if (date < -date0)
- return -1;
+ /* Julian day routine does not work for negative Julian days */
+ if (date < -date0)
+ return -1;
- /* add offset to go from J2000 back to standard Julian date */
- date += date0;
+ /* add offset to go from J2000 back to standard Julian date */
+ date += date0;
#ifdef DATEDEBUG
-printf( "datetime2tm- date is %f (%f %f)\n", dt, date, time);
+ printf("datetime2tm- date is %f (%f %f)\n", dt, date, time);
#endif
- j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
- dt2time( time, &tm->tm_hour, &tm->tm_min, &sec);
+ j2date((int) date, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+ dt2time(time, &tm->tm_hour, &tm->tm_min, &sec);
#ifdef DATEDEBUG
-printf( "datetime2tm- date is %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
-printf( "datetime2tm- time is %02d:%02d:%02.0f\n", tm->tm_hour, tm->tm_min, sec);
+ printf("datetime2tm- date is %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
+ printf("datetime2tm- time is %02d:%02d:%02.0f\n", tm->tm_hour, tm->tm_min, sec);
#endif
- *fsec = JROUND(sec);
- TMODULO(*fsec,tm->tm_sec,1);
+ *fsec = JROUND(sec);
+ TMODULO(*fsec, tm->tm_sec, 1);
#ifdef DATEDEBUG
-printf( "datetime2tm- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
+ printf("datetime2tm- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
#endif
- if (tzp != NULL) {
- if (IS_VALID_UTIME( tm->tm_year, tm->tm_mon, tm->tm_mday)) {
- utime = (dt + (date0-date2j(1970,1,1))*86400);
+ if (tzp != NULL)
+ {
+ if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
+ {
+ utime = (dt + (date0 - date2j(1970, 1, 1)) * 86400);
#if FALSE
- if (utime < -1) utime++;
+ if (utime < -1)
+ utime++;
#endif
#ifdef USE_POSIX_TIME
- tx = localtime(&utime);
+ tx = localtime(&utime);
#ifdef DATEDEBUG
#ifdef HAVE_INT_TIMEZONE
-printf( "datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s %s dst=%d\n",
- tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, sec,
- tzname[0], tzname[1], tx->tm_isdst);
+ printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s %s dst=%d\n",
+ tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, sec,
+ tzname[0], tzname[1], tx->tm_isdst);
#else
-printf( "datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s dst=%d\n",
- tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, sec,
- tx->tm_zone, tx->tm_isdst);
+ printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02.0f %s dst=%d\n",
+ tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, sec,
+ tx->tm_zone, tx->tm_isdst);
#endif
#else
#endif
- tm->tm_year = tx->tm_year + 1900;
- tm->tm_mon = tx->tm_mon + 1;
- tm->tm_mday = tx->tm_mday;
- tm->tm_hour = tx->tm_hour;
- tm->tm_min = tx->tm_min;
+ tm->tm_year = tx->tm_year + 1900;
+ tm->tm_mon = tx->tm_mon + 1;
+ tm->tm_mday = tx->tm_mday;
+ tm->tm_hour = tx->tm_hour;
+ tm->tm_min = tx->tm_min;
#if FALSE
/* XXX HACK
* Argh! My Linux box puts in a 1 second offset for dates less than 1970
- * but only if the seconds field was non-zero. So, don't copy the seconds
- * field and instead carry forward from the original - tgl 97/06/18
+ * but only if the seconds field was non-zero. So, don't copy the seconds
+ * field and instead carry forward from the original - tgl 97/06/18
* Note that GNU/Linux uses the standard freeware zic package as do
- * many other platforms so this may not be GNU/Linux/ix86-specific.
+ * many other platforms so this may not be GNU/Linux/ix86-specific.
*/
- tm->tm_sec = tx->tm_sec;
+ tm->tm_sec = tx->tm_sec;
#endif
- tm->tm_isdst = tx->tm_isdst;
+ tm->tm_isdst = tx->tm_isdst;
#ifdef HAVE_INT_TIMEZONE
- *tzp = (tm->tm_isdst? (timezone - 3600): timezone);
- if (tzn != NULL) *tzn = tzname[(tm->tm_isdst > 0)];
+ *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
+ if (tzn != NULL)
+ *tzn = tzname[(tm->tm_isdst > 0)];
-#else /* !HAVE_INT_TIMEZONE */
- tm->tm_gmtoff = tx->tm_gmtoff;
- tm->tm_zone = tx->tm_zone;
+#else /* !HAVE_INT_TIMEZONE */
+ tm->tm_gmtoff = tx->tm_gmtoff;
+ tm->tm_zone = tx->tm_zone;
- *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
- if (tzn != NULL) *tzn = tm->tm_zone;
+ *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
+ if (tzn != NULL)
+ *tzn = tm->tm_zone;
#endif
-#else /* !USE_POSIX_TIME */
- *tzp = CTimeZone; /* V7 conventions; don't know timezone? */
- if (tzn != NULL) *tzn = CTZName;
+#else /* !USE_POSIX_TIME */
+ *tzp = CTimeZone; /* V7 conventions; don't know timezone? */
+ if (tzn != NULL)
+ *tzn = CTZName;
#endif
- } else {
- *tzp = 0;
- tm->tm_isdst = 0;
- if (tzn != NULL) *tzn = NULL;
- }
+ }
+ else
+ {
+ *tzp = 0;
+ tm->tm_isdst = 0;
+ if (tzn != NULL)
+ *tzn = NULL;
+ }
- dt = dt2local( dt, *tzp);
+ dt = dt2local(dt, *tzp);
- } else {
- tm->tm_isdst = 0;
- if (tzn != NULL) *tzn = NULL;
- }
+ }
+ else
+ {
+ tm->tm_isdst = 0;
+ if (tzn != NULL)
+ *tzn = NULL;
+ }
#ifdef DATEDEBUG
-printf( "datetime2tm- date is %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
-printf( "datetime2tm- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
+ printf("datetime2tm- date is %d.%02d.%02d\n", tm->tm_year, tm->tm_mon, tm->tm_mday);
+ printf("datetime2tm- time is %02d:%02d:%02d %.7f\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
#endif
#ifdef DATEDEBUG
#ifdef USE_POSIX_TIME
#ifdef HAVE_INT_TIMEZONE
-printf( "datetime2tm- timezone is %s; offset is %d (%d); daylight is %d\n",
- tzname[tm->tm_isdst != 0], ((tzp != NULL)? *tzp: 0), CTimeZone, CDayLight);
+ printf("datetime2tm- timezone is %s; offset is %d (%d); daylight is %d\n",
+ tzname[tm->tm_isdst != 0], ((tzp != NULL) ? *tzp : 0), CTimeZone, CDayLight);
#endif
#endif
#endif
- return 0;
-} /* datetime2tm() */
+ return 0;
+} /* datetime2tm() */
/* tm2datetime()
@@ -2263,109 +2553,115 @@ printf( "datetime2tm- timezone is %s; offset is %d (%d); daylight is %d\n",
* Also, month is one-based, _not_ zero-based.
*/
int
-tm2datetime( struct tm *tm, double fsec, int *tzp, DateTime *result) {
+tm2datetime(struct tm * tm, double fsec, int *tzp, DateTime * result)
+{
- double date, time;
+ double date,
+ time;
- /* Julian day routines are not correct for negative Julian days */
- if (! IS_VALID_JULIAN( tm->tm_year, tm->tm_mon, tm->tm_mday))
- return(-1);
+ /* Julian day routines are not correct for negative Julian days */
+ if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
+ return (-1);
- date = date2j(tm->tm_year,tm->tm_mon,tm->tm_mday) - date2j(2000,1,1);
- time = time2t(tm->tm_hour,tm->tm_min,(tm->tm_sec + fsec));
- *result = (date*86400+time);
+ date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(2000, 1, 1);
+ time = time2t(tm->tm_hour, tm->tm_min, (tm->tm_sec + fsec));
+ *result = (date * 86400 + time);
#ifdef DATEDEBUG
-printf( "tm2datetime- date is %f (%f %f %d)\n", *result, date, time, (((tm->tm_hour*60)+tm->tm_min)*60+tm->tm_sec));
-printf( "tm2datetime- time is %f %02d:%02d:%02d %f\n", time, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
+ printf("tm2datetime- date is %f (%f %f %d)\n", *result, date, time, (((tm->tm_hour * 60) + tm->tm_min) * 60 + tm->tm_sec));
+ printf("tm2datetime- time is %f %02d:%02d:%02d %f\n", time, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
#endif
- if (tzp != NULL) *result = dt2local(*result, -(*tzp));
+ if (tzp != NULL)
+ *result = dt2local(*result, -(*tzp));
- return 0;
-} /* tm2datetime() */
+ return 0;
+} /* tm2datetime() */
/* timespan2tm()
* Convert a timespan data type to a tm structure.
*/
static int
-timespan2tm(TimeSpan span, struct tm *tm, float8 *fsec)
+timespan2tm(TimeSpan span, struct tm * tm, float8 * fsec)
{
- double time;
+ double time;
- if (span.month != 0) {
- tm->tm_year = span.month / 12;
- tm->tm_mon = span.month % 12;
+ if (span.month != 0)
+ {
+ tm->tm_year = span.month / 12;
+ tm->tm_mon = span.month % 12;
- } else {
- tm->tm_year = 0;
- tm->tm_mon = 0;
- }
+ }
+ else
+ {
+ tm->tm_year = 0;
+ tm->tm_mon = 0;
+ }
#ifdef ROUND_ALL
- time = JROUND(span.time);
+ time = JROUND(span.time);
#else
- time = span.time;
+ time = span.time;
#endif
- TMODULO(time, tm->tm_mday, 86400e0);
- TMODULO(time, tm->tm_hour, 3600e0);
- TMODULO(time, tm->tm_min, 60e0);
- TMODULO(time, tm->tm_sec, 1);
- *fsec = time;
+ TMODULO(time, tm->tm_mday, 86400e0);
+ TMODULO(time, tm->tm_hour, 3600e0);
+ TMODULO(time, tm->tm_min, 60e0);
+ TMODULO(time, tm->tm_sec, 1);
+ *fsec = time;
#ifdef DATEDEBUG
-printf( "timespan2tm- %d %f = %04d-%02d-%02d %02d:%02d:%02d %.2f\n", span.month, span.time,
- tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
+ printf("timespan2tm- %d %f = %04d-%02d-%02d %02d:%02d:%02d %.2f\n", span.month, span.time,
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
#endif
- return 0;
-} /* timespan2tm() */
+ return 0;
+} /* timespan2tm() */
static int
-tm2timespan( struct tm *tm, double fsec, TimeSpan *span)
+tm2timespan(struct tm * tm, double fsec, TimeSpan * span)
{
- span->month = ((tm->tm_year*12)+tm->tm_mon);
- span->time = ((((((tm->tm_mday*24)+tm->tm_hour)*60)+tm->tm_min)*60)+tm->tm_sec);
- span->time = JROUND(span->time + fsec);
+ span->month = ((tm->tm_year * 12) + tm->tm_mon);
+ span->time = ((((((tm->tm_mday * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60) + tm->tm_sec);
+ span->time = JROUND(span->time + fsec);
#ifdef DATEDEBUG
-printf( "tm2timespan- %d %f = %04d-%02d-%02d %02d:%02d:%02d %.2f\n", span->month, span->time,
- tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
+ printf("tm2timespan- %d %f = %04d-%02d-%02d %02d:%02d:%02d %.2f\n", span->month, span->time,
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, fsec);
#endif
- return 0;
-} /* tm2timespan() */
+ return 0;
+} /* tm2timespan() */
-static DateTime
+static DateTime
dt2local(DateTime dt, int tz)
{
- dt -= tz;
- dt = JROUND(dt);
- return(dt);
-} /* dt2local() */
+ dt -= tz;
+ dt = JROUND(dt);
+ return (dt);
+} /* dt2local() */
double
time2t(const int hour, const int min, const double sec)
{
- return((((hour*60)+min)*60)+sec);
-} /* time2t() */
+ return ((((hour * 60) + min) * 60) + sec);
+} /* time2t() */
static void
dt2time(DateTime jd, int *hour, int *min, double *sec)
{
- double time;
+ double time;
- time = jd;
+ time = jd;
- *hour = (time/3600);
- time -= ((*hour)*3600);
- *min = (time/60);
- time -= ((*min)*60);
- *sec = JROUND(time);
+ *hour = (time / 3600);
+ time -= ((*hour) * 3600);
+ *min = (time / 60);
+ time -= ((*min) * 60);
+ *sec = JROUND(time);
- return;
-} /* dt2time() */
+ return;
+} /* dt2time() */
/*
@@ -2378,469 +2674,561 @@ dt2time(DateTime jd, int *hour, int *min, double *sec)
* Break string into tokens based on a date/time context.
*/
int
-ParseDateTime( char *timestr, char *lowstr,
- char *field[], int ftype[], int maxfields, int *numfields)
-{
- int nf = 0;
- char *cp = timestr;
- char *lp = lowstr;
-
-#ifdef DATEDEBUG
-printf( "ParseDateTime- input string is %s\n", timestr);
-#endif
- /* outer loop through fields */
- while (*cp != '\0') {
- field[nf] = lp;
-
- /* leading digit? then date or time */
- if (isdigit(*cp)) {
- *lp++ = *cp++;
- while (isdigit(*cp)) *lp++ = *cp++;
- /* time field? */
- if (*cp == ':') {
- ftype[nf] = DTK_TIME;
- while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
- *lp++ = *cp++;
-
- /* date field? allow embedded text month */
- } else if ((*cp == '-') || (*cp == '/') || (*cp == '.')) {
- ftype[nf] = DTK_DATE;
- while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
- *lp++ = tolower(*cp++);
-
- /* otherwise, number only and will determine year, month, or day later */
- } else {
- ftype[nf] = DTK_NUMBER;
- }
-
- /* text? then date string, month, day of week, special, or timezone */
- } else if (isalpha(*cp)) {
- ftype[nf] = DTK_STRING;
- *lp++ = tolower(*cp++);
- while (isalpha(*cp)) *lp++ = tolower(*cp++);
-
- /* full date string with leading text month? */
- if ((*cp == '-') || (*cp == '/') || (*cp == '.')) {
- ftype[nf] = DTK_DATE;
- while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
- *lp++ = tolower(*cp++);
- }
-
- /* skip leading spaces */
- } else if (isspace(*cp)) {
- cp++;
- continue;
-
- /* sign? then special or numeric timezone */
- } else if ((*cp == '+') || (*cp == '-')) {
- *lp++ = *cp++;
- /* soak up leading whitespace */
- while (isspace(*cp)) cp++;
- /* numeric timezone? */
- if (isdigit(*cp)) {
- ftype[nf] = DTK_TZ;
- *lp++ = *cp++;
- while (isdigit(*cp) || (*cp == ':')) *lp++ = *cp++;
-
- /* special? */
- } else if (isalpha(*cp)) {
- ftype[nf] = DTK_SPECIAL;
- *lp++ = tolower(*cp++);
- while (isalpha(*cp)) *lp++ = tolower(*cp++);
-
- /* otherwise something wrong... */
- } else {
- return -1;
- }
+ParseDateTime(char *timestr, char *lowstr,
+ char *field[], int ftype[], int maxfields, int *numfields)
+{
+ int nf = 0;
+ char *cp = timestr;
+ char *lp = lowstr;
- /* ignore punctuation but use as delimiter */
- } else if (ispunct(*cp)) {
- cp++;
- continue;
+#ifdef DATEDEBUG
+ printf("ParseDateTime- input string is %s\n", timestr);
+#endif
+ /* outer loop through fields */
+ while (*cp != '\0')
+ {
+ field[nf] = lp;
+
+ /* leading digit? then date or time */
+ if (isdigit(*cp))
+ {
+ *lp++ = *cp++;
+ while (isdigit(*cp))
+ *lp++ = *cp++;
+ /* time field? */
+ if (*cp == ':')
+ {
+ ftype[nf] = DTK_TIME;
+ while (isdigit(*cp) || (*cp == ':') || (*cp == '.'))
+ *lp++ = *cp++;
+
+ /* date field? allow embedded text month */
+ }
+ else if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
+ {
+ ftype[nf] = DTK_DATE;
+ while (isalnum(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
+ *lp++ = tolower(*cp++);
+
+ /*
+ * otherwise, number only and will determine year, month,
+ * or day later
+ */
+ }
+ else
+ {
+ ftype[nf] = DTK_NUMBER;
+ }
+
+ /*
+ * text? then date string, month, day of week, special, or
+ * timezone
+ */
+ }
+ else if (isalpha(*cp))
+ {
+ ftype[nf] = DTK_STRING;
+ *lp++ = tolower(*cp++);
+ while (isalpha(*cp))
+ *lp++ = tolower(*cp++);
+
+ /* full date string with leading text month? */
+ if ((*cp == '-') || (*cp == '/') || (*cp == '.'))
+ {
+ ftype[nf] = DTK_DATE;
+ while (isdigit(*cp) || (*cp == '-') || (*cp == '/') || (*cp == '.'))
+ *lp++ = tolower(*cp++);
+ }
+
+ /* skip leading spaces */
+ }
+ else if (isspace(*cp))
+ {
+ cp++;
+ continue;
- } else {
- return -1;
- }
+ /* sign? then special or numeric timezone */
+ }
+ else if ((*cp == '+') || (*cp == '-'))
+ {
+ *lp++ = *cp++;
+ /* soak up leading whitespace */
+ while (isspace(*cp))
+ cp++;
+ /* numeric timezone? */
+ if (isdigit(*cp))
+ {
+ ftype[nf] = DTK_TZ;
+ *lp++ = *cp++;
+ while (isdigit(*cp) || (*cp == ':'))
+ *lp++ = *cp++;
+
+ /* special? */
+ }
+ else if (isalpha(*cp))
+ {
+ ftype[nf] = DTK_SPECIAL;
+ *lp++ = tolower(*cp++);
+ while (isalpha(*cp))
+ *lp++ = tolower(*cp++);
+
+ /* otherwise something wrong... */
+ }
+ else
+ {
+ return -1;
+ }
+
+ /* ignore punctuation but use as delimiter */
+ }
+ else if (ispunct(*cp))
+ {
+ cp++;
+ continue;
- /* force in a delimiter */
- *lp++ = '\0';
- nf++;
- if (nf > MAXDATEFIELDS) {
- return -1;
- }
+ }
+ else
+ {
+ return -1;
+ }
+
+ /* force in a delimiter */
+ *lp++ = '\0';
+ nf++;
+ if (nf > MAXDATEFIELDS)
+ {
+ return -1;
+ }
#ifdef DATEDEBUG
-printf( "ParseDateTime- set field[%d] to %s type %d\n", (nf-1), field[nf-1], ftype[nf-1]);
+ printf("ParseDateTime- set field[%d] to %s type %d\n", (nf - 1), field[nf - 1], ftype[nf - 1]);
#endif
- }
+ }
- *numfields = nf;
+ *numfields = nf;
- return 0;
-} /* ParseDateTime() */
+ return 0;
+} /* ParseDateTime() */
/* DecodeDateTime()
* Interpret previously parsed fields for general date and time.
* Return 0 if full date, 1 if only time, and -1 if problems.
- * External format(s):
- * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
- * "Fri Feb-7-1997 15:23:27"
- * "Feb-7-1997 15:23:27"
- * "2-7-1997 15:23:27"
- * "1997-2-7 15:23:27"
- * "1997.038 15:23:27" (day of year 1-366)
- * Also supports input in compact time:
- * "970207 152327"
- * "97038 152327"
+ * External format(s):
+ * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
+ * "Fri Feb-7-1997 15:23:27"
+ * "Feb-7-1997 15:23:27"
+ * "2-7-1997 15:23:27"
+ * "1997-2-7 15:23:27"
+ * "1997.038 15:23:27" (day of year 1-366)
+ * Also supports input in compact time:
+ * "970207 152327"
+ * "97038 152327"
*
* Use the system-provided functions to get the current time zone
- * if not specified in the input string.
+ * if not specified in the input string.
* If the date is outside the time_t system-supported time range,
- * then assume GMT time zone. - tgl 97/05/27
+ * then assume GMT time zone. - tgl 97/05/27
*/
int
-DecodeDateTime( char *field[], int ftype[], int nf,
- int *dtype, struct tm *tm, double *fsec, int *tzp)
+DecodeDateTime(char *field[], int ftype[], int nf,
+ int *dtype, struct tm * tm, double *fsec, int *tzp)
{
- int fmask = 0, tmask, type;
- int i;
- int flen, val;
- int mer = HR24;
- int bc = FALSE;
+ int fmask = 0,
+ tmask,
+ type;
+ int i;
+ int flen,
+ val;
+ int mer = HR24;
+ int bc = FALSE;
+
+ *dtype = DTK_DATE;
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ *fsec = 0;
+ tm->tm_isdst = -1; /* don't know daylight savings time status
+ * apriori */
+ if (tzp != NULL)
+ *tzp = 0;
- *dtype = DTK_DATE;
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- *fsec = 0;
- tm->tm_isdst = -1; /* don't know daylight savings time status apriori */
- if (tzp != NULL) *tzp = 0;
+ for (i = 0; i < nf; i++)
+ {
+#ifdef DATEDEBUG
+ printf("DecodeDateTime- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
+#endif
+ switch (ftype[i])
+ {
+ case DTK_DATE:
+ if (DecodeDate(field[i], fmask, &tmask, tm) != 0)
+ return -1;
+ break;
+
+ case DTK_TIME:
+ if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
+ return -1;
+
+ /*
+ * check upper limit on hours; other limits checked in
+ * DecodeTime()
+ */
+ if (tm->tm_hour > 23)
+ return -1;
+ break;
+
+ case DTK_TZ:
+ if (tzp == NULL)
+ return -1;
+ if (DecodeTimezone(field[i], tzp) != 0)
+ return -1;
+ tmask = DTK_M(TZ);
+ break;
+
+ case DTK_NUMBER:
+ flen = strlen(field[i]);
+
+ if (flen > 4)
+ {
+ if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
+ return -1;
+
+ }
+ else
+ {
+ if (DecodeNumber(flen, field[i], fmask, &tmask, tm, fsec) != 0)
+ return -1;
+ }
+ break;
+
+ case DTK_STRING:
+ case DTK_SPECIAL:
+ type = DecodeSpecial(i, field[i], &val);
+#ifdef DATEDEBUG
+ printf("DecodeDateTime- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
+#endif
+ if (type == IGNORE)
+ continue;
- for (i = 0; i < nf; i++) {
+ tmask = DTK_M(type);
+ switch (type)
+ {
+ case RESERV:
#ifdef DATEDEBUG
-printf( "DecodeDateTime- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
+ printf("DecodeDateTime- RESERV field %s value is %d\n", field[i], val);
#endif
- switch (ftype[i]) {
- case DTK_DATE:
- if (DecodeDate(field[i], fmask, &tmask, tm) != 0) return -1;
- break;
-
- case DTK_TIME:
- if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) return -1;
- /* check upper limit on hours; other limits checked in DecodeTime() */
- if (tm->tm_hour > 23) return -1;
- break;
-
- case DTK_TZ:
- if (tzp == NULL) return -1;
- if (DecodeTimezone( field[i], tzp) != 0) return -1;
- tmask = DTK_M(TZ);
- break;
-
- case DTK_NUMBER:
- flen = strlen(field[i]);
-
- if (flen > 4) {
- if (DecodeNumberField( flen, field[i], fmask, &tmask, tm, fsec) != 0)
- return -1;
-
- } else {
- if (DecodeNumber( flen, field[i], fmask, &tmask, tm, fsec) != 0)
- return -1;
- }
- break;
-
- case DTK_STRING:
- case DTK_SPECIAL:
- type = DecodeSpecial( i, field[i], &val);
-#ifdef DATEDEBUG
-printf( "DecodeDateTime- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
-#endif
- if (type == IGNORE) continue;
-
- tmask = DTK_M(type);
- switch (type) {
- case RESERV:
-#ifdef DATEDEBUG
-printf( "DecodeDateTime- RESERV field %s value is %d\n", field[i], val);
-#endif
- switch (val) {
- case DTK_NOW:
- tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
- *dtype = DTK_DATE;
- GetCurrentTime(tm);
- if (tzp != NULL) *tzp = CTimeZone;
- break;
-
- case DTK_YESTERDAY:
- tmask = DTK_DATE_M;
- *dtype = DTK_DATE;
- GetCurrentTime(tm);
- j2date( (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday)-1),
- &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- break;
-
- case DTK_TODAY:
- tmask = DTK_DATE_M;
- *dtype = DTK_DATE;
- GetCurrentTime(tm);
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- break;
-
- case DTK_TOMORROW:
- tmask = DTK_DATE_M;
- *dtype = DTK_DATE;
- GetCurrentTime(tm);
- j2date( (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday)+1),
- &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- break;
-
- case DTK_ZULU:
- tmask = (DTK_TIME_M | DTK_M(TZ));
- *dtype = DTK_DATE;
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- if (tzp != NULL) *tzp = 0;
- break;
+ switch (val)
+ {
+ case DTK_NOW:
+ tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
+ *dtype = DTK_DATE;
+ GetCurrentTime(tm);
+ if (tzp != NULL)
+ *tzp = CTimeZone;
+ break;
+
+ case DTK_YESTERDAY:
+ tmask = DTK_DATE_M;
+ *dtype = DTK_DATE;
+ GetCurrentTime(tm);
+ j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - 1),
+ &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ break;
+
+ case DTK_TODAY:
+ tmask = DTK_DATE_M;
+ *dtype = DTK_DATE;
+ GetCurrentTime(tm);
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ break;
+
+ case DTK_TOMORROW:
+ tmask = DTK_DATE_M;
+ *dtype = DTK_DATE;
+ GetCurrentTime(tm);
+ j2date((date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) + 1),
+ &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ break;
+
+ case DTK_ZULU:
+ tmask = (DTK_TIME_M | DTK_M(TZ));
+ *dtype = DTK_DATE;
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ if (tzp != NULL)
+ *tzp = 0;
+ break;
+
+ default:
+ *dtype = val;
+ }
+
+ break;
+
+ case MONTH:
+#ifdef DATEDEBUG
+ printf("DecodeDateTime- month field %s value is %d\n", field[i], val);
+#endif
+ tm->tm_mon = val;
+ break;
+
+ /*
+ * daylight savings time modifier (solves "MET DST"
+ * syntax)
+ */
+ case DTZMOD:
+ tmask |= DTK_M(DTZ);
+ tm->tm_isdst = 1;
+ if (tzp == NULL)
+ return -1;
+ *tzp += val * 60;
+ break;
+
+ case DTZ:
+
+ /*
+ * set mask for TZ here _or_ check for DTZ later when
+ * getting default timezone
+ */
+ tmask |= DTK_M(TZ);
+ tm->tm_isdst = 1;
+ if (tzp == NULL)
+ return -1;
+ *tzp = val * 60;
+ break;
+
+ case TZ:
+ tm->tm_isdst = 0;
+ if (tzp == NULL)
+ return -1;
+ *tzp = val * 60;
+ break;
+
+ case IGNORE:
+ break;
+
+ case AMPM:
+ mer = val;
+ break;
+
+ case ADBC:
+ bc = (val == BC);
+ break;
+
+ case DOW:
+ tm->tm_wday = val;
+ break;
+
+ default:
+ return -1;
+ }
+ break;
default:
- *dtype = val;
+ return -1;
}
- break;
-
- case MONTH:
#ifdef DATEDEBUG
-printf( "DecodeDateTime- month field %s value is %d\n", field[i], val);
+ printf("DecodeDateTime- field[%d] %s (%08x/%08x) value is %d\n",
+ i, field[i], fmask, tmask, val);
#endif
- tm->tm_mon = val;
- break;
- /* daylight savings time modifier (solves "MET DST" syntax) */
- case DTZMOD:
- tmask |= DTK_M(DTZ);
- tm->tm_isdst = 1;
- if (tzp == NULL) return -1;
- *tzp += val * 60;
- break;
-
- case DTZ:
- /* set mask for TZ here _or_ check for DTZ later when getting default timezone */
- tmask |= DTK_M(TZ);
- tm->tm_isdst = 1;
- if (tzp == NULL) return -1;
- *tzp = val * 60;
- break;
-
- case TZ:
- tm->tm_isdst = 0;
- if (tzp == NULL) return -1;
- *tzp = val * 60;
- break;
-
- case IGNORE:
- break;
-
- case AMPM:
- mer = val;
- break;
-
- case ADBC:
- bc = (val == BC);
- break;
-
- case DOW:
- tm->tm_wday = val;
- break;
-
- default:
- return -1;
- }
- break;
-
- default:
- return -1;
+ if (tmask & fmask)
+ return -1;
+ fmask |= tmask;
}
-#ifdef DATEDEBUG
-printf( "DecodeDateTime- field[%d] %s (%08x/%08x) value is %d\n",
- i, field[i], fmask, tmask, val);
-#endif
-
- if (tmask & fmask) return -1;
- fmask |= tmask;
- }
+ /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
+ if (bc)
+ tm->tm_year = -(tm->tm_year - 1);
- /* there is no year zero in AD/BC notation; i.e. "1 BC" == year 0 */
- if (bc) tm->tm_year = -(tm->tm_year-1);
-
- if ((mer != HR24) && (tm->tm_hour > 12))
- return -1;
- if (mer == PM) tm->tm_hour += 12;
+ if ((mer != HR24) && (tm->tm_hour > 12))
+ return -1;
+ if (mer == PM)
+ tm->tm_hour += 12;
#ifdef DATEDEBUG
-printf( "DecodeDateTime- mask %08x (%08x)", fmask, DTK_DATE_M);
-printf( " set y%04d m%02d d%02d", tm->tm_year, tm->tm_mon, tm->tm_mday);
-printf( " %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
+ printf("DecodeDateTime- mask %08x (%08x)", fmask, DTK_DATE_M);
+ printf(" set y%04d m%02d d%02d", tm->tm_year, tm->tm_mon, tm->tm_mday);
+ printf(" %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
#endif
- if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) != DTK_DATE_M))
- return(((fmask & DTK_TIME_M) == DTK_TIME_M)? 1: -1);
+ if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) != DTK_DATE_M))
+ return (((fmask & DTK_TIME_M) == DTK_TIME_M) ? 1 : -1);
- /* timezone not specified? then find local timezone if possible */
- if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) == DTK_DATE_M)
- && (tzp != NULL) && (! (fmask & DTK_M(TZ)))) {
+ /* timezone not specified? then find local timezone if possible */
+ if ((*dtype == DTK_DATE) && ((fmask & DTK_DATE_M) == DTK_DATE_M)
+ && (tzp != NULL) && (!(fmask & DTK_M(TZ))))
+ {
- /* daylight savings time modifier but no standard timezone? then error */
- if (fmask & DTK_M(DTZMOD)) return -1;
+ /*
+ * daylight savings time modifier but no standard timezone? then
+ * error
+ */
+ if (fmask & DTK_M(DTZMOD))
+ return -1;
- if (IS_VALID_UTIME( tm->tm_year, tm->tm_mon, tm->tm_mday)) {
+ if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
+ {
#ifdef USE_POSIX_TIME
- tm->tm_year -= 1900;
- tm->tm_mon -= 1;
- tm->tm_isdst = -1;
- mktime(tm);
- tm->tm_year += 1900;
- tm->tm_mon += 1;
+ tm->tm_year -= 1900;
+ tm->tm_mon -= 1;
+ tm->tm_isdst = -1;
+ mktime(tm);
+ tm->tm_year += 1900;
+ tm->tm_mon += 1;
#ifdef HAVE_INT_TIMEZONE
- *tzp = ((tm->tm_isdst > 0)? (timezone - 3600): timezone);
+ *tzp = ((tm->tm_isdst > 0) ? (timezone - 3600) : timezone);
-#else /* !HAVE_INT_TIMEZONE */
- *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
+#else /* !HAVE_INT_TIMEZONE */
+ *tzp = -(tm->tm_gmtoff); /* tm_gmtoff is Sun/DEC-ism */
#endif
-#else /* !USE_POSIX_TIME */
- *tzp = CTimeZone;
+#else /* !USE_POSIX_TIME */
+ *tzp = CTimeZone;
#endif
- } else {
- tm->tm_isdst = 0;
- *tzp = 0;
+ }
+ else
+ {
+ tm->tm_isdst = 0;
+ *tzp = 0;
+ }
}
- }
- return 0;
-} /* DecodeDateTime() */
+ return 0;
+} /* DecodeDateTime() */
/* DecodeTimeOnly()
* Interpret parsed string as time fields only.
*/
int
-DecodeTimeOnly( char *field[], int ftype[], int nf, int *dtype, struct tm *tm, double *fsec)
+DecodeTimeOnly(char *field[], int ftype[], int nf, int *dtype, struct tm * tm, double *fsec)
{
- int fmask, tmask, type;
- int i;
- int flen, val;
- int mer = HR24;
-
- *dtype = DTK_TIME;
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- tm->tm_isdst = -1; /* don't know daylight savings time status apriori */
+ int fmask,
+ tmask,
+ type;
+ int i;
+ int flen,
+ val;
+ int mer = HR24;
+
+ *dtype = DTK_TIME;
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ tm->tm_isdst = -1; /* don't know daylight savings time status
+ * apriori */
- fmask = DTK_DATE_M;
+ fmask = DTK_DATE_M;
- for (i = 0; i < nf; i++) {
+ for (i = 0; i < nf; i++)
+ {
#ifdef DATEDEBUG
-printf( "DecodeTimeOnly- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
+ printf("DecodeTimeOnly- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
#endif
- switch (ftype[i]) {
- case DTK_TIME:
- if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) return -1;
- break;
-
- case DTK_NUMBER:
- flen = strlen(field[i]);
-
- if (DecodeNumberField( flen, field[i], fmask, &tmask, tm, fsec) != 0)
- return -1;
- break;
-
- case DTK_STRING:
- case DTK_SPECIAL:
- type = DecodeSpecial( i, field[i], &val);
+ switch (ftype[i])
+ {
+ case DTK_TIME:
+ if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
+ return -1;
+ break;
+
+ case DTK_NUMBER:
+ flen = strlen(field[i]);
+
+ if (DecodeNumberField(flen, field[i], fmask, &tmask, tm, fsec) != 0)
+ return -1;
+ break;
+
+ case DTK_STRING:
+ case DTK_SPECIAL:
+ type = DecodeSpecial(i, field[i], &val);
#ifdef DATEDEBUG
-printf( "DecodeTimeOnly- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
+ printf("DecodeTimeOnly- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
#endif
- if (type == IGNORE) continue;
+ if (type == IGNORE)
+ continue;
- tmask = DTK_M(type);
- switch (type) {
- case RESERV:
+ tmask = DTK_M(type);
+ switch (type)
+ {
+ case RESERV:
#ifdef DATEDEBUG
-printf( "DecodeTimeOnly- RESERV field %s value is %d\n", field[i], val);
+ printf("DecodeTimeOnly- RESERV field %s value is %d\n", field[i], val);
#endif
- switch (val) {
- case DTK_NOW:
- tmask = DTK_TIME_M;
- *dtype = DTK_TIME;
- GetCurrentTime(tm);
- break;
-
- case DTK_ZULU:
- tmask = (DTK_TIME_M | DTK_M(TZ));
- *dtype = DTK_TIME;
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- tm->tm_isdst = 0;
- break;
+ switch (val)
+ {
+ case DTK_NOW:
+ tmask = DTK_TIME_M;
+ *dtype = DTK_TIME;
+ GetCurrentTime(tm);
+ break;
+
+ case DTK_ZULU:
+ tmask = (DTK_TIME_M | DTK_M(TZ));
+ *dtype = DTK_TIME;
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ tm->tm_isdst = 0;
+ break;
+
+ default:
+ return -1;
+ }
+
+ break;
+
+ case IGNORE:
+ break;
+
+ case AMPM:
+ mer = val;
+ break;
+
+ default:
+ return -1;
+ }
+ break;
default:
- return -1;
+ return -1;
}
- break;
-
- case IGNORE:
- break;
-
- case AMPM:
- mer = val;
- break;
-
- default:
- return -1;
- }
- break;
-
- default:
- return -1;
- }
-
- if (tmask & fmask) return -1;
- fmask |= tmask;
+ if (tmask & fmask)
+ return -1;
+ fmask |= tmask;
#ifdef DATEDEBUG
-printf( "DecodeTimeOnly- field[%d] %s value is %d\n", i, field[i], val);
+ printf("DecodeTimeOnly- field[%d] %s value is %d\n", i, field[i], val);
#endif
- }
+ }
#ifdef DATEDEBUG
-printf( "DecodeTimeOnly- mask %08x (%08x)", fmask, DTK_TIME_M);
-printf( " %02d:%02d:%02d (%f)\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
+ printf("DecodeTimeOnly- mask %08x (%08x)", fmask, DTK_TIME_M);
+ printf(" %02d:%02d:%02d (%f)\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
#endif
- if ((mer != HR24) && (tm->tm_hour > 12))
- return -1;
- if (mer == PM) tm->tm_hour += 12;
+ if ((mer != HR24) && (tm->tm_hour > 12))
+ return -1;
+ if (mer == PM)
+ tm->tm_hour += 12;
- if ((fmask & DTK_TIME_M) != DTK_TIME_M)
- return -1;
+ if ((fmask & DTK_TIME_M) != DTK_TIME_M)
+ return -1;
- return 0;
-} /* DecodeTimeOnly() */
+ return 0;
+} /* DecodeTimeOnly() */
/* DecodeDate()
@@ -2848,390 +3236,472 @@ printf( " %02d:%02d:%02d (%f)\n", tm->tm_hour, tm->tm_min, tm->tm_sec, *fsec);
* Insist on a complete set of fields.
*/
static int
-DecodeDate(char *str, int fmask, int *tmask, struct tm *tm)
+DecodeDate(char *str, int fmask, int *tmask, struct tm * tm)
{
- double fsec;
-
- int nf = 0;
- int i, len;
- int type, val, dmask = 0;
- char *field[MAXDATEFIELDS];
-
- /* parse this string... */
- while ((*str != '\0') && (nf < MAXDATEFIELDS)) {
- /* skip field separators */
- while (! isalnum(*str)) str++;
+ double fsec;
+
+ int nf = 0;
+ int i,
+ len;
+ int type,
+ val,
+ dmask = 0;
+ char *field[MAXDATEFIELDS];
+
+ /* parse this string... */
+ while ((*str != '\0') && (nf < MAXDATEFIELDS))
+ {
+ /* skip field separators */
+ while (!isalnum(*str))
+ str++;
+
+ field[nf] = str;
+ if (isdigit(*str))
+ {
+ while (isdigit(*str))
+ str++;
+ }
+ else if (isalpha(*str))
+ {
+ while (isalpha(*str))
+ str++;
+ }
- field[nf] = str;
- if (isdigit(*str)) {
- while (isdigit(*str)) str++;
- } else if (isalpha(*str)) {
- while (isalpha(*str)) str++;
+ if (*str != '\0')
+ *str++ = '\0';
+ nf++;
}
- if (*str != '\0') *str++ = '\0';
- nf++;
- }
-
- /* don't allow too many fields */
- if (nf > 3) return -1;
-
- *tmask = 0;
-
- /* look first for text fields, since that will be unambiguous month */
- for (i = 0; i < nf; i++) {
- if (isalpha(*field[i])) {
- type = DecodeSpecial( i, field[i], &val);
- if (type == IGNORE) continue;
+ /* don't allow too many fields */
+ if (nf > 3)
+ return -1;
- dmask = DTK_M(type);
- switch (type) {
- case MONTH:
+ *tmask = 0;
+
+ /* look first for text fields, since that will be unambiguous month */
+ for (i = 0; i < nf; i++)
+ {
+ if (isalpha(*field[i]))
+ {
+ type = DecodeSpecial(i, field[i], &val);
+ if (type == IGNORE)
+ continue;
+
+ dmask = DTK_M(type);
+ switch (type)
+ {
+ case MONTH:
#ifdef DATEDEBUG
-printf( "DecodeDate- month field %s value is %d\n", field[i], val);
+ printf("DecodeDate- month field %s value is %d\n", field[i], val);
#endif
- tm->tm_mon = val;
- break;
+ tm->tm_mon = val;
+ break;
- default:
+ default:
#ifdef DATEDEBUG
-printf( "DecodeDate- illegal field %s value is %d\n", field[i], val);
+ printf("DecodeDate- illegal field %s value is %d\n", field[i], val);
#endif
- return -1;
- }
- if (fmask & dmask) return -1;
+ return -1;
+ }
+ if (fmask & dmask)
+ return -1;
- fmask |= dmask;
- *tmask |= dmask;
+ fmask |= dmask;
+ *tmask |= dmask;
- /* mark this field as being completed */
- field[i] = NULL;
+ /* mark this field as being completed */
+ field[i] = NULL;
+ }
}
- }
- /* now pick up remaining numeric fields */
- for (i = 0; i < nf; i++) {
- if (field[i] == NULL) continue;
+ /* now pick up remaining numeric fields */
+ for (i = 0; i < nf; i++)
+ {
+ if (field[i] == NULL)
+ continue;
- if ((len = strlen(field[i])) <= 0)
- return -1;
+ if ((len = strlen(field[i])) <= 0)
+ return -1;
- if (DecodeNumber( len, field[i], fmask, &dmask, tm, &fsec) != 0)
- return -1;
+ if (DecodeNumber(len, field[i], fmask, &dmask, tm, &fsec) != 0)
+ return -1;
- if (fmask & dmask) return -1;
+ if (fmask & dmask)
+ return -1;
- fmask |= dmask;
- *tmask |= dmask;
- }
+ fmask |= dmask;
+ *tmask |= dmask;
+ }
- return 0;
-} /* DecodeDate() */
+ return 0;
+} /* DecodeDate() */
/* DecodeTime()
* Decode time string which includes delimiters.
* Only check the lower limit on hours, since this same code
- * can be used to represent time spans.
+ * can be used to represent time spans.
*/
static int
-DecodeTime(char *str, int fmask, int *tmask, struct tm *tm, double *fsec)
+DecodeTime(char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
{
- char *cp;
+ char *cp;
- *tmask = DTK_TIME_M;
+ *tmask = DTK_TIME_M;
- tm->tm_hour = strtol( str, &cp, 10);
- if (*cp != ':') return -1;
- str = cp+1;
- tm->tm_min = strtol( str, &cp, 10);
- if (*cp == '\0') {
- tm->tm_sec = 0;
- *fsec = 0;
+ tm->tm_hour = strtol(str, &cp, 10);
+ if (*cp != ':')
+ return -1;
+ str = cp + 1;
+ tm->tm_min = strtol(str, &cp, 10);
+ if (*cp == '\0')
+ {
+ tm->tm_sec = 0;
+ *fsec = 0;
- } else if (*cp != ':') {
- return -1;
+ }
+ else if (*cp != ':')
+ {
+ return -1;
- } else {
- str = cp+1;
- tm->tm_sec = strtol( str, &cp, 10);
- if (*cp == '\0') {
- *fsec = 0;
- } else if (*cp == '.') {
- str = cp;
- *fsec = strtod( str, &cp);
- if (cp == str) return -1;
- } else {
- return -1;
}
- }
+ else
+ {
+ str = cp + 1;
+ tm->tm_sec = strtol(str, &cp, 10);
+ if (*cp == '\0')
+ {
+ *fsec = 0;
+ }
+ else if (*cp == '.')
+ {
+ str = cp;
+ *fsec = strtod(str, &cp);
+ if (cp == str)
+ return -1;
+ }
+ else
+ {
+ return -1;
+ }
+ }
- /* do a sanity check */
- if ((tm->tm_hour < 0)
- || (tm->tm_min < 0) || (tm->tm_min > 59)
- || (tm->tm_sec < 0) || (tm->tm_sec > 59)) return -1;
+ /* do a sanity check */
+ if ((tm->tm_hour < 0)
+ || (tm->tm_min < 0) || (tm->tm_min > 59)
+ || (tm->tm_sec < 0) || (tm->tm_sec > 59))
+ return -1;
- return 0;
-} /* DecodeTime() */
+ return 0;
+} /* DecodeTime() */
/* DecodeNumber()
* Interpret numeric field as a date value in context.
*/
static int
-DecodeNumber( int flen, char *str, int fmask, int *tmask, struct tm *tm, double *fsec)
+DecodeNumber(int flen, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
{
- int val;
- char *cp;
+ int val;
+ char *cp;
- *tmask = 0;
+ *tmask = 0;
- val = strtol( str, &cp, 10);
- if (cp == str) return -1;
- if (*cp == '.') {
- *fsec = strtod( cp, &cp);
- if (*cp != '\0') return -1;
- }
+ val = strtol(str, &cp, 10);
+ if (cp == str)
+ return -1;
+ if (*cp == '.')
+ {
+ *fsec = strtod(cp, &cp);
+ if (*cp != '\0')
+ return -1;
+ }
#ifdef DATEDEBUG
-printf( "DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask);
+ printf("DecodeNumber- %s is %d fmask=%08x tmask=%08x\n", str, val, fmask, *tmask);
#endif
- /* enough digits to be unequivocal year? */
- if (flen == 4) {
+ /* enough digits to be unequivocal year? */
+ if (flen == 4)
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumber- match %d (%s) as year\n", val, str);
+ printf("DecodeNumber- match %d (%s) as year\n", val, str);
#endif
- *tmask = DTK_M(YEAR);
-
- /* already have a year? then see if we can substitute... */
- if (fmask & DTK_M(YEAR)) {
- if ((!(fmask & DTK_M(DAY)))
- && ((tm->tm_year >= 1) && (tm->tm_year <= 31))) {
+ *tmask = DTK_M(YEAR);
+
+ /* already have a year? then see if we can substitute... */
+ if (fmask & DTK_M(YEAR))
+ {
+ if ((!(fmask & DTK_M(DAY)))
+ && ((tm->tm_year >= 1) && (tm->tm_year <= 31)))
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
+ printf("DecodeNumber- misidentified year previously; swap with day %d\n", tm->tm_mday);
#endif
- tm->tm_mday = tm->tm_year;
- *tmask = DTK_M(DAY);
- }
- }
-
- tm->tm_year = val;
+ tm->tm_mday = tm->tm_year;
+ *tmask = DTK_M(DAY);
+ }
+ }
- /* special case day of year? */
- } else if ((flen == 3) && (fmask & DTK_M(YEAR))
- && ((val >= 1) && (val <= 366))) {
- *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
- tm->tm_yday = val;
- j2date((date2j(tm->tm_year,1,1)+tm->tm_yday-1),
- &tm->tm_year,&tm->tm_mon,&tm->tm_mday);
+ tm->tm_year = val;
- /* already have year? then could be month */
- } else if ((fmask & DTK_M(YEAR)) && (! (fmask & DTK_M(MONTH)))
- && ((val >= 1) && (val <= 12))) {
+ /* special case day of year? */
+ }
+ else if ((flen == 3) && (fmask & DTK_M(YEAR))
+ && ((val >= 1) && (val <= 366)))
+ {
+ *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
+ tm->tm_yday = val;
+ j2date((date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1),
+ &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
+
+ /* already have year? then could be month */
+ }
+ else if ((fmask & DTK_M(YEAR)) && (!(fmask & DTK_M(MONTH)))
+ && ((val >= 1) && (val <= 12)))
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumber- match %d (%s) as month\n", val, str);
+ printf("DecodeNumber- match %d (%s) as month\n", val, str);
#endif
- *tmask = DTK_M(MONTH);
- tm->tm_mon = val;
+ *tmask = DTK_M(MONTH);
+ tm->tm_mon = val;
- /* no year and EuroDates enabled? then could be day */
- } else if ((EuroDates || (fmask & DTK_M(MONTH)))
- && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
- && ((val >= 1) && (val <= 31))) {
+ /* no year and EuroDates enabled? then could be day */
+ }
+ else if ((EuroDates || (fmask & DTK_M(MONTH)))
+ && (!(fmask & DTK_M(YEAR)) && !(fmask & DTK_M(DAY)))
+ && ((val >= 1) && (val <= 31)))
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumber- match %d (%s) as day\n", val, str);
+ printf("DecodeNumber- match %d (%s) as day\n", val, str);
#endif
- *tmask = DTK_M(DAY);
- tm->tm_mday = val;
+ *tmask = DTK_M(DAY);
+ tm->tm_mday = val;
- } else if ((! (fmask & DTK_M(MONTH)))
- && ((val >= 1) && (val <= 12))) {
+ }
+ else if ((!(fmask & DTK_M(MONTH)))
+ && ((val >= 1) && (val <= 12)))
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumber- (2) match %d (%s) as month\n", val, str);
+ printf("DecodeNumber- (2) match %d (%s) as month\n", val, str);
#endif
- *tmask = DTK_M(MONTH);
- tm->tm_mon = val;
+ *tmask = DTK_M(MONTH);
+ tm->tm_mon = val;
- } else if ((! (fmask & DTK_M(DAY)))
- && ((val >= 1) && (val <= 31))) {
+ }
+ else if ((!(fmask & DTK_M(DAY)))
+ && ((val >= 1) && (val <= 31)))
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumber- (2) match %d (%s) as day\n", val, str);
+ printf("DecodeNumber- (2) match %d (%s) as day\n", val, str);
#endif
- *tmask = DTK_M(DAY);
- tm->tm_mday = val;
+ *tmask = DTK_M(DAY);
+ tm->tm_mday = val;
- } else if (! (fmask & DTK_M(YEAR))) {
+ }
+ else if (!(fmask & DTK_M(YEAR)))
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumber- (2) match %d (%s) as year\n", val, str);
+ printf("DecodeNumber- (2) match %d (%s) as year\n", val, str);
#endif
- *tmask = DTK_M(YEAR);
- tm->tm_year = val;
- if (tm->tm_year < 70) {
- tm->tm_year += 2000;
- } else if (tm->tm_year < 100) {
- tm->tm_year += 1900;
- }
+ *tmask = DTK_M(YEAR);
+ tm->tm_year = val;
+ if (tm->tm_year < 70)
+ {
+ tm->tm_year += 2000;
+ }
+ else if (tm->tm_year < 100)
+ {
+ tm->tm_year += 1900;
+ }
- } else {
- return -1;
- }
+ }
+ else
+ {
+ return -1;
+ }
- return 0;
-} /* DecodeNumber() */
+ return 0;
+} /* DecodeNumber() */
/* DecodeNumberField()
* Interpret numeric string as a concatenated date field.
*/
static int
-DecodeNumberField( int len, char *str, int fmask, int *tmask, struct tm *tm, double *fsec)
+DecodeNumberField(int len, char *str, int fmask, int *tmask, struct tm * tm, double *fsec)
{
- char *cp;
+ char *cp;
- /* yyyymmdd? */
- if (len == 8) {
+ /* yyyymmdd? */
+ if (len == 8)
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+ printf("DecodeNumberField- %s is 8 character date fmask=%08x tmask=%08x\n", str, fmask, *tmask);
#endif
- *tmask = DTK_DATE_M;
+ *tmask = DTK_DATE_M;
- tm->tm_mday = atoi(str+6);
- *(str+6) = '\0';
- tm->tm_mon = atoi(str+4);
- *(str+4) = '\0';
- tm->tm_year = atoi(str+0);
+ tm->tm_mday = atoi(str + 6);
+ *(str + 6) = '\0';
+ tm->tm_mon = atoi(str + 4);
+ *(str + 4) = '\0';
+ tm->tm_year = atoi(str + 0);
- /* yymmdd or hhmmss? */
- } else if (len == 6) {
+ /* yymmdd or hhmmss? */
+ }
+ else if (len == 6)
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumberField- %s is 6 characters fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+ printf("DecodeNumberField- %s is 6 characters fmask=%08x tmask=%08x\n", str, fmask, *tmask);
#endif
- if (fmask & DTK_DATE_M) {
+ if (fmask & DTK_DATE_M)
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+ printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
#endif
- *tmask = DTK_TIME_M;
- tm->tm_sec = atoi(str+4);
- *(str+4) = '\0';
- tm->tm_min = atoi(str+2);
- *(str+2) = '\0';
- tm->tm_hour = atoi(str+0);
+ *tmask = DTK_TIME_M;
+ tm->tm_sec = atoi(str + 4);
+ *(str + 4) = '\0';
+ tm->tm_min = atoi(str + 2);
+ *(str + 2) = '\0';
+ tm->tm_hour = atoi(str + 0);
- } else {
+ }
+ else
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumberField- %s is date field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+ printf("DecodeNumberField- %s is date field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
#endif
- *tmask = DTK_DATE_M;
- tm->tm_mday = atoi(str+4);
- *(str+4) = '\0';
- tm->tm_mon = atoi(str+2);
- *(str+2) = '\0';
- tm->tm_year = atoi(str+0);
- }
+ *tmask = DTK_DATE_M;
+ tm->tm_mday = atoi(str + 4);
+ *(str + 4) = '\0';
+ tm->tm_mon = atoi(str + 2);
+ *(str + 2) = '\0';
+ tm->tm_year = atoi(str + 0);
+ }
- } else if (strchr(str,'.') != NULL) {
+ }
+ else if (strchr(str, '.') != NULL)
+ {
#ifdef DATEDEBUG
-printf( "DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
+ printf("DecodeNumberField- %s is time field fmask=%08x tmask=%08x\n", str, fmask, *tmask);
#endif
- *tmask = DTK_TIME_M;
- tm->tm_sec = strtod( (str+4), &cp);
- if (cp == (str+4)) return -1;
- if (*cp == '.') {
- *fsec = strtod( cp, NULL);
- }
- *(str+4) = '\0';
- tm->tm_min = strtod( (str+2), &cp);
- *(str+2) = '\0';
- tm->tm_hour = strtod( (str+0), &cp);
+ *tmask = DTK_TIME_M;
+ tm->tm_sec = strtod((str + 4), &cp);
+ if (cp == (str + 4))
+ return -1;
+ if (*cp == '.')
+ {
+ *fsec = strtod(cp, NULL);
+ }
+ *(str + 4) = '\0';
+ tm->tm_min = strtod((str + 2), &cp);
+ *(str + 2) = '\0';
+ tm->tm_hour = strtod((str + 0), &cp);
- } else {
- return -1;
- }
+ }
+ else
+ {
+ return -1;
+ }
- return 0;
-} /* DecodeNumberField() */
+ return 0;
+} /* DecodeNumberField() */
/* DecodeTimezone()
* Interpret string as a numeric timezone.
*/
static int
-DecodeTimezone( char *str, int *tzp)
+DecodeTimezone(char *str, int *tzp)
{
- int tz;
- int hr, min;
- char *cp;
- int len;
+ int tz;
+ int hr,
+ min;
+ char *cp;
+ int len;
- /* assume leading character is "+" or "-" */
- hr = strtol( (str+1), &cp, 10);
+ /* assume leading character is "+" or "-" */
+ hr = strtol((str + 1), &cp, 10);
- /* explicit delimiter? */
- if (*cp == ':') {
- min = strtol( (cp+1), &cp, 10);
+ /* explicit delimiter? */
+ if (*cp == ':')
+ {
+ min = strtol((cp + 1), &cp, 10);
- /* otherwise, might have run things together... */
- } else if ((*cp == '\0') && ((len = strlen(str)) > 3)) {
- min = strtol( (str+len-2), &cp, 10);
- *(str+len-2) = '\0';
- hr = strtol( (str+1), &cp, 10);
+ /* otherwise, might have run things together... */
+ }
+ else if ((*cp == '\0') && ((len = strlen(str)) > 3))
+ {
+ min = strtol((str + len - 2), &cp, 10);
+ *(str + len - 2) = '\0';
+ hr = strtol((str + 1), &cp, 10);
- } else {
- min = 0;
- }
+ }
+ else
+ {
+ min = 0;
+ }
- tz = (hr*60+min)*60;
- if (*str == '-') tz = -tz;
+ tz = (hr * 60 + min) * 60;
+ if (*str == '-')
+ tz = -tz;
- *tzp = -tz;
- return( *cp != '\0');
-} /* DecodeTimezone() */
+ *tzp = -tz;
+ return (*cp != '\0');
+} /* DecodeTimezone() */
/* DecodeSpecial()
* Decode text string using lookup table.
* Implement a cache lookup since it is likely that dates
- * will be related in format.
+ * will be related in format.
*/
static int
DecodeSpecial(int field, char *lowtoken, int *val)
{
- int type;
- datetkn *tp;
+ int type;
+ datetkn *tp;
#if USE_DATE_CACHE
- if ((datecache[field] != NULL)
- && (strncmp(lowtoken,datecache[field]->token,TOKMAXLEN) == 0)) {
- tp = datecache[field];
- } else {
+ if ((datecache[field] != NULL)
+ && (strncmp(lowtoken, datecache[field]->token, TOKMAXLEN) == 0))
+ {
+ tp = datecache[field];
+ }
+ else
+ {
#endif
- tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
+ tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
#if USE_DATE_CACHE
- }
- datecache[field] = tp;
-#endif
- if (tp == NULL) {
- type = IGNORE;
- *val = 0;
- } else {
- type = tp->type;
- switch (type) {
- case TZ:
- case DTZ:
- case DTZMOD:
- *val = FROMVAL(tp);
- break;
+ }
+ datecache[field] = tp;
+#endif
+ if (tp == NULL)
+ {
+ type = IGNORE;
+ *val = 0;
+ }
+ else
+ {
+ type = tp->type;
+ switch (type)
+ {
+ case TZ:
+ case DTZ:
+ case DTZMOD:
+ *val = FROMVAL(tp);
+ break;
- default:
- *val = tp->value;
- break;
+ default:
+ *val = tp->value;
+ break;
+ }
}
- }
- return(type);
-} /* DecodeSpecial() */
+ return (type);
+} /* DecodeSpecial() */
/* DecodeDateDelta()
@@ -3239,212 +3709,239 @@ DecodeSpecial(int field, char *lowtoken, int *val)
* Return 0 if decoded and -1 if problems.
*
* If code is changed to read fields from first to last,
- * then use READ_FORWARD-bracketed code to allow sign
- * to persist to subsequent unsigned fields.
+ * then use READ_FORWARD-bracketed code to allow sign
+ * to persist to subsequent unsigned fields.
*/
int
-DecodeDateDelta( char *field[], int ftype[], int nf, int *dtype, struct tm *tm, double *fsec)
+DecodeDateDelta(char *field[], int ftype[], int nf, int *dtype, struct tm * tm, double *fsec)
{
- int is_before = FALSE;
+ int is_before = FALSE;
+
#if READ_FORWARD
- int is_neg = FALSE;
+ int is_neg = FALSE;
+
#endif
- int fmask = 0, tmask, type;
- int i, ii;
- int flen, val;
- char *cp;
- double sec;
+ int fmask = 0,
+ tmask,
+ type;
+ int i,
+ ii;
+ int flen,
+ val;
+ char *cp;
+ double sec;
- *dtype = DTK_DELTA;
+ *dtype = DTK_DELTA;
- type = SECOND;
- tm->tm_year = 0;
- tm->tm_mon = 0;
- tm->tm_mday = 0;
- tm->tm_hour = 0;
- tm->tm_min = 0;
- tm->tm_sec = 0;
- *fsec = 0;
+ type = SECOND;
+ tm->tm_year = 0;
+ tm->tm_mon = 0;
+ tm->tm_mday = 0;
+ tm->tm_hour = 0;
+ tm->tm_min = 0;
+ tm->tm_sec = 0;
+ *fsec = 0;
- /* read through list forwards to pick up initial time fields, if any */
- for (ii = 0; ii < nf; ii++) {
+ /* read through list forwards to pick up initial time fields, if any */
+ for (ii = 0; ii < nf; ii++)
+ {
#ifdef DATEDEBUG
-printf( "DecodeDateDelta- field[%d] is %s (type %d)\n", ii, field[ii], ftype[ii]);
+ printf("DecodeDateDelta- field[%d] is %s (type %d)\n", ii, field[ii], ftype[ii]);
#endif
- if (ftype[ii] == DTK_TIME) {
- if (DecodeTime(field[ii], fmask, &tmask, tm, fsec) != 0) return -1;
- fmask |= tmask;
+ if (ftype[ii] == DTK_TIME)
+ {
+ if (DecodeTime(field[ii], fmask, &tmask, tm, fsec) != 0)
+ return -1;
+ fmask |= tmask;
- } else {
- break;
+ }
+ else
+ {
+ break;
+ }
}
- }
- /* read through remaining list backwards to pick up units before values */
- for (i = nf-1; i >= ii; i--) {
+ /*
+ * read through remaining list backwards to pick up units before
+ * values
+ */
+ for (i = nf - 1; i >= ii; i--)
+ {
#ifdef DATEDEBUG
-printf( "DecodeDateDelta- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
+ printf("DecodeDateDelta- field[%d] is %s (type %d)\n", i, field[i], ftype[i]);
#endif
- switch (ftype[i]) {
- case DTK_TIME:
- /* already read in forward-scan above so return error */
+ switch (ftype[i])
+ {
+ case DTK_TIME:
+ /* already read in forward-scan above so return error */
#if FALSE
- if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0) return -1;
+ if (DecodeTime(field[i], fmask, &tmask, tm, fsec) != 0)
+ return -1;
#endif
- return -1;
- break;
+ return -1;
+ break;
- case DTK_TZ: /* timezone is a token with a leading sign character */
+ case DTK_TZ: /* timezone is a token with a leading sign
+ * character */
#if READ_FORWARD
- is_neg = (*field[i] == '-');
+ is_neg = (*field[i] == '-');
#endif
- case DTK_NUMBER:
- val = strtol( field[i], &cp, 10);
+ case DTK_NUMBER:
+ val = strtol(field[i], &cp, 10);
#if READ_FORWARD
- if (is_neg && (val > 0)) val = -val;
-#endif
- if (*cp == '.') {
- *fsec = strtod( cp, NULL);
- if (val < 0) *fsec = - (*fsec);
- }
- flen = strlen(field[i]);
- tmask = 0; /* DTK_M(type); */
-
- switch (type) {
- case DTK_MICROSEC:
- *fsec += (val * 1e-6);
- break;
-
- case DTK_MILLISEC:
- *fsec += (val * 1e-3);
- break;
-
- case DTK_SECOND:
- tm->tm_sec += val;
- tmask = DTK_M(SECOND);
- break;
-
- case DTK_MINUTE:
- tm->tm_min += val;
- tmask = DTK_M(MINUTE);
- break;
-
- case DTK_HOUR:
- tm->tm_hour += val;
- tmask = DTK_M(HOUR);
- break;
-
- case DTK_DAY:
- tm->tm_mday += val;
- tmask = ((fmask & DTK_M(DAY))? 0: DTK_M(DAY));
- break;
-
- case DTK_WEEK:
- tm->tm_mday += val*7;
- tmask = ((fmask & DTK_M(DAY))? 0: DTK_M(DAY));
- break;
-
- case DTK_MONTH:
- tm->tm_mon += val;
- tmask = DTK_M(MONTH);
- break;
-
- case DTK_YEAR:
- tm->tm_year += val;
- tmask = ((fmask & DTK_M(YEAR))? 0: DTK_M(YEAR));
- break;
-
- case DTK_DECADE:
- tm->tm_year += val*10;
- tmask = ((fmask & DTK_M(YEAR))? 0: DTK_M(YEAR));
- break;
-
- case DTK_CENTURY:
- tm->tm_year += val*100;
- tmask = ((fmask & DTK_M(YEAR))? 0: DTK_M(YEAR));
- break;
-
- case DTK_MILLENIUM:
- tm->tm_year += val*1000;
- tmask = ((fmask & DTK_M(YEAR))? 0: DTK_M(YEAR));
- break;
-
- default:
- return -1;
- }
- break;
-
- case DTK_STRING:
- case DTK_SPECIAL:
- type = DecodeUnits( i, field[i], &val);
+ if (is_neg && (val > 0))
+ val = -val;
+#endif
+ if (*cp == '.')
+ {
+ *fsec = strtod(cp, NULL);
+ if (val < 0)
+ *fsec = -(*fsec);
+ }
+ flen = strlen(field[i]);
+ tmask = 0; /* DTK_M(type); */
+
+ switch (type)
+ {
+ case DTK_MICROSEC:
+ *fsec += (val * 1e-6);
+ break;
+
+ case DTK_MILLISEC:
+ *fsec += (val * 1e-3);
+ break;
+
+ case DTK_SECOND:
+ tm->tm_sec += val;
+ tmask = DTK_M(SECOND);
+ break;
+
+ case DTK_MINUTE:
+ tm->tm_min += val;
+ tmask = DTK_M(MINUTE);
+ break;
+
+ case DTK_HOUR:
+ tm->tm_hour += val;
+ tmask = DTK_M(HOUR);
+ break;
+
+ case DTK_DAY:
+ tm->tm_mday += val;
+ tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
+ break;
+
+ case DTK_WEEK:
+ tm->tm_mday += val * 7;
+ tmask = ((fmask & DTK_M(DAY)) ? 0 : DTK_M(DAY));
+ break;
+
+ case DTK_MONTH:
+ tm->tm_mon += val;
+ tmask = DTK_M(MONTH);
+ break;
+
+ case DTK_YEAR:
+ tm->tm_year += val;
+ tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
+ break;
+
+ case DTK_DECADE:
+ tm->tm_year += val * 10;
+ tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
+ break;
+
+ case DTK_CENTURY:
+ tm->tm_year += val * 100;
+ tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
+ break;
+
+ case DTK_MILLENIUM:
+ tm->tm_year += val * 1000;
+ tmask = ((fmask & DTK_M(YEAR)) ? 0 : DTK_M(YEAR));
+ break;
+
+ default:
+ return -1;
+ }
+ break;
+
+ case DTK_STRING:
+ case DTK_SPECIAL:
+ type = DecodeUnits(i, field[i], &val);
#ifdef DATEDEBUG
-printf( "DecodeDateDelta- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
+ printf("DecodeDateDelta- special field[%d] %s type=%d value=%d\n", i, field[i], type, val);
#endif
- if (type == IGNORE) continue;
+ if (type == IGNORE)
+ continue;
- tmask = 0; /* DTK_M(type); */
- switch (type) {
- case UNITS:
+ tmask = 0; /* DTK_M(type); */
+ switch (type)
+ {
+ case UNITS:
#ifdef DATEDEBUG
-printf( "DecodeDateDelta- UNITS field %s value is %d\n", field[i], val);
+ printf("DecodeDateDelta- UNITS field %s value is %d\n", field[i], val);
#endif
- type = val;
- break;
+ type = val;
+ break;
- case AGO:
- is_before = TRUE;
- type = val;
- break;
+ case AGO:
+ is_before = TRUE;
+ type = val;
+ break;
- case RESERV:
- tmask = (DTK_DATE_M || DTK_TIME_M);
- *dtype = val;
- break;
+ case RESERV:
+ tmask = (DTK_DATE_M || DTK_TIME_M);
+ *dtype = val;
+ break;
- default:
- return -1;
- }
- break;
+ default:
+ return -1;
+ }
+ break;
- default:
- return -1;
- }
+ default:
+ return -1;
+ }
#ifdef DATEDEBUG
-printf( "DecodeDateDelta- (%08x/%08x) field[%d] %s value is %d\n",
- fmask, tmask, i, field[i], val);
+ printf("DecodeDateDelta- (%08x/%08x) field[%d] %s value is %d\n",
+ fmask, tmask, i, field[i], val);
#endif
- if (tmask & fmask) return -1;
- fmask |= tmask;
- }
+ if (tmask & fmask)
+ return -1;
+ fmask |= tmask;
+ }
- if (*fsec != 0) {
- TMODULO(*fsec,sec,1);
- tm->tm_sec += sec;
- }
+ if (*fsec != 0)
+ {
+ TMODULO(*fsec, sec, 1);
+ tm->tm_sec += sec;
+ }
- if (is_before) {
- *fsec = -(*fsec);
- tm->tm_sec = -(tm->tm_sec);
- tm->tm_min = -(tm->tm_min);
- tm->tm_hour = -(tm->tm_hour);
- tm->tm_mday = -(tm->tm_mday);
- tm->tm_mon = -(tm->tm_mon);
- tm->tm_year = -(tm->tm_year);
- }
+ if (is_before)
+ {
+ *fsec = -(*fsec);
+ tm->tm_sec = -(tm->tm_sec);
+ tm->tm_min = -(tm->tm_min);
+ tm->tm_hour = -(tm->tm_hour);
+ tm->tm_mday = -(tm->tm_mday);
+ tm->tm_mon = -(tm->tm_mon);
+ tm->tm_year = -(tm->tm_year);
+ }
#ifdef DATEDEBUG
-printf( "DecodeDateDelta- mask %08x (%08x)", fmask, DTK_DATE_M);
-printf( " set y%04d m%02d d%02d", tm->tm_year, tm->tm_mon, tm->tm_mday);
-printf( " %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
+ printf("DecodeDateDelta- mask %08x (%08x)", fmask, DTK_DATE_M);
+ printf(" set y%04d m%02d d%02d", tm->tm_year, tm->tm_mon, tm->tm_mday);
+ printf(" %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
#endif
- /* ensure that at least one time field has been found */
- return((fmask != 0)? 0: -1);
-} /* DecodeDateDelta() */
+ /* ensure that at least one time field has been found */
+ return ((fmask != 0) ? 0 : -1);
+} /* DecodeDateDelta() */
/* DecodeUnits()
@@ -3454,34 +3951,43 @@ printf( " %02d:%02d:%02d\n", tm->tm_hour, tm->tm_min, tm->tm_sec);
static int
DecodeUnits(int field, char *lowtoken, int *val)
{
- int type;
- datetkn *tp;
+ int type;
+ datetkn *tp;
#if USE_DATE_CACHE
- if ((deltacache[field] != NULL)
- && (strncmp(lowtoken,deltacache[field]->token,TOKMAXLEN) == 0)) {
- tp = deltacache[field];
- } else {
+ if ((deltacache[field] != NULL)
+ && (strncmp(lowtoken, deltacache[field]->token, TOKMAXLEN) == 0))
+ {
+ tp = deltacache[field];
+ }
+ else
+ {
#endif
- tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
+ tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
#if USE_DATE_CACHE
- }
- deltacache[field] = tp;
+ }
+ deltacache[field] = tp;
#endif
- if (tp == NULL) {
- type = IGNORE;
- *val = 0;
- } else {
- type = tp->type;
- if ((type == TZ) || (type == DTZ)) {
- *val = FROMVAL(tp);
- } else {
- *val = tp->value;
+ if (tp == NULL)
+ {
+ type = IGNORE;
+ *val = 0;
+ }
+ else
+ {
+ type = tp->type;
+ if ((type == TZ) || (type == DTZ))
+ {
+ *val = FROMVAL(tp);
+ }
+ else
+ {
+ *val = tp->value;
+ }
}
- }
- return(type);
-} /* DecodeUnits() */
+ return (type);
+} /* DecodeUnits() */
/* datebsearch()
@@ -3489,25 +3995,28 @@ DecodeUnits(int field, char *lowtoken, int *val)
* is WAY faster than the generic bsearch().
*/
static datetkn *
-datebsearch(char *key, datetkn *base, unsigned int nel)
+datebsearch(char *key, datetkn * base, unsigned int nel)
{
- register datetkn *last = base + nel - 1, *position;
- register int result;
-
- while (last >= base) {
- position = base + ((last - base) >> 1);
- result = key[0] - position->token[0];
- if (result == 0) {
- result = strncmp(key, position->token, TOKMAXLEN);
- if (result == 0)
- return position;
+ register datetkn *last = base + nel - 1,
+ *position;
+ register int result;
+
+ while (last >= base)
+ {
+ position = base + ((last - base) >> 1);
+ result = key[0] - position->token[0];
+ if (result == 0)
+ {
+ result = strncmp(key, position->token, TOKMAXLEN);
+ if (result == 0)
+ return position;
+ }
+ if (result < 0)
+ last = position - 1;
+ else
+ base = position + 1;
}
- if (result < 0)
- last = position - 1;
- else
- base = position + 1;
- }
- return NULL;
+ return NULL;
}
@@ -3517,373 +4026,466 @@ datebsearch(char *key, datetkn *base, unsigned int nel)
static int
EncodeSpecialDateTime(DateTime dt, char *str)
{
- if (DATETIME_IS_RESERVED(dt)) {
- if (DATETIME_IS_INVALID(dt)) {
- strcpy( str, INVALID);
+ if (DATETIME_IS_RESERVED(dt))
+ {
+ if (DATETIME_IS_INVALID(dt))
+ {
+ strcpy(str, INVALID);
- } else if (DATETIME_IS_NOBEGIN(dt)) {
- strcpy( str, EARLY);
+ }
+ else if (DATETIME_IS_NOBEGIN(dt))
+ {
+ strcpy(str, EARLY);
- } else if (DATETIME_IS_NOEND(dt)) {
- strcpy( str, LATE);
+ }
+ else if (DATETIME_IS_NOEND(dt))
+ {
+ strcpy(str, LATE);
- } else if (DATETIME_IS_CURRENT(dt)) {
- strcpy( str, DCURRENT);
+ }
+ else if (DATETIME_IS_CURRENT(dt))
+ {
+ strcpy(str, DCURRENT);
- } else if (DATETIME_IS_EPOCH(dt)) {
- strcpy( str, EPOCH);
+ }
+ else if (DATETIME_IS_EPOCH(dt))
+ {
+ strcpy(str, EPOCH);
- } else {
+ }
+ else
+ {
#ifdef DATEDEBUG
-printf( "EncodeSpecialDateTime- unrecognized date\n");
+ printf("EncodeSpecialDateTime- unrecognized date\n");
#endif
- strcpy( str, INVALID);
+ strcpy(str, INVALID);
+ }
+ return (TRUE);
}
- return(TRUE);
- }
- return(FALSE);
-} /* EncodeSpecialDateTime() */
+ return (FALSE);
+} /* EncodeSpecialDateTime() */
/* EncodeDateOnly()
* Encode date as local time.
*/
-int EncodeDateOnly(struct tm *tm, int style, char *str)
+int
+EncodeDateOnly(struct tm * tm, int style, char *str)
{
#if FALSE
- int day;
+ int day;
+
#endif
- if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
- return -1;
+ if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
+ return -1;
- /* compatible with ISO date formats */
- if (style == USE_ISO_DATES) {
- if (tm->tm_year > 0) {
- sprintf( str, "%04d-%02d-%02d",
- tm->tm_year, tm->tm_mon, tm->tm_mday);
+ /* compatible with ISO date formats */
+ if (style == USE_ISO_DATES)
+ {
+ if (tm->tm_year > 0)
+ {
+ sprintf(str, "%04d-%02d-%02d",
+ tm->tm_year, tm->tm_mon, tm->tm_mday);
- } else {
- sprintf( str, "%04d-%02d-%02d %s",
- -(tm->tm_year-1), tm->tm_mon, tm->tm_mday, "BC");
- }
+ }
+ else
+ {
+ sprintf(str, "%04d-%02d-%02d %s",
+ -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
+ }
- /* compatible with Oracle/Ingres date formats */
- } else if (style == USE_SQL_DATES) {
- if (EuroDates) {
- sprintf( str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
- } else {
- sprintf( str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
+ /* compatible with Oracle/Ingres date formats */
}
- if (tm->tm_year > 0) {
- sprintf( (str+5), "/%04d", tm->tm_year);
+ else if (style == USE_SQL_DATES)
+ {
+ if (EuroDates)
+ {
+ sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
+ }
+ else
+ {
+ sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
+ }
+ if (tm->tm_year > 0)
+ {
+ sprintf((str + 5), "/%04d", tm->tm_year);
- } else {
- sprintf( (str+5), "/%04d %s", -(tm->tm_year-1), "BC");
- }
+ }
+ else
+ {
+ sprintf((str + 5), "/%04d %s", -(tm->tm_year - 1), "BC");
+ }
- /* backward-compatible with traditional Postgres abstime dates */
- } else { /* if (style == USE_POSTGRES_DATES) */
+ /* backward-compatible with traditional Postgres abstime dates */
+ }
+ else
+ { /* if (style == USE_POSTGRES_DATES) */
#if FALSE
- day = date2j( tm->tm_year, tm->tm_mon, tm->tm_mday);
+ day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
#ifdef DATEDEBUG
-printf( "EncodeDateOnly- day is %d\n", day);
+ printf("EncodeDateOnly- day is %d\n", day);
#endif
- tm->tm_wday = j2day( day);
+ tm->tm_wday = j2day(day);
- strncpy( str, days[tm->tm_wday], 3);
- strcpy( (str+3), " ");
+ strncpy(str, days[tm->tm_wday], 3);
+ strcpy((str + 3), " ");
- if (EuroDates) {
- sprintf( (str+4), "%02d %3s", tm->tm_mday, months[tm->tm_mon-1]);
- } else {
- sprintf( (str+4), "%3s %02d", months[tm->tm_mon-1], tm->tm_mday);
- }
- if (tm->tm_year > 0) {
- sprintf( (str+10), " %04d", tm->tm_year);
+ if (EuroDates)
+ {
+ sprintf((str + 4), "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
+ }
+ else
+ {
+ sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
+ }
+ if (tm->tm_year > 0)
+ {
+ sprintf((str + 10), " %04d", tm->tm_year);
- } else {
- sprintf( (str+10), " %04d %s", -(tm->tm_year-1), "BC");
- }
+ }
+ else
+ {
+ sprintf((str + 10), " %04d %s", -(tm->tm_year - 1), "BC");
+ }
#endif
- /* traditional date-only style for Postgres */
- if (EuroDates) {
- sprintf( str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
- } else {
- sprintf( str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
- }
- if (tm->tm_year > 0) {
- sprintf( (str+5), "-%04d", tm->tm_year);
+ /* traditional date-only style for Postgres */
+ if (EuroDates)
+ {
+ sprintf(str, "%02d-%02d", tm->tm_mday, tm->tm_mon);
+ }
+ else
+ {
+ sprintf(str, "%02d-%02d", tm->tm_mon, tm->tm_mday);
+ }
+ if (tm->tm_year > 0)
+ {
+ sprintf((str + 5), "-%04d", tm->tm_year);
- } else {
- sprintf( (str+5), "-%04d %s", -(tm->tm_year-1), "BC");
+ }
+ else
+ {
+ sprintf((str + 5), "-%04d %s", -(tm->tm_year - 1), "BC");
+ }
}
- }
#ifdef DATEDEBUG
-printf( "EncodeDateOnly- date result is %s\n", str);
+ printf("EncodeDateOnly- date result is %s\n", str);
#endif
- return(TRUE);
-} /* EncodeDateOnly() */
+ return (TRUE);
+} /* EncodeDateOnly() */
/* EncodeTimeOnly()
* Encode time fields only.
*/
-int EncodeTimeOnly(struct tm *tm, double fsec, int style, char *str)
+int
+EncodeTimeOnly(struct tm * tm, double fsec, int style, char *str)
{
- double sec;
+ double sec;
- if ((tm->tm_hour < 0) || (tm->tm_hour > 24))
- return -1;
+ if ((tm->tm_hour < 0) || (tm->tm_hour > 24))
+ return -1;
- sec = (tm->tm_sec + fsec);
+ sec = (tm->tm_sec + fsec);
- sprintf( str, "%02d:%02d:", tm->tm_hour, tm->tm_min);
- sprintf( (str+6), ((fsec != 0)? "%05.2f": "%02.0f"), sec);
+ sprintf(str, "%02d:%02d:", tm->tm_hour, tm->tm_min);
+ sprintf((str + 6), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec);
#ifdef DATEDEBUG
-printf( "EncodeTimeOnly- time result is %s\n", str);
+ printf("EncodeTimeOnly- time result is %s\n", str);
#endif
- return(TRUE);
-} /* EncodeTimeOnly() */
+ return (TRUE);
+} /* EncodeTimeOnly() */
/* EncodeDateTime()
* Encode date and time interpreted as local time.
*/
-int EncodeDateTime(struct tm *tm, double fsec, int *tzp, char **tzn, int style, char *str)
+int
+EncodeDateTime(struct tm * tm, double fsec, int *tzp, char **tzn, int style, char *str)
{
- int day, hour, min;
- double sec;
+ int day,
+ hour,
+ min;
+ double sec;
- if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
- return -1;
+ if ((tm->tm_mon < 1) || (tm->tm_mon > 12))
+ return -1;
- sec = (tm->tm_sec + fsec);
+ sec = (tm->tm_sec + fsec);
#ifdef DATEDEBUG
#ifdef USE_POSIX_TIME
#ifdef HAVE_INT_TIMEZONE
-printf( "EncodeDateTime- timezone is %s (%s); offset is %d (%d); daylight is %d (%d)\n",
- *tzn, tzname[0], *tzp, CTimeZone, tm->tm_isdst, CDayLight);
+ printf("EncodeDateTime- timezone is %s (%s); offset is %d (%d); daylight is %d (%d)\n",
+ *tzn, tzname[0], *tzp, CTimeZone, tm->tm_isdst, CDayLight);
#else
-printf( "EncodeDateTime- timezone is %s (%s); offset is %ld (%d); daylight is %d (%d)\n",
- *tzn, tm->tm_zone, (- tm->tm_gmtoff), CTimeZone, tm->tm_isdst, CDayLight);
+ printf("EncodeDateTime- timezone is %s (%s); offset is %ld (%d); daylight is %d (%d)\n",
+ *tzn, tm->tm_zone, (-tm->tm_gmtoff), CTimeZone, tm->tm_isdst, CDayLight);
#endif
#else
-printf( "EncodeDateTime- timezone is %s (%s); offset is %d; daylight is %d\n",
- *tzn, CTZName, CTimeZone, CDayLight);
+ printf("EncodeDateTime- timezone is %s (%s); offset is %d; daylight is %d\n",
+ *tzn, CTZName, CTimeZone, CDayLight);
#endif
#endif
- /* compatible with ISO date formats */
- if (style == USE_ISO_DATES) {
- if (tm->tm_year > 0) {
- sprintf( str, "%04d-%02d-%02d %02d:%02d:",
- tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
- sprintf( (str+17), ((fsec != 0)? "%05.2f": "%02.0f"), sec);
+ /* compatible with ISO date formats */
+ if (style == USE_ISO_DATES)
+ {
+ if (tm->tm_year > 0)
+ {
+ sprintf(str, "%04d-%02d-%02d %02d:%02d:",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min);
+ sprintf((str + 17), ((fsec != 0) ? "%05.2f" : "%02.0f"), sec);
+
+ if ((*tzn != NULL) && (tm->tm_isdst >= 0))
+ {
+ if (tzp != NULL)
+ {
+ hour = -(*tzp / 3600);
+ min = ((abs(*tzp) / 60) % 60);
+ }
+ else
+ {
+ hour = 0;
+ min = 0;
+ }
+ sprintf((str + strlen(str)), ((min != 0) ? "%+03d:%02d" : "%+03d"), hour, min);
+ }
- if ((*tzn != NULL) && (tm->tm_isdst >= 0)) {
- if (tzp != NULL) {
- hour = -(*tzp / 3600);
- min = ((abs(*tzp) / 60) % 60);
- } else {
- hour = 0;
- min = 0;
}
- sprintf( (str+strlen(str)), ((min != 0)? "%+03d:%02d": "%+03d"), hour, min);
- }
+ else
+ {
+ if (tm->tm_hour || tm->tm_min)
+ {
+ sprintf(str, "%04d-%02d-%02d %02d:%02d %s",
+ -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, "BC");
+ }
+ else
+ {
+ sprintf(str, "%04d-%02d-%02d %s",
+ -(tm->tm_year - 1), tm->tm_mon, tm->tm_mday, "BC");
+ }
+ }
- } else {
- if (tm->tm_hour || tm->tm_min) {
- sprintf( str, "%04d-%02d-%02d %02d:%02d %s",
- -(tm->tm_year-1), tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, "BC");
- } else {
- sprintf( str, "%04d-%02d-%02d %s",
- -(tm->tm_year-1), tm->tm_mon, tm->tm_mday, "BC");
- }
+ /* compatible with Oracle/Ingres date formats */
}
+ else if (style == USE_SQL_DATES)
+ {
+ if (EuroDates)
+ {
+ sprintf(str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
+ }
+ else
+ {
+ sprintf(str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
+ }
+ if (tm->tm_year > 0)
+ {
+ sprintf((str + 5), "/%04d %02d:%02d:%05.2f",
+ tm->tm_year, tm->tm_hour, tm->tm_min, sec);
- /* compatible with Oracle/Ingres date formats */
- } else if (style == USE_SQL_DATES) {
- if (EuroDates) {
- sprintf( str, "%02d/%02d", tm->tm_mday, tm->tm_mon);
- } else {
- sprintf( str, "%02d/%02d", tm->tm_mon, tm->tm_mday);
- }
- if (tm->tm_year > 0) {
- sprintf( (str+5), "/%04d %02d:%02d:%05.2f",
- tm->tm_year, tm->tm_hour, tm->tm_min, sec);
+ if ((*tzn != NULL) && (tm->tm_isdst >= 0))
+ {
+ strcpy((str + 22), " ");
+ strcpy((str + 23), *tzn);
+ }
- if ((*tzn != NULL) && (tm->tm_isdst >= 0)) {
- strcpy( (str+22), " ");
- strcpy( (str+23), *tzn);
- }
+ }
+ else
+ {
+ sprintf((str + 5), "/%04d %02d:%02d %s",
+ -(tm->tm_year - 1), tm->tm_hour, tm->tm_min, "BC");
+ }
- } else {
- sprintf( (str+5), "/%04d %02d:%02d %s",
- -(tm->tm_year-1), tm->tm_hour, tm->tm_min, "BC");
+ /* backward-compatible with traditional Postgres abstime dates */
}
-
- /* backward-compatible with traditional Postgres abstime dates */
- } else { /* if (style == USE_POSTGRES_DATES) */
- day = date2j( tm->tm_year, tm->tm_mon, tm->tm_mday);
+ else
+ { /* if (style == USE_POSTGRES_DATES) */
+ day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
#ifdef DATEDEBUG
-printf( "EncodeDateTime- day is %d\n", day);
+ printf("EncodeDateTime- day is %d\n", day);
#endif
- tm->tm_wday = j2day( day);
+ tm->tm_wday = j2day(day);
- strncpy( str, days[tm->tm_wday], 3);
- strcpy( (str+3), " ");
+ strncpy(str, days[tm->tm_wday], 3);
+ strcpy((str + 3), " ");
- if (EuroDates) {
- sprintf( (str+4), "%02d %3s", tm->tm_mday, months[tm->tm_mon-1]);
- } else {
- sprintf( (str+4), "%3s %02d", months[tm->tm_mon-1], tm->tm_mday);
- }
- if (tm->tm_year > 0) {
- sprintf( (str+10), " %02d:%02d", tm->tm_hour, tm->tm_min);
- if (fsec != 0) {
- sprintf( (str+16), ":%05.2f %04d", sec, tm->tm_year);
- if ((*tzn != NULL) && (tm->tm_isdst >= 0)) {
- strcpy( (str+27), " ");
- strcpy( (str+28), *tzn);
+ if (EuroDates)
+ {
+ sprintf((str + 4), "%02d %3s", tm->tm_mday, months[tm->tm_mon - 1]);
}
- } else {
- sprintf( (str+16), ":%02.0f %04d", sec, tm->tm_year);
- if ((*tzn != NULL) && (tm->tm_isdst >= 0)) {
- strcpy( (str+24), " ");
- strcpy( (str+25), *tzn);
+ else
+ {
+ sprintf((str + 4), "%3s %02d", months[tm->tm_mon - 1], tm->tm_mday);
}
- }
+ if (tm->tm_year > 0)
+ {
+ sprintf((str + 10), " %02d:%02d", tm->tm_hour, tm->tm_min);
+ if (fsec != 0)
+ {
+ sprintf((str + 16), ":%05.2f %04d", sec, tm->tm_year);
+ if ((*tzn != NULL) && (tm->tm_isdst >= 0))
+ {
+ strcpy((str + 27), " ");
+ strcpy((str + 28), *tzn);
+ }
+ }
+ else
+ {
+ sprintf((str + 16), ":%02.0f %04d", sec, tm->tm_year);
+ if ((*tzn != NULL) && (tm->tm_isdst >= 0))
+ {
+ strcpy((str + 24), " ");
+ strcpy((str + 25), *tzn);
+ }
+ }
- } else {
- sprintf( (str+10), " %02d:%02d %04d %s",
- tm->tm_hour, tm->tm_min, -(tm->tm_year-1), "BC");
+ }
+ else
+ {
+ sprintf((str + 10), " %02d:%02d %04d %s",
+ tm->tm_hour, tm->tm_min, -(tm->tm_year - 1), "BC");
+ }
}
- }
#ifdef DATEDEBUG
-printf( "EncodeDateTime- date result is %s\n", str);
+ printf("EncodeDateTime- date result is %s\n", str);
#endif
- return(TRUE);
-} /* EncodeDateTime() */
+ return (TRUE);
+} /* EncodeDateTime() */
/* EncodeTimeSpan()
* Interpret time structure as a delta time and convert to string.
*
* Pass a flag to specify the style of string, but only implement
- * the traditional Postgres style for now. - tgl 97/03/27
+ * the traditional Postgres style for now. - tgl 97/03/27
*/
-int EncodeTimeSpan(struct tm *tm, double fsec, int style, char *str)
-{
- int is_before = FALSE;
- int is_nonzero = FALSE;
- char *cp;
-
- strcpy( str, "@");
- cp = str+strlen(str);
-
- if (tm->tm_year != 0) {
- is_nonzero = TRUE;
- is_before |= (tm->tm_year < 0);
- sprintf( cp, " %d year%s", abs(tm->tm_year), ((abs(tm->tm_year) != 1)? "s": ""));
- cp += strlen(cp);
- }
-
- if (tm->tm_mon != 0) {
- is_nonzero = TRUE;
- is_before |= (tm->tm_mon < 0);
- sprintf( cp, " %d mon%s", abs(tm->tm_mon), ((abs(tm->tm_mon) != 1)? "s": ""));
- cp += strlen(cp);
- }
-
- if (tm->tm_mday != 0) {
- is_nonzero = TRUE;
- is_before |= (tm->tm_mday < 0);
- sprintf( cp, " %d day%s", abs(tm->tm_mday), ((abs(tm->tm_mday) != 1)? "s": ""));
- cp += strlen(cp);
- }
-
- if (tm->tm_hour != 0) {
- is_nonzero = TRUE;
- is_before |= (tm->tm_hour < 0);
- sprintf( cp, " %d hour%s", abs(tm->tm_hour), ((abs(tm->tm_hour) != 1)? "s": ""));
- cp += strlen(cp);
- }
-
- if (tm->tm_min != 0) {
- is_nonzero = TRUE;
- is_before |= (tm->tm_min < 0);
- sprintf( cp, " %d min%s", abs(tm->tm_min), ((abs(tm->tm_min) != 1)? "s": ""));
- cp += strlen(cp);
- }
-
- /* fractional seconds? */
- if (fsec != 0) {
- is_nonzero = TRUE;
- fsec += tm->tm_sec;
- is_before |= (fsec < 0);
- sprintf( cp, " %.2f secs", fabs(fsec));
- cp += strlen(cp);
-
- /* otherwise, integer seconds only? */
- } else if (tm->tm_sec != 0) {
- is_nonzero = TRUE;
- is_before |= (tm->tm_sec < 0);
- sprintf( cp, " %d sec%s", abs(tm->tm_sec), ((abs(tm->tm_sec) != 1)? "s": ""));
- cp += strlen(cp);
- }
-
- /* identically zero? then put in a unitless zero... */
- if (! is_nonzero) {
- strcat( cp, " 0");
- cp += strlen(cp);
- }
-
- if (is_before) {
- strcat( cp, " ago");
- cp += strlen(cp);
- }
-
-#ifdef DATEDEBUG
-printf( "EncodeTimeSpan- result is %s\n", str);
-#endif
-
- return 0;
-} /* EncodeTimeSpan() */
+int
+EncodeTimeSpan(struct tm * tm, double fsec, int style, char *str)
+{
+ int is_before = FALSE;
+ int is_nonzero = FALSE;
+ char *cp;
+
+ strcpy(str, "@");
+ cp = str + strlen(str);
+
+ if (tm->tm_year != 0)
+ {
+ is_nonzero = TRUE;
+ is_before |= (tm->tm_year < 0);
+ sprintf(cp, " %d year%s", abs(tm->tm_year), ((abs(tm->tm_year) != 1) ? "s" : ""));
+ cp += strlen(cp);
+ }
+
+ if (tm->tm_mon != 0)
+ {
+ is_nonzero = TRUE;
+ is_before |= (tm->tm_mon < 0);
+ sprintf(cp, " %d mon%s", abs(tm->tm_mon), ((abs(tm->tm_mon) != 1) ? "s" : ""));
+ cp += strlen(cp);
+ }
+
+ if (tm->tm_mday != 0)
+ {
+ is_nonzero = TRUE;
+ is_before |= (tm->tm_mday < 0);
+ sprintf(cp, " %d day%s", abs(tm->tm_mday), ((abs(tm->tm_mday) != 1) ? "s" : ""));
+ cp += strlen(cp);
+ }
+
+ if (tm->tm_hour != 0)
+ {
+ is_nonzero = TRUE;
+ is_before |= (tm->tm_hour < 0);
+ sprintf(cp, " %d hour%s", abs(tm->tm_hour), ((abs(tm->tm_hour) != 1) ? "s" : ""));
+ cp += strlen(cp);
+ }
+
+ if (tm->tm_min != 0)
+ {
+ is_nonzero = TRUE;
+ is_before |= (tm->tm_min < 0);
+ sprintf(cp, " %d min%s", abs(tm->tm_min), ((abs(tm->tm_min) != 1) ? "s" : ""));
+ cp += strlen(cp);
+ }
+
+ /* fractional seconds? */
+ if (fsec != 0)
+ {
+ is_nonzero = TRUE;
+ fsec += tm->tm_sec;
+ is_before |= (fsec < 0);
+ sprintf(cp, " %.2f secs", fabs(fsec));
+ cp += strlen(cp);
+
+ /* otherwise, integer seconds only? */
+ }
+ else if (tm->tm_sec != 0)
+ {
+ is_nonzero = TRUE;
+ is_before |= (tm->tm_sec < 0);
+ sprintf(cp, " %d sec%s", abs(tm->tm_sec), ((abs(tm->tm_sec) != 1) ? "s" : ""));
+ cp += strlen(cp);
+ }
+
+ /* identically zero? then put in a unitless zero... */
+ if (!is_nonzero)
+ {
+ strcat(cp, " 0");
+ cp += strlen(cp);
+ }
+
+ if (is_before)
+ {
+ strcat(cp, " ago");
+ cp += strlen(cp);
+ }
+
+#ifdef DATEDEBUG
+ printf("EncodeTimeSpan- result is %s\n", str);
+#endif
+
+ return 0;
+} /* EncodeTimeSpan() */
#if defined(linux) && defined(PPC)
-int datetime_is_epoch(double j)
+int
+datetime_is_epoch(double j)
{
- static union {
- double epoch;
- unsigned char c[8];
- } u;
+ static union
+ {
+ double epoch;
+ unsigned char c[8];
+ } u;
- u.c[0] = 0x80; /* sign bit */
- u.c[1] = 0x10; /* DBL_MIN */
+ u.c[0] = 0x80; /* sign bit */
+ u.c[1] = 0x10; /* DBL_MIN */
- return(j == u.epoch);
+ return (j == u.epoch);
}
-int datetime_is_current(double j)
+int
+datetime_is_current(double j)
{
- static union {
- double current;
- unsigned char c[8];
- } u;
+ static union
+ {
+ double current;
+ unsigned char c[8];
+ } u;
- u.c[1] = 0x10; /* DBL_MIN */
+ u.c[1] = 0x10; /* DBL_MIN */
- return(j == u.current);
+ return (j == u.current);
}
+
#endif
diff --git a/src/backend/utils/adt/filename.c b/src/backend/utils/adt/filename.c
index a14b8283b59..445de98a77a 100644
--- a/src/backend/utils/adt/filename.c
+++ b/src/backend/utils/adt/filename.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* filename.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/filename.c,v 1.8 1997/08/12 20:15:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/filename.c,v 1.9 1997/09/07 04:50:14 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,95 +20,118 @@
#include "postgres.h"
#include <miscadmin.h>
-#include "utils/builtins.h" /* where function declarations go */
+#include "utils/builtins.h" /* where function declarations go */
-char *
+char *
filename_in(char *file)
{
- char *str;
- int ind = 0;
-
- /*
- * XXX - HACK CITY --- REDO
- * should let the shell do expansions (shexpand)
- */
+ char *str;
+ int ind = 0;
- str = (char *) palloc(MAXPATHLEN * sizeof(*str));
- str[0] = '\0';
- if (file[0] == '~') {
- if (file[1] == '\0' || file[1] == '/') {
- /* Home directory */
-
- char *userName;
- struct passwd *pw;
-
- userName = GetPgUserName();
-
- if ((pw = getpwnam(userName)) == NULL) {
- elog(WARN, "User %s is not a Unix user on the db server.",
- userName);
- }
-
- strcpy(str, pw->pw_dir);
-
- ind = 1;
- } else {
- /* Someone else's directory */
- char name[16], *p;
- struct passwd *pw;
- int len;
-
- if ((p = (char *) strchr(file, '/')) == NULL) {
- strcpy(name, file+1);
- len = strlen(name);
- } else {
- len = (p - file) - 1;
- strNcpy(name, file+1, len);
- }
- /*printf("name: %s\n");*/
- if ((pw = getpwnam(name)) == NULL) {
- elog(WARN, "No such user: %s\n", name);
- ind = 0;
- } else {
- strcpy(str, pw->pw_dir);
- ind = len + 1;
- }
- }
- } else if (file[0] == '$') { /* $POSTGRESHOME, etc. expand it. */
- char environment[80], *envirp, *p;
- int len;
-
- if ((p = (char *) strchr(file, '/')) == NULL) {
- strcpy(environment, file+1);
- len = strlen(environment);
- } else {
- len = (p - file) - 1;
- strNcpy(environment, file+1, len);
+ /*
+ * XXX - HACK CITY --- REDO should let the shell do expansions
+ * (shexpand)
+ */
+
+ str = (char *) palloc(MAXPATHLEN * sizeof(*str));
+ str[0] = '\0';
+ if (file[0] == '~')
+ {
+ if (file[1] == '\0' || file[1] == '/')
+ {
+ /* Home directory */
+
+ char *userName;
+ struct passwd *pw;
+
+ userName = GetPgUserName();
+
+ if ((pw = getpwnam(userName)) == NULL)
+ {
+ elog(WARN, "User %s is not a Unix user on the db server.",
+ userName);
+ }
+
+ strcpy(str, pw->pw_dir);
+
+ ind = 1;
+ }
+ else
+ {
+ /* Someone else's directory */
+ char name[16],
+ *p;
+ struct passwd *pw;
+ int len;
+
+ if ((p = (char *) strchr(file, '/')) == NULL)
+ {
+ strcpy(name, file + 1);
+ len = strlen(name);
+ }
+ else
+ {
+ len = (p - file) - 1;
+ strNcpy(name, file + 1, len);
+ }
+ /* printf("name: %s\n"); */
+ if ((pw = getpwnam(name)) == NULL)
+ {
+ elog(WARN, "No such user: %s\n", name);
+ ind = 0;
+ }
+ else
+ {
+ strcpy(str, pw->pw_dir);
+ ind = len + 1;
+ }
+ }
}
- envirp = getenv(environment);
- if (envirp) {
- strcpy(str, envirp);
- ind = len + 1;
+ else if (file[0] == '$')
+ { /* $POSTGRESHOME, etc. expand it. */
+ char environment[80],
+ *envirp,
+ *p;
+ int len;
+
+ if ((p = (char *) strchr(file, '/')) == NULL)
+ {
+ strcpy(environment, file + 1);
+ len = strlen(environment);
+ }
+ else
+ {
+ len = (p - file) - 1;
+ strNcpy(environment, file + 1, len);
+ }
+ envirp = getenv(environment);
+ if (envirp)
+ {
+ strcpy(str, envirp);
+ ind = len + 1;
+ }
+ else
+ {
+ elog(WARN, "Couldn't find %s in your environment", environment);
+ }
}
- else {
- elog(WARN,"Couldn't find %s in your environment", environment);
+ else
+ {
+ ind = 0;
}
- } else {
- ind = 0;
- }
- strcat(str, file+ind);
- return(str);
+ strcat(str, file + ind);
+ return (str);
}
-char *
+char *
filename_out(char *s)
{
- char *ret;
-
- if (!s)
- return((char *) NULL);
- ret = (char *) palloc(strlen(s) + 1);
- if (!ret)
- elog(WARN, "filename_out: palloc failed");
- return(strcpy(ret, s));
+ char *ret;
+
+ if (!s)
+ return ((char *) NULL);
+ ret = (char *) palloc(strlen(s) + 1);
+ if (!ret)
+ elog(WARN, "filename_out: palloc failed");
+ return (strcpy(ret, s));
}
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 3518fd7d4cc..32d78fb2ba7 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -1,66 +1,66 @@
/*-------------------------------------------------------------------------
*
* float.c--
- * Functions for the built-in floating-point types.
+ * Functions for the built-in floating-point types.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.17 1997/07/28 00:55:49 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/float.c,v 1.18 1997/09/07 04:50:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* OLD COMMENTS
- * Basic float4 ops:
- * float4in, float4out, float4abs, float4um
- * Basic float8 ops:
- * float8in, float8inAd, float8out, float8outAd, float8abs, float8um
- * Arithmetic operators:
- * float4pl, float4mi, float4mul, float4div
- * float8pl, float8mi, float8mul, float8div
- * Comparison operators:
- * float4eq, float4ne, float4lt, float4le, float4gt, float4ge
- * float8eq, float8ne, float8lt, float8le, float8gt, float8ge
- * Conversion routines:
- * ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
+ * Basic float4 ops:
+ * float4in, float4out, float4abs, float4um
+ * Basic float8 ops:
+ * float8in, float8inAd, float8out, float8outAd, float8abs, float8um
+ * Arithmetic operators:
+ * float4pl, float4mi, float4mul, float4div
+ * float8pl, float8mi, float8mul, float8div
+ * Comparison operators:
+ * float4eq, float4ne, float4lt, float4le, float4gt, float4ge
+ * float8eq, float8ne, float8lt, float8le, float8gt, float8ge
+ * Conversion routines:
+ * ftod, dtof, i4tod, dtoi4, i2tod, dtoi2, itof, ftoi, i2tof, ftoi2
*
- * Random float8 ops:
- * dround, dtrunc, dsqrt, dcbrt, dpow, dexp, dlog1
- * Arithmetic operators:
- * float48pl, float48mi, float48mul, float48div
- * float84pl, float84mi, float84mul, float84div
- * Comparison operators:
- * float48eq, float48ne, float48lt, float48le, float48gt, float48ge
- * float84eq, float84ne, float84lt, float84le, float84gt, float84ge
+ * Random float8 ops:
+ * dround, dtrunc, dsqrt, dcbrt, dpow, dexp, dlog1
+ * Arithmetic operators:
+ * float48pl, float48mi, float48mul, float48div
+ * float84pl, float84mi, float84mul, float84div
+ * Comparison operators:
+ * float48eq, float48ne, float48lt, float48le, float48gt, float48ge
+ * float84eq, float84ne, float84lt, float84le, float84gt, float84ge
*
- * (You can do the arithmetic and comparison stuff using conversion
- * routines, but then you pay the overhead of converting...)
+ * (You can do the arithmetic and comparison stuff using conversion
+ * routines, but then you pay the overhead of converting...)
*
* XXX GLUESOME STUFF. FIX IT! -AY '94
*
- * Added some additional conversion routines and cleaned up
- * a bit of the existing code. Need to change the error checking
- * for calls to pow(), exp() since on some machines (my Linux box
- * included) these routines do not set errno. - tgl 97/05/10
+ * Added some additional conversion routines and cleaned up
+ * a bit of the existing code. Need to change the error checking
+ * for calls to pow(), exp() since on some machines (my Linux box
+ * included) these routines do not set errno. - tgl 97/05/10
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
-#include <float.h> /* faked on sunos4 */
+#include <float.h> /* faked on sunos4 */
#include <math.h>
#include "postgres.h"
#ifdef HAVE_LIMITS_H
-# include <limits.h>
+#include <limits.h>
#endif
#include "fmgr.h"
-#include "utils/builtins.h" /* for ftod() prototype */
+#include "utils/builtins.h" /* for ftod() prototype */
#include "utils/palloc.h"
@@ -71,65 +71,73 @@
#define SHRT_MIN (-32768)
#endif
-#define FORMAT 'g' /* use "g" output format as standard format */
+#define FORMAT 'g' /* use "g" output format as standard
+ * format */
/* not sure what the following should be, but better to make it over-sufficient */
-#define MAXFLOATWIDTH 64
+#define MAXFLOATWIDTH 64
#define MAXDOUBLEWIDTH 128
#if !(NeXT && NX_CURRENT_COMPILER_RELEASE > NX_COMPILER_RELEASE_3_2)
- /* NS3.3 has conflicting declarations of these in <math.h> */
+ /* NS3.3 has conflicting declarations of these in <math.h> */
#ifndef atof
extern double atof(const char *p);
+
#endif
#ifndef HAVE_CBRT
-# define cbrt my_cbrt
- static double cbrt(double x);
-#else
-# if !defined(nextstep)
- extern double cbrt(double x);
-# endif
-#endif
+#define cbrt my_cbrt
+static double cbrt(double x);
+
+#else
+#if !defined(nextstep)
+extern double cbrt(double x);
+
+#endif
+#endif
#ifndef HAVE_RINT
-# define rint my_rint
- static double rint(double x);
-#else
- extern double rint(double x);
-#endif
+#define rint my_rint
+static double rint(double x);
+
+#else
+extern double rint(double x);
+
+#endif
#ifndef HAVE_ISINF
-# define isinf my_isinf
- static int isinf(double x);
-#else
- extern int isinf(double x);
-#endif
+#define isinf my_isinf
+static int isinf(double x);
+
+#else
+extern int isinf(double x);
-#endif
+#endif
+
+#endif
/* ========== USER I/O ROUTINES ========== */
-
-
-#define FLOAT4_MAX FLT_MAX
-#define FLOAT4_MIN FLT_MIN
-#define FLOAT8_MAX DBL_MAX
-#define FLOAT8_MIN DBL_MIN
-
-/*
+
+
+#define FLOAT4_MAX FLT_MAX
+#define FLOAT4_MIN FLT_MIN
+#define FLOAT8_MAX DBL_MAX
+#define FLOAT8_MIN DBL_MIN
+
+/*
* if FLOAT8_MIN and FLOAT8_MAX are the limits of the range a
* double can store, then how are we ever going to wind up
* with something stored in a double that is outside those
- * limits? (and similarly for FLOAT4_{MIN,MAX}/float.)
+ * limits? (and similarly for FLOAT4_{MIN,MAX}/float.)
* doesn't make sense to me, and it causes a
* floating point exception on linuxalpha, so UNSAFE_FLOATS
* it is.
* (maybe someone wanted to allow for values other than DBL_MIN/
* DBL_MAX for FLOAT8_MIN/FLOAT8_MAX?)
- * --djm 12/12/96
- * according to Richard Henderson this is a known bug in gcc on
- * the Alpha. might as well leave the workaround in
+ * --djm 12/12/96
+ * according to Richard Henderson this is a known bug in gcc on
+ * the Alpha. might as well leave the workaround in
* until the distributions are updated.
- * --djm 12/16/96
+ * --djm 12/16/96
*/
#if defined(linuxalpha) && !defined(UNSAFE_FLOATS)
#define UNSAFE_FLOATS
@@ -138,1157 +146,1240 @@ extern double atof(const char *p);
/*
check to see if a float4 val is outside of
the FLOAT4_MIN, FLOAT4_MAX bounds.
-
+
raise an elog warning if it is
*/
-static void CheckFloat4Val(double val)
+static void
+CheckFloat4Val(double val)
{
- /* defining unsafe floats's will make float4 and float8 ops faster
- at the cost of safety, of course! */
+
+ /*
+ * defining unsafe floats's will make float4 and float8 ops faster at
+ * the cost of safety, of course!
+ */
#ifdef UNSAFE_FLOATS
- return;
+ return;
#else
- if (fabs(val) > FLOAT4_MAX)
- elog(WARN,"\tBad float4 input format -- overflow\n");
- if (val != 0.0 && fabs(val) < FLOAT4_MIN)
- elog(WARN,"\tBad float4 input format -- underflow\n");
- return;
-#endif /* UNSAFE_FLOATS */
+ if (fabs(val) > FLOAT4_MAX)
+ elog(WARN, "\tBad float4 input format -- overflow\n");
+ if (val != 0.0 && fabs(val) < FLOAT4_MIN)
+ elog(WARN, "\tBad float4 input format -- underflow\n");
+ return;
+#endif /* UNSAFE_FLOATS */
}
/*
check to see if a float8 val is outside of
the FLOAT8_MIN, FLOAT8_MAX bounds.
-
+
raise an elog warning if it is
*/
-void CheckFloat8Val(double val)
+void
+CheckFloat8Val(double val)
{
- /* defining unsafe floats's will make float4 and float8 ops faster
- at the cost of safety, of course! */
+
+ /*
+ * defining unsafe floats's will make float4 and float8 ops faster at
+ * the cost of safety, of course!
+ */
#ifdef UNSAFE_FLOATS
- return;
+ return;
#else
- if (fabs(val) > FLOAT8_MAX)
- elog(WARN,"\tBad float8 input format -- overflow\n");
- if (val != 0.0 && fabs(val) < FLOAT8_MIN)
- elog(WARN,"\tBad float8 input format -- underflow\n");
- return;
-#endif /* UNSAFE_FLOATS */
+ if (fabs(val) > FLOAT8_MAX)
+ elog(WARN, "\tBad float8 input format -- overflow\n");
+ if (val != 0.0 && fabs(val) < FLOAT8_MIN)
+ elog(WARN, "\tBad float8 input format -- underflow\n");
+ return;
+#endif /* UNSAFE_FLOATS */
}
/*
- * float4in - converts "num" to float
- * restricted syntax:
- * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
- * where <sp> is a space, digit is 0-9,
- * <exp> is "e" or "E" followed by an integer.
+ * float4in - converts "num" to float
+ * restricted syntax:
+ * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
+ * where <sp> is a space, digit is 0-9,
+ * <exp> is "e" or "E" followed by an integer.
*/
-float32 float4in(char *num)
-{
- float32 result = (float32) palloc(sizeof(float32data));
- double val;
- char* endptr;
-
- errno = 0;
- val = strtod(num,&endptr);
- if (*endptr != '\0' || errno == ERANGE)
- elog(WARN,"\tBad float4 input format\n");
-
- /* if we get here, we have a legal double, still need to check to see
- if it's a legal float */
-
- CheckFloat4Val(val);
-
- *result = val;
- return result;
+float32
+float4in(char *num)
+{
+ float32 result = (float32) palloc(sizeof(float32data));
+ double val;
+ char *endptr;
+
+ errno = 0;
+ val = strtod(num, &endptr);
+ if (*endptr != '\0' || errno == ERANGE)
+ elog(WARN, "\tBad float4 input format\n");
+
+ /*
+ * if we get here, we have a legal double, still need to check to see
+ * if it's a legal float
+ */
+
+ CheckFloat4Val(val);
+
+ *result = val;
+ return result;
}
/*
- * float4out - converts a float4 number to a string
- * using a standard output format
+ * float4out - converts a float4 number to a string
+ * using a standard output format
*/
-char *float4out(float32 num)
+char *
+float4out(float32 num)
{
- char *ascii = (char *)palloc(MAXFLOATWIDTH+1);
-
- if (!num)
- return strcpy(ascii, "(null)");
-
- sprintf(ascii, "%.*g", FLT_DIG, *num);
- return(ascii);
+ char *ascii = (char *) palloc(MAXFLOATWIDTH + 1);
+
+ if (!num)
+ return strcpy(ascii, "(null)");
+
+ sprintf(ascii, "%.*g", FLT_DIG, *num);
+ return (ascii);
}
/*
- * float8in - converts "num" to float8
- * restricted syntax:
- * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
- * where <sp> is a space, digit is 0-9,
- * <exp> is "e" or "E" followed by an integer.
+ * float8in - converts "num" to float8
+ * restricted syntax:
+ * {<sp>} [+|-] {digit} [.{digit}] [<exp>]
+ * where <sp> is a space, digit is 0-9,
+ * <exp> is "e" or "E" followed by an integer.
*/
-float64 float8in(char *num)
+float64
+float8in(char *num)
{
- float64 result = (float64) palloc(sizeof(float64data));
- double val;
- char* endptr;
-
- errno = 0;
- val = strtod(num,&endptr);
- if (*endptr != '\0' || errno == ERANGE)
- elog(WARN,"\tBad float8 input format\n");
-
- CheckFloat8Val(val);
- *result = val;
- return(result);
+ float64 result = (float64) palloc(sizeof(float64data));
+ double val;
+ char *endptr;
+
+ errno = 0;
+ val = strtod(num, &endptr);
+ if (*endptr != '\0' || errno == ERANGE)
+ elog(WARN, "\tBad float8 input format\n");
+
+ CheckFloat8Val(val);
+ *result = val;
+ return (result);
}
/*
- * float8out - converts float8 number to a string
- * using a standard output format
+ * float8out - converts float8 number to a string
+ * using a standard output format
*/
-char *float8out(float64 num)
+char *
+float8out(float64 num)
{
- char *ascii = (char *)palloc(MAXDOUBLEWIDTH+1);
-
- if (!num)
- return strcpy(ascii, "(null)");
+ char *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
+
+ if (!num)
+ return strcpy(ascii, "(null)");
- if (isnan(*num))
- return strcpy(ascii, "NaN");
- if (isinf(*num))
- return strcpy(ascii, "Infinity");
+ if (isnan(*num))
+ return strcpy(ascii, "NaN");
+ if (isinf(*num))
+ return strcpy(ascii, "Infinity");
- sprintf(ascii, "%.*g", DBL_DIG, *num);
- return(ascii);
+ sprintf(ascii, "%.*g", DBL_DIG, *num);
+ return (ascii);
}
/* ========== PUBLIC ROUTINES ========== */
/*
- * ======================
- * FLOAT4 BASE OPERATIONS
- * ======================
+ * ======================
+ * FLOAT4 BASE OPERATIONS
+ * ======================
*/
/*
- * float4abs - returns a pointer to |arg1| (absolute value)
+ * float4abs - returns a pointer to |arg1| (absolute value)
*/
-float32 float4abs(float32 arg1)
+float32
+float4abs(float32 arg1)
{
- float32 result;
- double val;
-
- if (!arg1)
- return (float32)NULL;
-
- val = fabs(*arg1);
+ float32 result;
+ double val;
- CheckFloat4Val(val);
+ if (!arg1)
+ return (float32) NULL;
- result = (float32) palloc(sizeof(float32data));
- *result = val;
- return(result);
+ val = fabs(*arg1);
+
+ CheckFloat4Val(val);
+
+ result = (float32) palloc(sizeof(float32data));
+ *result = val;
+ return (result);
}
/*
- * float4um - returns a pointer to -arg1 (unary minus)
+ * float4um - returns a pointer to -arg1 (unary minus)
*/
-float32 float4um(float32 arg1)
+float32
+float4um(float32 arg1)
{
- float32 result;
- double val;
-
- if (!arg1)
- return (float32)NULL;
-
- val = ((*arg1 != 0) ? -(*arg1): *arg1);
- CheckFloat4Val(val);
+ float32 result;
+ double val;
+
+ if (!arg1)
+ return (float32) NULL;
+
+ val = ((*arg1 != 0) ? -(*arg1) : *arg1);
+ CheckFloat4Val(val);
- result = (float32) palloc(sizeof(float32data));
- *result = val;
- return(result);
+ result = (float32) palloc(sizeof(float32data));
+ *result = val;
+ return (result);
}
-float32 float4larger(float32 arg1, float32 arg2)
+float32
+float4larger(float32 arg1, float32 arg2)
{
- float32 result;
-
- if (!arg1 || !arg2)
- return (float32)NULL;
-
- result = (float32) palloc(sizeof(float32data));
-
- *result = ((*arg1 > *arg2) ? *arg1 : *arg2);
- return result;
+ float32 result;
+
+ if (!arg1 || !arg2)
+ return (float32) NULL;
+
+ result = (float32) palloc(sizeof(float32data));
+
+ *result = ((*arg1 > *arg2) ? *arg1 : *arg2);
+ return result;
}
-float32 float4smaller(float32 arg1, float32 arg2)
+float32
+float4smaller(float32 arg1, float32 arg2)
{
- float32 result;
-
- if (!arg1 || !arg2)
- return (float32)NULL;
-
- result = (float32) palloc(sizeof(float32data));
-
- *result = ((*arg1 > *arg2) ? *arg2 : *arg1);
- return result;
+ float32 result;
+
+ if (!arg1 || !arg2)
+ return (float32) NULL;
+
+ result = (float32) palloc(sizeof(float32data));
+
+ *result = ((*arg1 > *arg2) ? *arg2 : *arg1);
+ return result;
}
/*
- * ======================
- * FLOAT8 BASE OPERATIONS
- * ======================
+ * ======================
+ * FLOAT8 BASE OPERATIONS
+ * ======================
*/
/*
- * float8abs - returns a pointer to |arg1| (absolute value)
+ * float8abs - returns a pointer to |arg1| (absolute value)
*/
-float64 float8abs(float64 arg1)
+float64
+float8abs(float64 arg1)
{
- float64 result;
- double val;
-
- if (!arg1)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- val = fabs(*arg1);
- CheckFloat8Val(val);
- *result = val;
- return(result);
+ float64 result;
+ double val;
+
+ if (!arg1)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ val = fabs(*arg1);
+ CheckFloat8Val(val);
+ *result = val;
+ return (result);
}
/*
- * float8um - returns a pointer to -arg1 (unary minus)
+ * float8um - returns a pointer to -arg1 (unary minus)
*/
-float64 float8um(float64 arg1)
+float64
+float8um(float64 arg1)
{
- float64 result;
- double val;
+ float64 result;
+ double val;
+
+ if (!arg1)
+ return (float64) NULL;
+
+ val = ((*arg1 != 0) ? -(*arg1) : *arg1);
- if (!arg1)
- return (float64)NULL;
-
- val = ((*arg1 != 0)? -(*arg1): *arg1);
-
- CheckFloat8Val(val);
- result = (float64) palloc(sizeof(float64data));
- *result = val;
- return(result);
+ CheckFloat8Val(val);
+ result = (float64) palloc(sizeof(float64data));
+ *result = val;
+ return (result);
}
-float64 float8larger(float64 arg1, float64 arg2)
+float64
+float8larger(float64 arg1, float64 arg2)
{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = ((*arg1 > *arg2) ? *arg1 : *arg2);
- return result;
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = ((*arg1 > *arg2) ? *arg1 : *arg2);
+ return result;
}
-float64 float8smaller(float64 arg1, float64 arg2)
+float64
+float8smaller(float64 arg1, float64 arg2)
{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = ((*arg1 > *arg2) ? *arg2 : *arg1);
- return result;
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = ((*arg1 > *arg2) ? *arg2 : *arg1);
+ return result;
}
/*
- * ====================
- * ARITHMETIC OPERATORS
- * ====================
+ * ====================
+ * ARITHMETIC OPERATORS
+ * ====================
*/
/*
- * float4pl - returns a pointer to arg1 + arg2
- * float4mi - returns a pointer to arg1 - arg2
- * float4mul - returns a pointer to arg1 * arg2
- * float4div - returns a pointer to arg1 / arg2
- * float4inc - returns a poniter to arg1 + 1.0
+ * float4pl - returns a pointer to arg1 + arg2
+ * float4mi - returns a pointer to arg1 - arg2
+ * float4mul - returns a pointer to arg1 * arg2
+ * float4div - returns a pointer to arg1 / arg2
+ * float4inc - returns a poniter to arg1 + 1.0
*/
-float32 float4pl(float32 arg1, float32 arg2)
+float32
+float4pl(float32 arg1, float32 arg2)
{
- float32 result;
- double val;
-
- if (!arg1 || !arg2)
- return (float32)NULL;
-
- val = *arg1 + *arg2;
- CheckFloat4Val(val);
+ float32 result;
+ double val;
+
+ if (!arg1 || !arg2)
+ return (float32) NULL;
- result = (float32) palloc(sizeof(float32data));
- *result = val;
+ val = *arg1 + *arg2;
+ CheckFloat4Val(val);
- return(result);
+ result = (float32) palloc(sizeof(float32data));
+ *result = val;
+
+ return (result);
}
-float32 float4mi(float32 arg1, float32 arg2)
+float32
+float4mi(float32 arg1, float32 arg2)
{
- float32 result;
- double val;
-
- if (!arg1 || !arg2)
- return (float32)NULL;
-
- val = *arg1 - *arg2;
+ float32 result;
+ double val;
+
+ if (!arg1 || !arg2)
+ return (float32) NULL;
+
+ val = *arg1 - *arg2;
- CheckFloat4Val(val);
- result = (float32) palloc(sizeof(float32data));
- *result = val;
- return(result);
+ CheckFloat4Val(val);
+ result = (float32) palloc(sizeof(float32data));
+ *result = val;
+ return (result);
}
-float32 float4mul(float32 arg1, float32 arg2)
+float32
+float4mul(float32 arg1, float32 arg2)
{
- float32 result;
- double val;
-
- if (!arg1 || !arg2)
- return (float32)NULL;
-
- val = *arg1 * *arg2;
+ float32 result;
+ double val;
- CheckFloat4Val(val);
- result = (float32) palloc(sizeof(float32data));
- *result = val;
- return(result);
+ if (!arg1 || !arg2)
+ return (float32) NULL;
+
+ val = *arg1 * *arg2;
+
+ CheckFloat4Val(val);
+ result = (float32) palloc(sizeof(float32data));
+ *result = val;
+ return (result);
}
-float32 float4div(float32 arg1, float32 arg2)
+float32
+float4div(float32 arg1, float32 arg2)
{
- float32 result;
- double val;
-
- if (!arg1 || !arg2)
- return (float32)NULL;
-
- if (*arg2 == 0.0)
- elog(WARN,"float4div: divide by 0.0 error");
+ float32 result;
+ double val;
+
+ if (!arg1 || !arg2)
+ return (float32) NULL;
+
+ if (*arg2 == 0.0)
+ elog(WARN, "float4div: divide by 0.0 error");
- val = *arg1 / *arg2;
-
- CheckFloat4Val(val);
- result = (float32) palloc(sizeof(float32data));
- *result = *arg1 / *arg2;
- return(result);
+ val = *arg1 / *arg2;
+
+ CheckFloat4Val(val);
+ result = (float32) palloc(sizeof(float32data));
+ *result = *arg1 / *arg2;
+ return (result);
}
-float32 float4inc(float32 arg1)
+float32
+float4inc(float32 arg1)
{
- double val;
+ double val;
+
+ if (!arg1)
+ return (float32) NULL;
- if (!arg1)
- return (float32)NULL;
-
- val = *arg1 + (float32data)1.0;
- CheckFloat4Val(val);
- *arg1 = val;
- return arg1;
+ val = *arg1 + (float32data) 1.0;
+ CheckFloat4Val(val);
+ *arg1 = val;
+ return arg1;
}
/*
- * float8pl - returns a pointer to arg1 + arg2
- * float8mi - returns a pointer to arg1 - arg2
- * float8mul - returns a pointer to arg1 * arg2
- * float8div - returns a pointer to arg1 / arg2
- * float8inc - returns a pointer to arg1 + 1.0
+ * float8pl - returns a pointer to arg1 + arg2
+ * float8mi - returns a pointer to arg1 - arg2
+ * float8mul - returns a pointer to arg1 * arg2
+ * float8div - returns a pointer to arg1 / arg2
+ * float8inc - returns a pointer to arg1 + 1.0
*/
-float64 float8pl(float64 arg1, float64 arg2)
-{
- float64 result;
- double val;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- val = *arg1 + *arg2;
- CheckFloat8Val(val);
- *result = val;
- return(result);
-}
-
-float64 float8mi(float64 arg1, float64 arg2)
-{
- float64 result;
- double val;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- val = *arg1 - *arg2;
- CheckFloat8Val(val);
- *result = val;
- return(result);
-}
-
-float64 float8mul(float64 arg1, float64 arg2)
-{
- float64 result;
- double val;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- val = *arg1 * *arg2;
- CheckFloat8Val(val);
- *result = val;
- return(result);
-}
-
-float64 float8div(float64 arg1, float64 arg2)
-{
- float64 result;
- double val;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- if (*arg2 == 0.0)
- elog(WARN,"float8div: divide by 0.0 error");
-
- val = *arg1 / *arg2;
- CheckFloat8Val(val);
- *result = val;
- return(result);
-}
-
-float64 float8inc(float64 arg1)
-{
- double val;
- if (!arg1)
- return (float64)NULL;
-
- val = *arg1 + (float64data)1.0;
- CheckFloat8Val(val);
- *arg1 = val;
- return(arg1);
+float64
+float8pl(float64 arg1, float64 arg2)
+{
+ float64 result;
+ double val;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ val = *arg1 + *arg2;
+ CheckFloat8Val(val);
+ *result = val;
+ return (result);
+}
+
+float64
+float8mi(float64 arg1, float64 arg2)
+{
+ float64 result;
+ double val;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ val = *arg1 - *arg2;
+ CheckFloat8Val(val);
+ *result = val;
+ return (result);
+}
+
+float64
+float8mul(float64 arg1, float64 arg2)
+{
+ float64 result;
+ double val;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ val = *arg1 * *arg2;
+ CheckFloat8Val(val);
+ *result = val;
+ return (result);
+}
+
+float64
+float8div(float64 arg1, float64 arg2)
+{
+ float64 result;
+ double val;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ if (*arg2 == 0.0)
+ elog(WARN, "float8div: divide by 0.0 error");
+
+ val = *arg1 / *arg2;
+ CheckFloat8Val(val);
+ *result = val;
+ return (result);
+}
+
+float64
+float8inc(float64 arg1)
+{
+ double val;
+
+ if (!arg1)
+ return (float64) NULL;
+
+ val = *arg1 + (float64data) 1.0;
+ CheckFloat8Val(val);
+ *arg1 = val;
+ return (arg1);
}
/*
- * ====================
- * COMPARISON OPERATORS
- * ====================
+ * ====================
+ * COMPARISON OPERATORS
+ * ====================
*/
/*
- * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
+ * float4{eq,ne,lt,le,gt,ge} - float4/float4 comparison operations
*/
-bool float4eq(float32 arg1, float32 arg2)
+bool
+float4eq(float32 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
+ if (!arg1 || !arg2)
+ return 0;
- return(*arg1 == *arg2);
+ return (*arg1 == *arg2);
}
-bool float4ne(float32 arg1, float32 arg2)
+bool
+float4ne(float32 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 != *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 != *arg2);
}
-bool float4lt(float32 arg1, float32 arg2)
+bool
+float4lt(float32 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 < *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 < *arg2);
}
-bool float4le(float32 arg1, float32 arg2)
+bool
+float4le(float32 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 <= *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 <= *arg2);
}
-bool float4gt(float32 arg1, float32 arg2)
+bool
+float4gt(float32 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 > *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 > *arg2);
}
-bool float4ge(float32 arg1, float32 arg2)
+bool
+float4ge(float32 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 >= *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 >= *arg2);
}
/*
- * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
+ * float8{eq,ne,lt,le,gt,ge} - float8/float8 comparison operations
*/
-bool float8eq(float64 arg1, float64 arg2)
+bool
+float8eq(float64 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 == *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 == *arg2);
}
-bool float8ne(float64 arg1, float64 arg2)
+bool
+float8ne(float64 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 != *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 != *arg2);
}
-bool float8lt(float64 arg1, float64 arg2)
+bool
+float8lt(float64 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 < *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 < *arg2);
}
-bool float8le(float64 arg1, float64 arg2)
+bool
+float8le(float64 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 <= *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 <= *arg2);
}
-bool float8gt(float64 arg1, float64 arg2)
+bool
+float8gt(float64 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 > *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 > *arg2);
}
-bool float8ge(float64 arg1, float64 arg2)
+bool
+float8ge(float64 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 >= *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 >= *arg2);
}
/*
- * ===================
- * CONVERSION ROUTINES
- * ===================
+ * ===================
+ * CONVERSION ROUTINES
+ * ===================
*/
/*
- * ftod - converts a float4 number to a float8 number
+ * ftod - converts a float4 number to a float8 number
*/
-float64 ftod(float32 num)
+float64
+ftod(float32 num)
{
- float64 result;
-
- if (!num)
- return (float64)NULL;
+ float64 result;
+
+ if (!num)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
- result = (float64) palloc(sizeof(float64data));
-
- *result = *num;
- return(result);
+ *result = *num;
+ return (result);
}
/*
- * dtof - converts a float8 number to a float4 number
+ * dtof - converts a float8 number to a float4 number
*/
-float32 dtof(float64 num)
+float32
+dtof(float64 num)
{
- float32 result;
-
- if (!num)
- return (float32)NULL;
+ float32 result;
- CheckFloat4Val(*num);
+ if (!num)
+ return (float32) NULL;
- result = (float32) palloc(sizeof(float32data));
+ CheckFloat4Val(*num);
- *result = *num;
- return(result);
+ result = (float32) palloc(sizeof(float32data));
+
+ *result = *num;
+ return (result);
}
/*
- * dtoi4 - converts a float8 number to an int4 number
+ * dtoi4 - converts a float8 number to an int4 number
*/
-int32 dtoi4(float64 num)
+int32
+dtoi4(float64 num)
{
- int32 result;
-
- if (!num)
- elog(WARN,"dtoi4: unable to convert null",NULL);
+ int32 result;
+
+ if (!num)
+ elog(WARN, "dtoi4: unable to convert null", NULL);
- if ((*num < INT_MIN) || (*num > INT_MAX))
- elog(WARN,"dtoi4: integer out of range",NULL);
+ if ((*num < INT_MIN) || (*num > INT_MAX))
+ elog(WARN, "dtoi4: integer out of range", NULL);
- result = rint(*num);
- return(result);
+ result = rint(*num);
+ return (result);
}
/*
- * dtoi2 - converts a float8 number to an int2 number
+ * dtoi2 - converts a float8 number to an int2 number
*/
-int16 dtoi2(float64 num)
+int16
+dtoi2(float64 num)
{
- int16 result;
-
- if (!num)
- elog(WARN,"dtoi2: unable to convert null",NULL);
+ int16 result;
+
+ if (!num)
+ elog(WARN, "dtoi2: unable to convert null", NULL);
- if ((*num < SHRT_MIN) || (*num > SHRT_MAX))
- elog(WARN,"dtoi2: integer out of range",NULL);
+ if ((*num < SHRT_MIN) || (*num > SHRT_MAX))
+ elog(WARN, "dtoi2: integer out of range", NULL);
- result = rint(*num);
- return(result);
+ result = rint(*num);
+ return (result);
}
/*
- * i4tod - converts an int4 number to a float8 number
+ * i4tod - converts an int4 number to a float8 number
*/
-float64 i4tod(int32 num)
+float64
+i4tod(int32 num)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = num;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = num;
+ return (result);
}
/*
- * i2tod - converts an int2 number to a float8 number
+ * i2tod - converts an int2 number to a float8 number
*/
-float64 i2tod(int16 num)
+float64
+i2tod(int16 num)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = num;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = num;
+ return (result);
}
/*
- * ftoi4 - converts a float8 number to an int4 number
+ * ftoi4 - converts a float8 number to an int4 number
*/
-int32 ftoi4(float32 num)
+int32
+ftoi4(float32 num)
{
- int32 result;
-
- if (!num)
- elog(WARN,"ftoi4: unable to convert null",NULL);
+ int32 result;
- if ((*num < INT_MIN) || (*num > INT_MAX))
- elog(WARN,"ftoi4: integer out of range",NULL);
+ if (!num)
+ elog(WARN, "ftoi4: unable to convert null", NULL);
- result = rint(*num);
- return(result);
+ if ((*num < INT_MIN) || (*num > INT_MAX))
+ elog(WARN, "ftoi4: integer out of range", NULL);
+
+ result = rint(*num);
+ return (result);
}
/*
- * ftoi2 - converts a float8 number to an int2 number
+ * ftoi2 - converts a float8 number to an int2 number
*/
-int16 ftoi2(float32 num)
+int16
+ftoi2(float32 num)
{
- int16 result;
-
- if (!num)
- elog(WARN,"ftoi2: unable to convert null",NULL);
+ int16 result;
+
+ if (!num)
+ elog(WARN, "ftoi2: unable to convert null", NULL);
- if ((*num < SHRT_MIN) || (*num > SHRT_MAX))
- elog(WARN,"ftoi2: integer out of range",NULL);
+ if ((*num < SHRT_MIN) || (*num > SHRT_MAX))
+ elog(WARN, "ftoi2: integer out of range", NULL);
- result = rint(*num);
- return(result);
+ result = rint(*num);
+ return (result);
}
/*
- * i4tof - converts an int4 number to a float8 number
+ * i4tof - converts an int4 number to a float8 number
*/
-float32 i4tof(int32 num)
+float32
+i4tof(int32 num)
{
- float32 result;
-
- result = (float32) palloc(sizeof(float32data));
-
- *result = num;
- return(result);
+ float32 result;
+
+ result = (float32) palloc(sizeof(float32data));
+
+ *result = num;
+ return (result);
}
/*
- * i2tof - converts an int2 number to a float8 number
+ * i2tof - converts an int2 number to a float8 number
*/
-float32 i2tof(int16 num)
+float32
+i2tof(int16 num)
{
- float32 result;
-
- result = (float32) palloc(sizeof(float32data));
-
- *result = num;
- return(result);
+ float32 result;
+
+ result = (float32) palloc(sizeof(float32data));
+
+ *result = num;
+ return (result);
}
/*
- * =======================
- * RANDOM FLOAT8 OPERATORS
- * =======================
+ * =======================
+ * RANDOM FLOAT8 OPERATORS
+ * =======================
*/
/*
- * dround - returns a pointer to ROUND(arg1)
+ * dround - returns a pointer to ROUND(arg1)
*/
-float64 dround(float64 arg1)
+float64
+dround(float64 arg1)
{
- float64 result;
- double tmp;
-
- if (!arg1)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- tmp = *arg1;
- *result = (float64data) rint(tmp);
- return(result);
+ float64 result;
+ double tmp;
+
+ if (!arg1)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ tmp = *arg1;
+ *result = (float64data) rint(tmp);
+ return (result);
}
/*
- * dtrunc - returns a pointer to truncation of arg1,
- * arg1 >= 0 ... the greatest integer as float8 less
- * than or equal to arg1
- * arg1 < 0 ... the greatest integer as float8 greater
- * than or equal to arg1
+ * dtrunc - returns a pointer to truncation of arg1,
+ * arg1 >= 0 ... the greatest integer as float8 less
+ * than or equal to arg1
+ * arg1 < 0 ... the greatest integer as float8 greater
+ * than or equal to arg1
*/
-float64 dtrunc(float64 arg1)
-{
- float64 result;
- double tmp;
-
- if (!arg1)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- tmp = *arg1;
- if (*arg1 >= 0)
- *result = (float64data) floor(tmp);
- else
- *result = (float64data) -(floor(-tmp));
- return(result);
-}
-
-
-/*
- * dsqrt - returns a pointer to square root of arg1
+float64
+dtrunc(float64 arg1)
+{
+ float64 result;
+ double tmp;
+
+ if (!arg1)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ tmp = *arg1;
+ if (*arg1 >= 0)
+ *result = (float64data) floor(tmp);
+ else
+ *result = (float64data) - (floor(-tmp));
+ return (result);
+}
+
+
+/*
+ * dsqrt - returns a pointer to square root of arg1
*/
-float64 dsqrt(float64 arg1)
+float64
+dsqrt(float64 arg1)
{
- float64 result;
- double tmp;
-
- if (!arg1)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- tmp = *arg1;
- *result = (float64data) sqrt(tmp);
- return (result);
+ float64 result;
+ double tmp;
+
+ if (!arg1)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ tmp = *arg1;
+ *result = (float64data) sqrt(tmp);
+ return (result);
}
/*
- * dcbrt - returns a pointer to cube root of arg1
+ * dcbrt - returns a pointer to cube root of arg1
*/
-float64 dcbrt(float64 arg1)
+float64
+dcbrt(float64 arg1)
{
- float64 result;
- double tmp;
-
- if (!arg1)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- tmp = *arg1;
- *result = (float64data) cbrt(tmp);
- return(result);
+ float64 result;
+ double tmp;
+
+ if (!arg1)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ tmp = *arg1;
+ *result = (float64data) cbrt(tmp);
+ return (result);
}
/*
- * dpow - returns a pointer to pow(arg1,arg2)
+ * dpow - returns a pointer to pow(arg1,arg2)
*/
-float64 dpow(float64 arg1, float64 arg2)
-{
- float64 result;
- double tmp1, tmp2;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- tmp1 = *arg1;
- tmp2 = *arg2;
+float64
+dpow(float64 arg1, float64 arg2)
+{
+ float64 result;
+ double tmp1,
+ tmp2;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ tmp1 = *arg1;
+ tmp2 = *arg2;
#ifndef finite
- errno = 0;
+ errno = 0;
#endif
- *result = (float64data) pow(tmp1, tmp2);
+ *result = (float64data) pow(tmp1, tmp2);
#ifndef finite
- if (errno == ERANGE)
+ if (errno == ERANGE)
#else
- if (!finite(*result))
+ if (!finite(*result))
#endif
- elog(WARN, "pow() returned a floating point out of the range\n");
+ elog(WARN, "pow() returned a floating point out of the range\n");
- CheckFloat8Val(*result);
- return(result);
+ CheckFloat8Val(*result);
+ return (result);
}
/*
- * dexp - returns a pointer to the exponential function of arg1
+ * dexp - returns a pointer to the exponential function of arg1
*/
-float64 dexp(float64 arg1)
-{
- float64 result;
- double tmp;
-
- if (!arg1)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- tmp = *arg1;
+float64
+dexp(float64 arg1)
+{
+ float64 result;
+ double tmp;
+
+ if (!arg1)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ tmp = *arg1;
#ifndef finite
- errno = 0;
+ errno = 0;
#endif
- *result = (float64data) exp(tmp);
+ *result = (float64data) exp(tmp);
#ifndef finite
- if (errno == ERANGE)
+ if (errno == ERANGE)
#else
- if (!finite(*result))
+ if (!finite(*result))
#endif
- elog(WARN, "exp() returned a floating point out of range\n");
+ elog(WARN, "exp() returned a floating point out of range\n");
- CheckFloat8Val(*result);
- return(result);
+ CheckFloat8Val(*result);
+ return (result);
}
/*
- * dlog1 - returns a pointer to the natural logarithm of arg1
- * ("dlog" is already a logging routine...)
+ * dlog1 - returns a pointer to the natural logarithm of arg1
+ * ("dlog" is already a logging routine...)
*/
-float64 dlog1(float64 arg1)
+float64
+dlog1(float64 arg1)
{
- float64 result;
- double tmp;
-
- if (!arg1)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- tmp = *arg1;
- if (tmp == 0.0)
- elog(WARN, "can't take log of 0!");
- if (tmp < 0)
- elog(WARN, "can't take log of a negative number");
- *result = (float64data) log(tmp);
+ float64 result;
+ double tmp;
+
+ if (!arg1)
+ return (float64) NULL;
- CheckFloat8Val(*result);
- return(result);
+ result = (float64) palloc(sizeof(float64data));
+
+ tmp = *arg1;
+ if (tmp == 0.0)
+ elog(WARN, "can't take log of 0!");
+ if (tmp < 0)
+ elog(WARN, "can't take log of a negative number");
+ *result = (float64data) log(tmp);
+
+ CheckFloat8Val(*result);
+ return (result);
}
/*
- * ====================
- * ARITHMETIC OPERATORS
- * ====================
+ * ====================
+ * ARITHMETIC OPERATORS
+ * ====================
*/
/*
- * float48pl - returns a pointer to arg1 + arg2
- * float48mi - returns a pointer to arg1 - arg2
- * float48mul - returns a pointer to arg1 * arg2
- * float48div - returns a pointer to arg1 / arg2
+ * float48pl - returns a pointer to arg1 + arg2
+ * float48mi - returns a pointer to arg1 - arg2
+ * float48mul - returns a pointer to arg1 * arg2
+ * float48div - returns a pointer to arg1 / arg2
*/
-float64 float48pl(float32 arg1, float64 arg2)
-{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = *arg1 + *arg2;
- CheckFloat8Val(*result);
- return(result);
-}
-
-float64 float48mi(float32 arg1, float64 arg2)
-{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = *arg1 - *arg2;
- CheckFloat8Val(*result);
- return(result);
-}
-
-float64 float48mul(float32 arg1, float64 arg2)
-{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = *arg1 * *arg2;
- CheckFloat8Val(*result);
- return(result);
-}
-
-float64 float48div(float32 arg1, float64 arg2)
-{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- if (*arg2 == 0.0)
- elog(WARN, "float48div: divide by 0.0 error!");
-
- *result = *arg1 / *arg2;
- CheckFloat8Val(*result);
- return(result);
+float64
+float48pl(float32 arg1, float64 arg2)
+{
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = *arg1 + *arg2;
+ CheckFloat8Val(*result);
+ return (result);
+}
+
+float64
+float48mi(float32 arg1, float64 arg2)
+{
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = *arg1 - *arg2;
+ CheckFloat8Val(*result);
+ return (result);
+}
+
+float64
+float48mul(float32 arg1, float64 arg2)
+{
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = *arg1 * *arg2;
+ CheckFloat8Val(*result);
+ return (result);
+}
+
+float64
+float48div(float32 arg1, float64 arg2)
+{
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ if (*arg2 == 0.0)
+ elog(WARN, "float48div: divide by 0.0 error!");
+
+ *result = *arg1 / *arg2;
+ CheckFloat8Val(*result);
+ return (result);
}
/*
- * float84pl - returns a pointer to arg1 + arg2
- * float84mi - returns a pointer to arg1 - arg2
- * float84mul - returns a pointer to arg1 * arg2
- * float84div - returns a pointer to arg1 / arg2
+ * float84pl - returns a pointer to arg1 + arg2
+ * float84mi - returns a pointer to arg1 - arg2
+ * float84mul - returns a pointer to arg1 * arg2
+ * float84div - returns a pointer to arg1 / arg2
*/
-float64 float84pl(float64 arg1, float32 arg2)
-{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = *arg1 + *arg2;
- CheckFloat8Val(*result);
- return(result);
-}
-
-float64 float84mi(float64 arg1, float32 arg2)
-{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = *arg1 - *arg2;
- CheckFloat8Val(*result);
- return(result);
-}
-
-float64 float84mul(float64 arg1, float32 arg2)
-{
-
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- *result = *arg1 * *arg2;
- CheckFloat8Val(*result);
- return(result);
-}
-
-float64 float84div(float64 arg1, float32 arg2)
-{
- float64 result;
-
- if (!arg1 || !arg2)
- return (float64)NULL;
-
- result = (float64) palloc(sizeof(float64data));
-
- if (*arg2 == 0.0)
- elog(WARN, "float48div: divide by 0.0 error!");
-
- *result = *arg1 / *arg2;
- CheckFloat8Val(*result);
- return(result);
+float64
+float84pl(float64 arg1, float32 arg2)
+{
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = *arg1 + *arg2;
+ CheckFloat8Val(*result);
+ return (result);
+}
+
+float64
+float84mi(float64 arg1, float32 arg2)
+{
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = *arg1 - *arg2;
+ CheckFloat8Val(*result);
+ return (result);
+}
+
+float64
+float84mul(float64 arg1, float32 arg2)
+{
+
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ *result = *arg1 * *arg2;
+ CheckFloat8Val(*result);
+ return (result);
+}
+
+float64
+float84div(float64 arg1, float32 arg2)
+{
+ float64 result;
+
+ if (!arg1 || !arg2)
+ return (float64) NULL;
+
+ result = (float64) palloc(sizeof(float64data));
+
+ if (*arg2 == 0.0)
+ elog(WARN, "float48div: divide by 0.0 error!");
+
+ *result = *arg1 / *arg2;
+ CheckFloat8Val(*result);
+ return (result);
}
/*
- * ====================
- * COMPARISON OPERATORS
- * ====================
+ * ====================
+ * COMPARISON OPERATORS
+ * ====================
*/
/*
- * float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
+ * float48{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
*/
-bool float48eq(float32 arg1, float64 arg2)
+bool
+float48eq(float32 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 == (float)*arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 == (float) *arg2);
}
-bool float48ne(float32 arg1, float64 arg2)
+bool
+float48ne(float32 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 != (float)*arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 != (float) *arg2);
}
-bool float48lt(float32 arg1, float64 arg2)
+bool
+float48lt(float32 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 < (float)*arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 < (float) *arg2);
}
-bool float48le(float32 arg1, float64 arg2)
+bool
+float48le(float32 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 <= (float)*arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 <= (float) *arg2);
}
-bool float48gt(float32 arg1, float64 arg2)
+bool
+float48gt(float32 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 > (float)*arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 > (float) *arg2);
}
-bool float48ge(float32 arg1, float64 arg2)
+bool
+float48ge(float32 arg1, float64 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return(*arg1 >= (float)*arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return (*arg1 >= (float) *arg2);
}
/*
- * float84{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
+ * float84{eq,ne,lt,le,gt,ge} - float4/float8 comparison operations
*/
-bool float84eq(float64 arg1, float32 arg2)
+bool
+float84eq(float64 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return((float)*arg1 == *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return ((float) *arg1 == *arg2);
}
-bool float84ne(float64 arg1, float32 arg2)
+bool
+float84ne(float64 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return((float)*arg1 != *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return ((float) *arg1 != *arg2);
}
-bool float84lt(float64 arg1, float32 arg2)
+bool
+float84lt(float64 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return((float)*arg1 < *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return ((float) *arg1 < *arg2);
}
-bool float84le(float64 arg1, float32 arg2)
+bool
+float84le(float64 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return((float)*arg1 <= *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return ((float) *arg1 <= *arg2);
}
-bool float84gt(float64 arg1, float32 arg2)
+bool
+float84gt(float64 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return((float)*arg1 > *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return ((float) *arg1 > *arg2);
}
-bool float84ge(float64 arg1, float32 arg2)
+bool
+float84ge(float64 arg1, float32 arg2)
{
- if (!arg1 || !arg2)
- return 0;
-
- return((float)*arg1 >= *arg2);
+ if (!arg1 || !arg2)
+ return 0;
+
+ return ((float) *arg1 >= *arg2);
}
/* ========== PRIVATE ROUTINES ========== */
@@ -1304,7 +1395,7 @@ bool float84ge(float64 arg1, float32 arg2)
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
+ * software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
@@ -1314,89 +1405,115 @@ bool float84ge(float64 arg1, float32 arg2)
* Return x rounded to integral value according to the prevailing
* rounding mode.
* Method:
- * Using floating addition.
+ * Using floating addition.
* Exception:
- * Inexact flag raised if x not equal to rint(x).
+ * Inexact flag raised if x not equal to rint(x).
*/
#ifdef __STDC__
static const double
#else
- static double
+static double
#endif
- one = 1.0,
- TWO52[2]={
+ one = 1.0,
+ TWO52[2] = {
4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
- -4.50359962737049600000e+15, /* 0xC3300000, 0x00000000 */
- };
+ -4.50359962737049600000e+15,/* 0xC3300000, 0x00000000 */
+};
#ifdef __STDC__
-static double rint(double x)
+static double
+rint(double x)
#else
- static double rint(x)
- double x;
+static double
+rint(x)
+double x;
+
#endif
{
- int i0,n0,j0,sx;
- unsigned i,i1;
- double w,t;
- n0 = (*((int *)&one)>>29)^1;
- i0 = *(n0+(int*)&x);
- sx = (i0>>31)&1;
- i1 = *(1-n0+(int*)&x);
- j0 = ((i0>>20)&0x7ff)-0x3ff;
- if(j0<20) {
- if(j0<0) {
- if(((i0&0x7fffffff)|i1)==0) return x;
- i1 |= (i0&0x0fffff);
- i0 &= 0xfffe0000;
- i0 |= ((i1|-i1)>>12)&0x80000;
- *(n0+(int*)&x)=i0;
- w = TWO52[sx]+x;
- t = w-TWO52[sx];
- i0 = *(n0+(int*)&t);
- *(n0+(int*)&t) = (i0&0x7fffffff)|(sx<<31);
- return t;
- } else {
- i = (0x000fffff)>>j0;
- if(((i0&i)|i1)==0) return x; /* x is integral */
- i>>=1;
- if(((i0&i)|i1)!=0) {
- if(j0==19) i1 = 0x40000000; else
- i0 = (i0&(~i))|((0x20000)>>j0);
- }
+ int i0,
+ n0,
+ j0,
+ sx;
+ unsigned i,
+ i1;
+ double w,
+ t;
+
+ n0 = (*((int *) &one) >> 29) ^ 1;
+ i0 = *(n0 + (int *) &x);
+ sx = (i0 >> 31) & 1;
+ i1 = *(1 - n0 + (int *) &x);
+ j0 = ((i0 >> 20) & 0x7ff) - 0x3ff;
+ if (j0 < 20)
+ {
+ if (j0 < 0)
+ {
+ if (((i0 & 0x7fffffff) | i1) == 0)
+ return x;
+ i1 |= (i0 & 0x0fffff);
+ i0 &= 0xfffe0000;
+ i0 |= ((i1 | -i1) >> 12) & 0x80000;
+ *(n0 + (int *) &x) = i0;
+ w = TWO52[sx] + x;
+ t = w - TWO52[sx];
+ i0 = *(n0 + (int *) &t);
+ *(n0 + (int *) &t) = (i0 & 0x7fffffff) | (sx << 31);
+ return t;
+ }
+ else
+ {
+ i = (0x000fffff) >> j0;
+ if (((i0 & i) | i1) == 0)
+ return x; /* x is integral */
+ i >>= 1;
+ if (((i0 & i) | i1) != 0)
+ {
+ if (j0 == 19)
+ i1 = 0x40000000;
+ else
+ i0 = (i0 & (~i)) | ((0x20000) >> j0);
+ }
+ }
+ }
+ else if (j0 > 51)
+ {
+ if (j0 == 0x400)
+ return x + x; /* inf or NaN */
+ else
+ return x; /* x is integral */
+ }
+ else
+ {
+ i = ((unsigned) (0xffffffff)) >> (j0 - 20);
+ if ((i1 & i) == 0)
+ return x; /* x is integral */
+ i >>= 1;
+ if ((i1 & i) != 0)
+ i1 = (i1 & (~i)) | ((0x40000000) >> (j0 - 20));
}
- } else if (j0>51) {
- if(j0==0x400) return x+x; /* inf or NaN */
- else return x; /* x is integral */
- } else {
- i = ((unsigned)(0xffffffff))>>(j0-20);
- if((i1&i)==0) return x; /* x is integral */
- i>>=1;
- if((i1&i)!=0) i1 = (i1&(~i))|((0x40000000)>>(j0-20));
- }
- *(n0+(int*)&x) = i0;
- *(1-n0+(int*)&x) = i1;
- w = TWO52[sx]+x;
- return w-TWO52[sx];
-}
-
-#endif /* !HAVE_RINT */
+ *(n0 + (int *) &x) = i0;
+ *(1 - n0 + (int *) &x) = i1;
+ w = TWO52[sx] + x;
+ return w - TWO52[sx];
+}
+
+#endif /* !HAVE_RINT */
#ifndef HAVE_CBRT
static
- double
- cbrt(x)
-double x;
+double
+cbrt(x)
+double x;
{
- int isneg = (x < 0.0);
- double tmpres = pow(fabs(x), (double) 1.0 / (double) 3.0);
-
- return(isneg ? -tmpres : tmpres);
+ int isneg = (x < 0.0);
+ double tmpres = pow(fabs(x), (double) 1.0 / (double) 3.0);
+
+ return (isneg ? -tmpres : tmpres);
}
-#endif /* !HAVE_CBRT */
+#endif /* !HAVE_CBRT */
#ifndef HAVE_ISINF
@@ -1404,89 +1521,104 @@ double x;
#ifdef CLASS_CONFLICT
/* we want the math symbol */
#undef class
-#endif /* CLASS_CONFICT */
+#endif /* CLASS_CONFICT */
-static int isinf(x)
- double x;
+static int
+isinf(x)
+double x;
{
- int fpclass = class(x);
- if (fpclass == FP_PLUS_INF)
- return(1);
- if (fpclass == FP_MINUS_INF)
- return(-1);
- return(0);
+ int fpclass = class(x);
+
+ if (fpclass == FP_PLUS_INF)
+ return (1);
+ if (fpclass == FP_MINUS_INF)
+ return (-1);
+ return (0);
}
-#endif /* aix */
+
+#endif /* aix */
#if defined(ultrix4)
#include <fp_class.h>
-static int isinf(x)
- double x;
+static int
+isinf(x)
+double x;
{
- int fpclass = fp_class_d(x);
- if (fpclass == FP_POS_INF)
- return(1);
- if (fpclass == FP_NEG_INF)
- return(-1);
- return(0);
+ int fpclass = fp_class_d(x);
+
+ if (fpclass == FP_POS_INF)
+ return (1);
+ if (fpclass == FP_NEG_INF)
+ return (-1);
+ return (0);
}
-#endif /* ultrix4 */
+
+#endif /* ultrix4 */
#if defined(alpha)
#include <fp_class.h>
-static int isinf(x)
- double x;
+static int
+isinf(x)
+double x;
{
- int fpclass = fp_class(x);
- if (fpclass == FP_POS_INF)
- return(1);
- if (fpclass == FP_NEG_INF)
- return(-1);
- return(0);
+ int fpclass = fp_class(x);
+
+ if (fpclass == FP_POS_INF)
+ return (1);
+ if (fpclass == FP_NEG_INF)
+ return (-1);
+ return (0);
}
-#endif /* alpha */
+
+#endif /* alpha */
#if defined(sparc_solaris) || defined(i386_solaris) || defined(svr4) || \
- defined(sco)
+ defined(sco)
#include <ieeefp.h>
static int
- isinf(d)
-double d;
-{
- fpclass_t type = fpclass(d);
- switch (type) {
- case FP_SNAN:
- case FP_QNAN:
- case FP_NINF:
- case FP_PINF:
- return (1);
- default:
- break;
- }
-
- return (0);
-}
-#endif /* sparc_solaris */
+isinf(d)
+double d;
+{
+ fpclass_t type = fpclass(d);
+
+ switch (type)
+ {
+ case FP_SNAN:
+ case FP_QNAN:
+ case FP_NINF:
+ case FP_PINF:
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+#endif /* sparc_solaris */
#if defined(irix5)
#include <ieeefp.h>
static int
- isinf(d)
-double d;
-{
- fpclass_t type = fpclass(d);
- switch (type) {
- case FP_SNAN:
- case FP_QNAN:
- case FP_NINF:
- case FP_PINF:
- return (1);
- default:
- break;
- }
-
- return (0);
-}
-#endif /* irix5 */
-
-#endif /* !HAVE_ISINF */
+isinf(d)
+double d;
+{
+ fpclass_t type = fpclass(d);
+
+ switch (type)
+ {
+ case FP_SNAN:
+ case FP_QNAN:
+ case FP_NINF:
+ case FP_PINF:
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+#endif /* irix5 */
+
+#endif /* !HAVE_ISINF */
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index d805ba7a220..71b478788ef 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* geo_ops.c--
- * 2D geometric operations
+ * 2D geometric operations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.19 1997/09/05 20:20:56 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_ops.c,v 1.20 1997/09/07 04:50:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <math.h>
#include <limits.h>
#include <float.h>
-#include <stdio.h> /* for sprintf proto, etc. */
-#include <stdlib.h> /* for strtod, etc. */
+#include <stdio.h> /* for sprintf proto, etc. */
+#include <stdlib.h> /* for strtod, etc. */
#include <string.h>
#include <ctype.h>
@@ -28,38 +28,38 @@
#define PI 3.1415926536
#endif
-static int point_inside( Point *p, int npts, Point plist[]);
-static int lseg_crossing( double x, double y, double px, double py);
-static BOX *box_construct(double x1, double x2, double y1, double y2);
-static BOX *box_copy(BOX *box);
-static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2);
-static double box_ht(BOX *box);
-static double box_wd(BOX *box);
-static double circle_ar(CIRCLE *circle);
-static CIRCLE *circle_copy(CIRCLE *circle);
-static LINE *line_construct_pm(Point *pt, double m);
-static bool line_horizontal(LINE *line);
-static Point *line_interpt(LINE *l1, LINE *l2);
-static bool line_intersect(LINE *l1, LINE *l2);
-static bool line_parallel(LINE *l1, LINE *l2);
-static bool line_vertical(LINE *line);
-static double lseg_dt(LSEG *l1, LSEG *l2);
-static void make_bound_box(POLYGON *poly);
-static PATH *path_copy(PATH *path);
-static bool plist_same(int npts, Point p1[], Point p2[]);
-static Point *point_construct(double x, double y);
-static Point *point_copy(Point *pt);
-static int single_decode(char *str, float8 *x, char **ss);
-static int single_encode(float8 x, char *str);
-static int pair_decode(char *str, float8 *x, float8 *y, char **s);
-static int pair_encode(float8 x, float8 y, char *str);
-static int pair_count(char *s, char delim);
-static int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p);
-static char *path_encode( bool closed, int npts, Point *pt);
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
-static double box_ar(BOX *box);
-static Point *interpt_sl(LSEG *lseg, LINE *line);
-static LINE *line_construct_pp(Point *pt1, Point *pt2);
+static int point_inside(Point * p, int npts, Point plist[]);
+static int lseg_crossing(double x, double y, double px, double py);
+static BOX *box_construct(double x1, double x2, double y1, double y2);
+static BOX *box_copy(BOX * box);
+static BOX *box_fill(BOX * result, double x1, double x2, double y1, double y2);
+static double box_ht(BOX * box);
+static double box_wd(BOX * box);
+static double circle_ar(CIRCLE * circle);
+static CIRCLE *circle_copy(CIRCLE * circle);
+static LINE *line_construct_pm(Point * pt, double m);
+static bool line_horizontal(LINE * line);
+static Point *line_interpt(LINE * l1, LINE * l2);
+static bool line_intersect(LINE * l1, LINE * l2);
+static bool line_parallel(LINE * l1, LINE * l2);
+static bool line_vertical(LINE * line);
+static double lseg_dt(LSEG * l1, LSEG * l2);
+static void make_bound_box(POLYGON * poly);
+static PATH *path_copy(PATH * path);
+static bool plist_same(int npts, Point p1[], Point p2[]);
+static Point *point_construct(double x, double y);
+static Point *point_copy(Point * pt);
+static int single_decode(char *str, float8 * x, char **ss);
+static int single_encode(float8 x, char *str);
+static int pair_decode(char *str, float8 * x, float8 * y, char **s);
+static int pair_encode(float8 x, float8 y, char *str);
+static int pair_count(char *s, char delim);
+static int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point * p);
+static char *path_encode(bool closed, int npts, Point * pt);
+static void statlseg_construct(LSEG * lseg, Point * pt1, Point * pt2);
+static double box_ar(BOX * box);
+static Point *interpt_sl(LSEG * lseg, LINE * line);
+static LINE *line_construct_pp(Point * pt1, Point * pt2);
/*
@@ -68,203 +68,248 @@ static LINE *line_construct_pp(Point *pt1, Point *pt2);
* LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
*/
-#define LDELIM '('
-#define RDELIM ')'
-#define DELIM ','
-#define LDELIM_EP '['
-#define RDELIM_EP ']'
-#define LDELIM_C '<'
-#define RDELIM_C '>'
+#define LDELIM '('
+#define RDELIM ')'
+#define DELIM ','
+#define LDELIM_EP '['
+#define RDELIM_EP ']'
+#define LDELIM_C '<'
+#define RDELIM_C '>'
/* Maximum number of output digits printed */
#define P_MAXDIG DBL_DIG
#define P_MAXLEN (2*(P_MAXDIG+7)+1)
-static int digits8 = P_MAXDIG;
+static int digits8 = P_MAXDIG;
/*
* Geometric data types are composed of points.
* This code tries to support a common format throughout the data types,
- * to allow for more predictable usage and data type conversion.
+ * to allow for more predictable usage and data type conversion.
* The fundamental unit is the point. Other units are line segments,
- * open paths, boxes, closed paths, and polygons (which should be considered
- * non-intersecting closed paths).
+ * open paths, boxes, closed paths, and polygons (which should be considered
+ * non-intersecting closed paths).
*
* Data representation is as follows:
- * point: (x,y)
- * line segment: [(x1,y1),(x2,y2)]
- * box: (x1,y1),(x2,y2)
- * open path: [(x1,y1),...,(xn,yn)]
- * closed path: ((x1,y1),...,(xn,yn))
- * polygon: ((x1,y1),...,(xn,yn))
+ * point: (x,y)
+ * line segment: [(x1,y1),(x2,y2)]
+ * box: (x1,y1),(x2,y2)
+ * open path: [(x1,y1),...,(xn,yn)]
+ * closed path: ((x1,y1),...,(xn,yn))
+ * polygon: ((x1,y1),...,(xn,yn))
*
* For boxes, the points are opposite corners with the first point at the top right.
* For closed paths and polygons, the points should be reordered to allow
- * fast and correct equality comparisons.
+ * fast and correct equality comparisons.
*
* XXX perhaps points in complex shapes should be reordered internally
- * to allow faster internal operations, but should keep track of input order
- * and restore that order for text output - tgl 97/01/16
+ * to allow faster internal operations, but should keep track of input order
+ * and restore that order for text output - tgl 97/01/16
*/
-static int single_decode(char *str, float8 *x, char **s)
+static int
+single_decode(char *str, float8 * x, char **s)
{
- char *cp;
+ char *cp;
- if (!PointerIsValid(str))
- return(FALSE);
+ if (!PointerIsValid(str))
+ return (FALSE);
- while (isspace( *str)) str++;
- *x = strtod( str, &cp);
+ while (isspace(*str))
+ str++;
+ *x = strtod(str, &cp);
#ifdef GEODEBUG
-fprintf( stderr, "single_decode- (%x) try decoding %s to %g\n", (cp-str), str, *x);
+ fprintf(stderr, "single_decode- (%x) try decoding %s to %g\n", (cp - str), str, *x);
#endif
- if (cp <= str) return(FALSE);
- while (isspace( *cp)) cp++;
-
- if (s != NULL) *s = cp;
+ if (cp <= str)
+ return (FALSE);
+ while (isspace(*cp))
+ cp++;
- return(TRUE);
-} /* single_decode() */
+ if (s != NULL)
+ *s = cp;
-static int single_encode(float8 x, char *str)
-{
- sprintf(str, "%.*g", digits8, x);
- return(TRUE);
-} /* single_encode() */
+ return (TRUE);
+} /* single_decode() */
-static int pair_decode(char *str, float8 *x, float8 *y, char **s)
+static int
+single_encode(float8 x, char *str)
{
- int has_delim;
- char *cp;
-
- if (!PointerIsValid(str))
- return(FALSE);
-
- while (isspace( *str)) str++;
- if ((has_delim = (*str == LDELIM))) str++;
+ sprintf(str, "%.*g", digits8, x);
+ return (TRUE);
+} /* single_encode() */
- while (isspace( *str)) str++;
- *x = strtod( str, &cp);
- if (cp <= str) return(FALSE);
- while (isspace( *cp)) cp++;
- if (*cp++ != DELIM) return(FALSE);
- while (isspace( *cp)) cp++;
- *y = strtod( cp, &str);
- if (str <= cp) return(FALSE);
- while (isspace( *str)) str++;
- if (has_delim) {
- if (*str != RDELIM) return(FALSE);
- str++;
- while (isspace( *str)) str++;
- }
- if (s != NULL) *s = str;
+static int
+pair_decode(char *str, float8 * x, float8 * y, char **s)
+{
+ int has_delim;
+ char *cp;
+
+ if (!PointerIsValid(str))
+ return (FALSE);
+
+ while (isspace(*str))
+ str++;
+ if ((has_delim = (*str == LDELIM)))
+ str++;
+
+ while (isspace(*str))
+ str++;
+ *x = strtod(str, &cp);
+ if (cp <= str)
+ return (FALSE);
+ while (isspace(*cp))
+ cp++;
+ if (*cp++ != DELIM)
+ return (FALSE);
+ while (isspace(*cp))
+ cp++;
+ *y = strtod(cp, &str);
+ if (str <= cp)
+ return (FALSE);
+ while (isspace(*str))
+ str++;
+ if (has_delim)
+ {
+ if (*str != RDELIM)
+ return (FALSE);
+ str++;
+ while (isspace(*str))
+ str++;
+ }
+ if (s != NULL)
+ *s = str;
- return(TRUE);
+ return (TRUE);
}
-static int pair_encode(float8 x, float8 y, char *str)
+static int
+pair_encode(float8 x, float8 y, char *str)
{
- sprintf(str, "%.*g,%.*g", digits8, x, digits8, y);
- return(TRUE);
+ sprintf(str, "%.*g,%.*g", digits8, x, digits8, y);
+ return (TRUE);
}
-static int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p)
-{
- int depth = 0;
- char *s, *cp;
- int i;
-
- s = str;
- while (isspace( *s)) s++;
- if ((*isopen = (*s == LDELIM_EP))) {
- /* no open delimiter allowed? */
- if (! opentype) return(FALSE);
- depth++;
- s++;
- while (isspace( *s)) s++;
+static int
+path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point * p)
+{
+ int depth = 0;
+ char *s,
+ *cp;
+ int i;
+
+ s = str;
+ while (isspace(*s))
+ s++;
+ if ((*isopen = (*s == LDELIM_EP)))
+ {
+ /* no open delimiter allowed? */
+ if (!opentype)
+ return (FALSE);
+ depth++;
+ s++;
+ while (isspace(*s))
+ s++;
- } else if (*s == LDELIM) {
- cp = (s+1);
- while (isspace( *cp)) cp++;
- if (*cp == LDELIM) {
- /* nested delimiters with only one point? */
- if (npts <= 1) return(FALSE);
- depth++;
- s = cp;
- } else if (strrchr( s, LDELIM) == s) {
- depth++;
- s = cp;
}
- }
-
- for (i = 0; i < npts; i++) {
- if (! pair_decode( s, &(p->x), &(p->y), &s))
- return(FALSE);
+ else if (*s == LDELIM)
+ {
+ cp = (s + 1);
+ while (isspace(*cp))
+ cp++;
+ if (*cp == LDELIM)
+ {
+ /* nested delimiters with only one point? */
+ if (npts <= 1)
+ return (FALSE);
+ depth++;
+ s = cp;
+ }
+ else if (strrchr(s, LDELIM) == s)
+ {
+ depth++;
+ s = cp;
+ }
+ }
- if (*s == DELIM) s++;
- p++;
- }
+ for (i = 0; i < npts; i++)
+ {
+ if (!pair_decode(s, &(p->x), &(p->y), &s))
+ return (FALSE);
- while (depth > 0) {
- if ((*s == RDELIM)
- || ((*s == RDELIM_EP) && (*isopen) && (depth == 1))) {
- depth--;
- s++;
- while (isspace( *s)) s++;
- } else {
- return(FALSE);
+ if (*s == DELIM)
+ s++;
+ p++;
}
- }
- *ss = s;
- return(TRUE);
-} /* path_decode() */
+ while (depth > 0)
+ {
+ if ((*s == RDELIM)
+ || ((*s == RDELIM_EP) && (*isopen) && (depth == 1)))
+ {
+ depth--;
+ s++;
+ while (isspace(*s))
+ s++;
+ }
+ else
+ {
+ return (FALSE);
+ }
+ }
+ *ss = s;
+
+ return (TRUE);
+} /* path_decode() */
+
+static char *
+path_encode(bool closed, int npts, Point * pt)
+{
+ char *result = PALLOC(npts * (P_MAXLEN + 3) + 2);
+
+ char *cp;
+ int i;
+
+ cp = result;
+ switch (closed)
+ {
+ case TRUE:
+ *cp++ = LDELIM;
+ break;
+ case FALSE:
+ *cp++ = LDELIM_EP;
+ break;
+ default:
+ break;
+ }
-static char *path_encode( bool closed, int npts, Point *pt)
-{
- char *result = PALLOC(npts*(P_MAXLEN+3)+2);
+ for (i = 0; i < npts; i++)
+ {
+ *cp++ = LDELIM;
+ if (!pair_encode(pt->x, pt->y, cp))
+ elog(WARN, "Unable to format path", NULL);
+ cp += strlen(cp);
+ *cp++ = RDELIM;
+ *cp++ = DELIM;
+ pt++;
+ }
+ cp--;
+ switch (closed)
+ {
+ case TRUE:
+ *cp++ = RDELIM;
+ break;
+ case FALSE:
+ *cp++ = RDELIM_EP;
+ break;
+ default:
+ break;
+ }
+ *cp = '\0';
- char *cp;
- int i;
-
- cp = result;
- switch (closed) {
- case TRUE:
- *cp++ = LDELIM;
- break;
- case FALSE:
- *cp++ = LDELIM_EP;
- break;
- default:
- break;
- }
-
- for (i = 0; i < npts; i++) {
- *cp++ = LDELIM;
- if (! pair_encode( pt->x, pt->y, cp))
- elog (WARN, "Unable to format path", NULL);
- cp += strlen(cp);
- *cp++ = RDELIM;
- *cp++ = DELIM;
- pt++;
- }
- cp--;
- switch (closed) {
- case TRUE:
- *cp++ = RDELIM;
- break;
- case FALSE:
- *cp++ = RDELIM_EP;
- break;
- default:
- break;
- }
- *cp = '\0';
-
- return(result);
-} /* path_encode() */
+ return (result);
+} /* path_encode() */
/*-------------------------------------------------------------
* pair_count - count the number of points
@@ -273,20 +318,22 @@ static char *path_encode( bool closed, int npts, Point *pt)
* '(1,3,2,4)'
* require an odd number of delim characters in the string
*-------------------------------------------------------------*/
-static int pair_count(char *s, char delim)
+static int
+pair_count(char *s, char delim)
{
- int ndelim = 0;
+ int ndelim = 0;
- while ((s = strchr( s, delim)) != NULL) {
- ndelim++;
- s++;
- }
- return((ndelim % 2)? ((ndelim+1)/2): -1);
+ while ((s = strchr(s, delim)) != NULL)
+ {
+ ndelim++;
+ s++;
+ }
+ return ((ndelim % 2) ? ((ndelim + 1) / 2) : -1);
}
/***********************************************************************
**
- ** Routines for two-dimensional boxes.
+ ** Routines for two-dimensional boxes.
**
***********************************************************************/
@@ -294,716 +341,795 @@ static int pair_count(char *s, char delim)
* Formatting and conversion routines.
*---------------------------------------------------------*/
-/* box_in - convert a string to internal form.
+/* box_in - convert a string to internal form.
*
- * External format: (two corners of box)
- * "(f8, f8), (f8, f8)"
- * also supports the older style "(f8, f8, f8, f8)"
+ * External format: (two corners of box)
+ * "(f8, f8), (f8, f8)"
+ * also supports the older style "(f8, f8, f8, f8)"
*/
-BOX *box_in(char *str)
+BOX *
+box_in(char *str)
{
- BOX *box = PALLOCTYPE(BOX);
+ BOX *box = PALLOCTYPE(BOX);
- int isopen;
- char *s;
- double x, y;
+ int isopen;
+ char *s;
+ double x,
+ y;
- if (!PointerIsValid(str))
- elog (WARN," Bad (null) box external representation",NULL);
+ if (!PointerIsValid(str))
+ elog(WARN, " Bad (null) box external representation", NULL);
- if ((! path_decode(FALSE, 2, str, &isopen, &s, &(box->high)))
- || (*s != '\0'))
- elog (WARN, "Bad box external representation '%s'",str);
+ if ((!path_decode(FALSE, 2, str, &isopen, &s, &(box->high)))
+ || (*s != '\0'))
+ elog(WARN, "Bad box external representation '%s'", str);
- /* reorder corners if necessary... */
- if (box->high.x < box->low.x) {
- x = box->high.x;
- box->high.x = box->low.x;
- box->low.x = x;
- }
- if (box->high.y < box->low.y) {
- y = box->high.y;
- box->high.y = box->low.y;
- box->low.y = y;
- }
+ /* reorder corners if necessary... */
+ if (box->high.x < box->low.x)
+ {
+ x = box->high.x;
+ box->high.x = box->low.x;
+ box->low.x = x;
+ }
+ if (box->high.y < box->low.y)
+ {
+ y = box->high.y;
+ box->high.y = box->low.y;
+ box->low.y = y;
+ }
- return(box);
-} /* box_in() */
+ return (box);
+} /* box_in() */
-/* box_out - convert a box to external form.
+/* box_out - convert a box to external form.
*/
-char *box_out(BOX *box)
+char *
+box_out(BOX * box)
{
- if (!PointerIsValid(box))
- return(NULL);
+ if (!PointerIsValid(box))
+ return (NULL);
- return( path_encode( -1, 2, (Point *) &(box->high)));
-} /* box_out() */
+ return (path_encode(-1, 2, (Point *) & (box->high)));
+} /* box_out() */
-/* box_construct - fill in a new box.
+/* box_construct - fill in a new box.
*/
-static BOX *box_construct(double x1, double x2, double y1, double y2)
+static BOX *
+box_construct(double x1, double x2, double y1, double y2)
{
- BOX *result = PALLOCTYPE(BOX);
+ BOX *result = PALLOCTYPE(BOX);
- return( box_fill(result, x1, x2, y1, y2) );
+ return (box_fill(result, x1, x2, y1, y2));
}
-/* box_fill - fill in a static box
+/* box_fill - fill in a static box
*/
-static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2)
+static BOX *
+box_fill(BOX * result, double x1, double x2, double y1, double y2)
{
- if (x1 > x2) {
- result->high.x = x1;
- result->low.x = x2;
- } else {
- result->high.x = x2;
- result->low.x = x1;
- }
- if (y1 > y2) {
- result->high.y = y1;
- result->low.y = y2;
- } else {
- result->high.y = y2;
- result->low.y = y1;
- }
-
- return(result);
+ if (x1 > x2)
+ {
+ result->high.x = x1;
+ result->low.x = x2;
+ }
+ else
+ {
+ result->high.x = x2;
+ result->low.x = x1;
+ }
+ if (y1 > y2)
+ {
+ result->high.y = y1;
+ result->low.y = y2;
+ }
+ else
+ {
+ result->high.y = y2;
+ result->low.y = y1;
+ }
+
+ return (result);
}
-/* box_copy - copy a box
+/* box_copy - copy a box
*/
-static BOX *box_copy(BOX *box)
+static BOX *
+box_copy(BOX * box)
{
- BOX *result = PALLOCTYPE(BOX);
+ BOX *result = PALLOCTYPE(BOX);
- memmove((char *) result, (char *) box, sizeof(BOX));
-
- return(result);
+ memmove((char *) result, (char *) box, sizeof(BOX));
+
+ return (result);
}
/*----------------------------------------------------------
- * Relational operators for BOXes.
- * <, >, <=, >=, and == are based on box area.
+ * Relational operators for BOXes.
+ * <, >, <=, >=, and == are based on box area.
*---------------------------------------------------------*/
-/* box_same - are two boxes identical?
+/* box_same - are two boxes identical?
*/
-bool box_same(BOX *box1, BOX *box2)
+bool
+box_same(BOX * box1, BOX * box2)
{
- return((FPeq(box1->high.x,box2->high.x) && FPeq(box1->low.x,box2->low.x)) &&
- (FPeq(box1->high.y,box2->high.y) && FPeq(box1->low.y,box2->low.y)));
+ return ((FPeq(box1->high.x, box2->high.x) && FPeq(box1->low.x, box2->low.x)) &&
+ (FPeq(box1->high.y, box2->high.y) && FPeq(box1->low.y, box2->low.y)));
}
-/* box_overlap - does box1 overlap box2?
+/* box_overlap - does box1 overlap box2?
*/
-bool box_overlap(BOX *box1, BOX *box2)
+bool
+box_overlap(BOX * box1, BOX * box2)
{
- return(((FPge(box1->high.x,box2->high.x) && FPle(box1->low.x,box2->high.x)) ||
- (FPge(box2->high.x,box1->high.x) && FPle(box2->low.x,box1->high.x))) &&
- ((FPge(box1->high.y,box2->high.y) && FPle(box1->low.y,box2->high.y)) ||
- (FPge(box2->high.y,box1->high.y) && FPle(box2->low.y,box1->high.y))) );
+ return (((FPge(box1->high.x, box2->high.x) && FPle(box1->low.x, box2->high.x)) ||
+ (FPge(box2->high.x, box1->high.x) && FPle(box2->low.x, box1->high.x))) &&
+ ((FPge(box1->high.y, box2->high.y) && FPle(box1->low.y, box2->high.y)) ||
+ (FPge(box2->high.y, box1->high.y) && FPle(box2->low.y, box1->high.y))));
}
-/* box_overleft - is the right edge of box1 to the left of
- * the right edge of box2?
+/* box_overleft - is the right edge of box1 to the left of
+ * the right edge of box2?
*
- * This is "less than or equal" for the end of a time range,
- * when time ranges are stored as rectangles.
+ * This is "less than or equal" for the end of a time range,
+ * when time ranges are stored as rectangles.
*/
-bool box_overleft(BOX *box1, BOX *box2)
+bool
+box_overleft(BOX * box1, BOX * box2)
{
- return(FPle(box1->high.x,box2->high.x));
+ return (FPle(box1->high.x, box2->high.x));
}
-/* box_left - is box1 strictly left of box2?
+/* box_left - is box1 strictly left of box2?
*/
-bool box_left(BOX *box1, BOX *box2)
+bool
+box_left(BOX * box1, BOX * box2)
{
- return(FPlt(box1->high.x,box2->low.x));
+ return (FPlt(box1->high.x, box2->low.x));
}
-/* box_right - is box1 strictly right of box2?
+/* box_right - is box1 strictly right of box2?
*/
-bool box_right(BOX *box1, BOX *box2)
+bool
+box_right(BOX * box1, BOX * box2)
{
- return(FPgt(box1->low.x,box2->high.x));
+ return (FPgt(box1->low.x, box2->high.x));
}
-/* box_overright - is the left edge of box1 to the right of
- * the left edge of box2?
+/* box_overright - is the left edge of box1 to the right of
+ * the left edge of box2?
*
- * This is "greater than or equal" for time ranges, when time ranges
- * are stored as rectangles.
+ * This is "greater than or equal" for time ranges, when time ranges
+ * are stored as rectangles.
*/
-bool box_overright(BOX *box1, BOX *box2)
+bool
+box_overright(BOX * box1, BOX * box2)
{
- return(box1->low.x >= box2->low.x);
+ return (box1->low.x >= box2->low.x);
}
-/* box_contained - is box1 contained by box2?
+/* box_contained - is box1 contained by box2?
*/
-bool box_contained(BOX *box1, BOX *box2)
+bool
+box_contained(BOX * box1, BOX * box2)
{
- return((FPle(box1->high.x,box2->high.x) && FPge(box1->low.x,box2->low.x)) &&
- (FPle(box1->high.y,box2->high.y) && FPge(box1->low.y,box2->low.y)));
+ return ((FPle(box1->high.x, box2->high.x) && FPge(box1->low.x, box2->low.x)) &&
+ (FPle(box1->high.y, box2->high.y) && FPge(box1->low.y, box2->low.y)));
}
-/* box_contain - does box1 contain box2?
+/* box_contain - does box1 contain box2?
*/
-bool box_contain(BOX *box1, BOX *box2)
+bool
+box_contain(BOX * box1, BOX * box2)
{
- return((FPge(box1->high.x,box2->high.x) && FPle(box1->low.x,box2->low.x) &&
- FPge(box1->high.y,box2->high.y) && FPle(box1->low.y,box2->low.y)));
+ return ((FPge(box1->high.x, box2->high.x) && FPle(box1->low.x, box2->low.x) &&
+ FPge(box1->high.y, box2->high.y) && FPle(box1->low.y, box2->low.y)));
}
-/* box_positionop -
- * is box1 entirely {above,below} box2?
+/* box_positionop -
+ * is box1 entirely {above,below} box2?
*/
-bool box_below(BOX *box1, BOX *box2)
+bool
+box_below(BOX * box1, BOX * box2)
{
- return( FPle(box1->high.y,box2->low.y) );
+ return (FPle(box1->high.y, box2->low.y));
}
-bool box_above(BOX *box1, BOX *box2)
+bool
+box_above(BOX * box1, BOX * box2)
{
- return( FPge(box1->low.y,box2->high.y) );
+ return (FPge(box1->low.y, box2->high.y));
}
-/* box_relop - is area(box1) relop area(box2), within
- * our accuracy constraint?
+/* box_relop - is area(box1) relop area(box2), within
+ * our accuracy constraint?
*/
-bool box_lt(BOX *box1, BOX *box2)
+bool
+box_lt(BOX * box1, BOX * box2)
{
- return( FPlt(box_ar(box1), box_ar(box2)) );
+ return (FPlt(box_ar(box1), box_ar(box2)));
}
-bool box_gt(BOX *box1, BOX *box2)
+bool
+box_gt(BOX * box1, BOX * box2)
{
- return( FPgt(box_ar(box1), box_ar(box2)) );
+ return (FPgt(box_ar(box1), box_ar(box2)));
}
-bool box_eq(BOX *box1, BOX *box2)
+bool
+box_eq(BOX * box1, BOX * box2)
{
- return( FPeq(box_ar(box1), box_ar(box2)) );
+ return (FPeq(box_ar(box1), box_ar(box2)));
}
-bool box_le(BOX *box1, BOX *box2)
+bool
+box_le(BOX * box1, BOX * box2)
{
- return( FPle(box_ar(box1), box_ar(box2)) );
+ return (FPle(box_ar(box1), box_ar(box2)));
}
-bool box_ge(BOX *box1, BOX *box2)
+bool
+box_ge(BOX * box1, BOX * box2)
{
- return( FPge(box_ar(box1), box_ar(box2)) );
+ return (FPge(box_ar(box1), box_ar(box2)));
}
/*----------------------------------------------------------
- * "Arithmetic" operators on boxes.
- * box_foo returns foo as an object (pointer) that
+ * "Arithmetic" operators on boxes.
+ * box_foo returns foo as an object (pointer) that
can be passed between languages.
- * box_xx is an internal routine which returns the
- * actual value (and cannot be handed back to
- * LISP).
+ * box_xx is an internal routine which returns the
+ * actual value (and cannot be handed back to
+ * LISP).
*---------------------------------------------------------*/
-/* box_area - returns the area of the box.
+/* box_area - returns the area of the box.
*/
-double *box_area(BOX *box)
+double *
+box_area(BOX * box)
{
- double *result = PALLOCTYPE(double);
+ double *result = PALLOCTYPE(double);
- *result = box_wd(box) * box_ht(box);
-
- return(result);
+ *result = box_wd(box) * box_ht(box);
+
+ return (result);
}
-/* box_width - returns the width of the box
- * (horizontal magnitude).
+/* box_width - returns the width of the box
+ * (horizontal magnitude).
*/
-double *box_width(BOX *box)
+double *
+box_width(BOX * box)
{
- double *result = PALLOCTYPE(double);
+ double *result = PALLOCTYPE(double);
+
+ *result = box->high.x - box->low.x;
- *result = box->high.x - box->low.x;
-
- return(result);
-} /* box_width() */
+ return (result);
+} /* box_width() */
-/* box_height - returns the height of the box
- * (vertical magnitude).
+/* box_height - returns the height of the box
+ * (vertical magnitude).
*/
-double *box_height(BOX *box)
+double *
+box_height(BOX * box)
{
- double *result = PALLOCTYPE(double);
+ double *result = PALLOCTYPE(double);
+
+ *result = box->high.y - box->low.y;
- *result = box->high.y - box->low.y;
-
- return(result);
+ return (result);
}
-/* box_distance - returns the distance between the
- * center points of two boxes.
+/* box_distance - returns the distance between the
+ * center points of two boxes.
*/
-double *box_distance(BOX *box1, BOX *box2)
+double *
+box_distance(BOX * box1, BOX * box2)
{
- double *result = PALLOCTYPE(double);
- Point *a, *b;
-
- a = box_center(box1);
- b = box_center(box2);
- *result = HYPOT(a->x - b->x, a->y - b->y);
-
- PFREE(a);
- PFREE(b);
- return(result);
+ double *result = PALLOCTYPE(double);
+ Point *a,
+ *b;
+
+ a = box_center(box1);
+ b = box_center(box2);
+ *result = HYPOT(a->x - b->x, a->y - b->y);
+
+ PFREE(a);
+ PFREE(b);
+ return (result);
}
-/* box_center - returns the center point of the box.
+/* box_center - returns the center point of the box.
*/
-Point *box_center(BOX *box)
+Point *
+box_center(BOX * box)
{
- Point *result = PALLOCTYPE(Point);
+ Point *result = PALLOCTYPE(Point);
- result->x = (box->high.x + box->low.x) / 2.0;
- result->y = (box->high.y + box->low.y) / 2.0;
-
- return(result);
+ result->x = (box->high.x + box->low.x) / 2.0;
+ result->y = (box->high.y + box->low.y) / 2.0;
+
+ return (result);
}
-/* box_ar - returns the area of the box.
+/* box_ar - returns the area of the box.
*/
-static double box_ar(BOX *box)
+static double
+box_ar(BOX * box)
{
- return( box_wd(box) * box_ht(box) );
+ return (box_wd(box) * box_ht(box));
}
-/* box_wd - returns the width (length) of the box
- * (horizontal magnitude).
+/* box_wd - returns the width (length) of the box
+ * (horizontal magnitude).
*/
-static double box_wd(BOX *box)
+static double
+box_wd(BOX * box)
{
- return( box->high.x - box->low.x );
+ return (box->high.x - box->low.x);
}
-/* box_ht - returns the height of the box
- * (vertical magnitude).
+/* box_ht - returns the height of the box
+ * (vertical magnitude).
*/
-static double box_ht(BOX *box)
+static double
+box_ht(BOX * box)
{
- return( box->high.y - box->low.y );
+ return (box->high.y - box->low.y);
}
-/* box_dt - returns the distance between the
- * center points of two boxes.
+/* box_dt - returns the distance between the
+ * center points of two boxes.
*/
#ifdef NOT_USED
-static double box_dt(BOX *box1, BOX *box2)
-{
- double result;
- Point *a, *b;
-
- a = box_center(box1);
- b = box_center(box2);
- result = HYPOT(a->x - b->x, a->y - b->y);
-
- PFREE(a);
- PFREE(b);
- return(result);
+static double
+box_dt(BOX * box1, BOX * box2)
+{
+ double result;
+ Point *a,
+ *b;
+
+ a = box_center(box1);
+ b = box_center(box2);
+ result = HYPOT(a->x - b->x, a->y - b->y);
+
+ PFREE(a);
+ PFREE(b);
+ return (result);
}
+
#endif
/*----------------------------------------------------------
- * Funky operations.
+ * Funky operations.
*---------------------------------------------------------*/
-/* box_intersect -
- * returns the overlapping portion of two boxes,
- * or NULL if they do not intersect.
+/* box_intersect -
+ * returns the overlapping portion of two boxes,
+ * or NULL if they do not intersect.
*/
-BOX *box_intersect(BOX *box1, BOX *box2)
+BOX *
+box_intersect(BOX * box1, BOX * box2)
{
- BOX *result;
+ BOX *result;
+
+ if (!box_overlap(box1, box2))
+ return (NULL);
- if (! box_overlap(box1,box2))
- return(NULL);
+ result = PALLOCTYPE(BOX);
- result = PALLOCTYPE(BOX);
+ result->high.x = Min(box1->high.x, box2->high.x);
+ result->low.x = Max(box1->low.x, box2->low.x);
+ result->high.y = Min(box1->high.y, box2->high.y);
+ result->low.y = Max(box1->low.y, box2->low.y);
- result->high.x = Min(box1->high.x, box2->high.x);
- result->low.x = Max(box1->low.x, box2->low.x);
- result->high.y = Min(box1->high.y, box2->high.y);
- result->low.y = Max(box1->low.y, box2->low.y);
-
- return(result);
+ return (result);
}
-/* box_diagonal -
- * returns a line segment which happens to be the
- * positive-slope diagonal of "box".
- * provided, of course, we have LSEGs.
+/* box_diagonal -
+ * returns a line segment which happens to be the
+ * positive-slope diagonal of "box".
+ * provided, of course, we have LSEGs.
*/
-LSEG *box_diagonal(BOX *box)
+LSEG *
+box_diagonal(BOX * box)
{
- Point p1, p2;
-
- p1.x = box->high.x;
- p1.y = box->high.y;
- p2.x = box->low.x;
- p2.y = box->low.y;
- return( lseg_construct( &p1, &p2 ) );
-
+ Point p1,
+ p2;
+
+ p1.x = box->high.x;
+ p1.y = box->high.y;
+ p2.x = box->low.x;
+ p2.y = box->low.y;
+ return (lseg_construct(&p1, &p2));
+
}
/***********************************************************************
**
- ** Routines for 2D lines.
- ** Lines are not intended to be used as ADTs per se,
- ** but their ops are useful tools for other ADT ops. Thus,
- ** there are few relops.
+ ** Routines for 2D lines.
+ ** Lines are not intended to be used as ADTs per se,
+ ** but their ops are useful tools for other ADT ops. Thus,
+ ** there are few relops.
**
***********************************************************************/
/*----------------------------------------------------------
- * Conversion routines from one line formula to internal.
- * Internal form: Ax+By+C=0
+ * Conversion routines from one line formula to internal.
+ * Internal form: Ax+By+C=0
*---------------------------------------------------------*/
-static LINE * /* point-slope */
-line_construct_pm(Point *pt, double m)
+static LINE * /* point-slope */
+line_construct_pm(Point * pt, double m)
{
- LINE *result = PALLOCTYPE(LINE);
+ LINE *result = PALLOCTYPE(LINE);
- /* use "mx - y + yinter = 0" */
- result->A = m;
- result->B = -1.0;
- result->C = pt->y - m * pt->x;
+ /* use "mx - y + yinter = 0" */
+ result->A = m;
+ result->B = -1.0;
+ result->C = pt->y - m * pt->x;
- result->m = m;
+ result->m = m;
- return(result);
-} /* line_construct_pm() */
+ return (result);
+} /* line_construct_pm() */
-static LINE * /* two points */
-line_construct_pp(Point *pt1, Point *pt2)
+static LINE * /* two points */
+line_construct_pp(Point * pt1, Point * pt2)
{
- LINE *result = PALLOCTYPE(LINE);
+ LINE *result = PALLOCTYPE(LINE);
- if (FPeq(pt1->x, pt2->x)) { /* vertical */
- /* use "x = C" */
- result->A = -1;
- result->B = 0;
- result->C = pt1->x;
+ if (FPeq(pt1->x, pt2->x))
+ { /* vertical */
+ /* use "x = C" */
+ result->A = -1;
+ result->B = 0;
+ result->C = pt1->x;
#ifdef GEODEBUG
-printf( "line_construct_pp- line is vertical\n");
+ printf("line_construct_pp- line is vertical\n");
#endif
- result->m = DBL_MAX;
+ result->m = DBL_MAX;
- } else if (FPeq(pt1->y, pt2->y)) { /* horizontal */
- /* use "x = C" */
- result->A = 0;
- result->B = -1;
- result->C = pt1->y;
+ }
+ else if (FPeq(pt1->y, pt2->y))
+ { /* horizontal */
+ /* use "x = C" */
+ result->A = 0;
+ result->B = -1;
+ result->C = pt1->y;
#ifdef GEODEBUG
-printf( "line_construct_pp- line is horizontal\n");
+ printf("line_construct_pp- line is horizontal\n");
#endif
- result->m = 0.0;
+ result->m = 0.0;
- } else {
- /* use "mx - y + yinter = 0" */
+ }
+ else
+ {
+ /* use "mx - y + yinter = 0" */
#if FALSE
- result->A = (pt1->y - pt2->y) / (pt1->x - pt2->x);
+ result->A = (pt1->y - pt2->y) / (pt1->x - pt2->x);
#endif
- result->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
- result->B = -1.0;
- result->C = pt1->y - result->A * pt1->x;
+ result->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
+ result->B = -1.0;
+ result->C = pt1->y - result->A * pt1->x;
#ifdef GEODEBUG
-printf( "line_construct_pp- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
- digits8, (pt2->x - pt1->x), digits8, (pt2->y - pt1->y));
+ printf("line_construct_pp- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
+ digits8, (pt2->x - pt1->x), digits8, (pt2->y - pt1->y));
#endif
- result->m = result->A;
- }
- return(result);
-} /* line_construct_pp() */
+ result->m = result->A;
+ }
+ return (result);
+} /* line_construct_pp() */
/*----------------------------------------------------------
- * Relative position routines.
+ * Relative position routines.
*---------------------------------------------------------*/
-static bool line_intersect(LINE *l1, LINE *l2)
+static bool
+line_intersect(LINE * l1, LINE * l2)
{
- return( ! line_parallel(l1, l2) );
+ return (!line_parallel(l1, l2));
}
-static bool line_parallel(LINE *l1, LINE *l2)
+static bool
+line_parallel(LINE * l1, LINE * l2)
{
#if FALSE
- return( FPeq(l1->m, l2->m) );
+ return (FPeq(l1->m, l2->m));
#endif
- if (FPzero(l1->B)) {
- return(FPzero(l2->B));
- }
+ if (FPzero(l1->B))
+ {
+ return (FPzero(l2->B));
+ }
- return(FPeq(l2->A, l1->A*(l2->B / l1->B)));
-} /* line_parallel() */
+ return (FPeq(l2->A, l1->A * (l2->B / l1->B)));
+} /* line_parallel() */
#ifdef NOT_USED
-bool line_perp(LINE *l1, LINE *l2)
+bool
+line_perp(LINE * l1, LINE * l2)
{
#if FALSE
- if (l1->m)
- return( FPeq(l2->m / l1->m, -1.0) );
- else if (l2->m)
- return( FPeq(l1->m / l2->m, -1.0) );
+ if (l1->m)
+ return (FPeq(l2->m / l1->m, -1.0));
+ else if (l2->m)
+ return (FPeq(l1->m / l2->m, -1.0));
#endif
- if (FPzero(l1->A)) {
- return( FPzero(l2->B) );
- } else if (FPzero(l1->B)) {
- return( FPzero(l2->A) );
- }
-
- return( FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0) );
-} /* line_perp() */
+ if (FPzero(l1->A))
+ {
+ return (FPzero(l2->B));
+ }
+ else if (FPzero(l1->B))
+ {
+ return (FPzero(l2->A));
+ }
+
+ return (FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
+} /* line_perp() */
+
#endif
-static bool line_vertical(LINE *line)
+static bool
+line_vertical(LINE * line)
{
#if FALSE
- return( FPeq(line->A, -1.0) && FPzero(line->B) );
+ return (FPeq(line->A, -1.0) && FPzero(line->B));
#endif
- return( FPzero(line->B) );
-} /* line_vertical() */
+ return (FPzero(line->B));
+} /* line_vertical() */
-static bool line_horizontal(LINE *line)
+static bool
+line_horizontal(LINE * line)
{
#if FALSE
- return( FPzero(line->m) );
+ return (FPzero(line->m));
#endif
- return( FPzero(line->A) );
-} /* line_horizontal() */
+ return (FPzero(line->A));
+} /* line_horizontal() */
#ifdef NOT_USED
-bool line_eq(LINE *l1, LINE *l2)
-{
- double k;
-
- if (! FPzero(l2->A))
- k = l1->A / l2->A;
- else if (! FPzero(l2->B))
- k = l1->B / l2->B;
- else if (! FPzero(l2->C))
- k = l1->C / l2->C;
- else
- k = 1.0;
-
- return( FPeq(l1->A, k * l2->A) &&
- FPeq(l1->B, k * l2->B) &&
- FPeq(l1->C, k * l2->C) );
+bool
+line_eq(LINE * l1, LINE * l2)
+{
+ double k;
+
+ if (!FPzero(l2->A))
+ k = l1->A / l2->A;
+ else if (!FPzero(l2->B))
+ k = l1->B / l2->B;
+ else if (!FPzero(l2->C))
+ k = l1->C / l2->C;
+ else
+ k = 1.0;
+
+ return (FPeq(l1->A, k * l2->A) &&
+ FPeq(l1->B, k * l2->B) &&
+ FPeq(l1->C, k * l2->C));
}
+
#endif
/*----------------------------------------------------------
- * Line arithmetic routines.
+ * Line arithmetic routines.
*---------------------------------------------------------*/
-double * /* distance between l1, l2 */
-line_distance(LINE *l1, LINE *l2)
-{
- double *result = PALLOCTYPE(double);
- Point *tmp;
-
- if (line_intersect(l1, l2)) {
- *result = 0.0;
- return(result);
- }
- if (line_vertical(l1))
- *result = fabs(l1->C - l2->C);
- else {
- tmp = point_construct(0.0, l1->C);
- result = dist_pl(tmp, l2);
- PFREE(tmp);
- }
- return(result);
+double * /* distance between l1, l2 */
+line_distance(LINE * l1, LINE * l2)
+{
+ double *result = PALLOCTYPE(double);
+ Point *tmp;
+
+ if (line_intersect(l1, l2))
+ {
+ *result = 0.0;
+ return (result);
+ }
+ if (line_vertical(l1))
+ *result = fabs(l1->C - l2->C);
+ else
+ {
+ tmp = point_construct(0.0, l1->C);
+ result = dist_pl(tmp, l2);
+ PFREE(tmp);
+ }
+ return (result);
}
/* line_interpt()
* Point where two lines l1, l2 intersect (if any)
*/
-static Point *
-line_interpt(LINE *l1, LINE *l2)
+static Point *
+line_interpt(LINE * l1, LINE * l2)
{
- Point *result;
- double x, y;
-
- if (line_parallel(l1, l2))
- return(NULL);
+ Point *result;
+ double x,
+ y;
+
+ if (line_parallel(l1, l2))
+ return (NULL);
#if FALSE
- if (line_vertical(l1))
- result = point_construct(l2->m * l1->C + l2->C, l1->C);
- else if (line_vertical(l2))
- result = point_construct(l1->m * l2->C + l1->C, l2->C);
- else {
- x = (l1->C - l2->C) / (l2->A - l1->A);
- result = point_construct(x, l1->m * x + l1->C);
- }
+ if (line_vertical(l1))
+ result = point_construct(l2->m * l1->C + l2->C, l1->C);
+ else if (line_vertical(l2))
+ result = point_construct(l1->m * l2->C + l1->C, l2->C);
+ else
+ {
+ x = (l1->C - l2->C) / (l2->A - l1->A);
+ result = point_construct(x, l1->m * x + l1->C);
+ }
#endif
- if (line_vertical(l1)) {
+ if (line_vertical(l1))
+ {
#if FALSE
- x = l1->C;
- y = -((l2->A * x + l2->C) / l2->B);
+ x = l1->C;
+ y = -((l2->A * x + l2->C) / l2->B);
#endif
- x = l1->C;
- y = (l2->A * x + l2->C);
+ x = l1->C;
+ y = (l2->A * x + l2->C);
- } else if (line_vertical(l2)) {
+ }
+ else if (line_vertical(l2))
+ {
#if FALSE
- x = l2->C;
- y = -((l1->A * x + l1->C) / l1->B);
+ x = l2->C;
+ y = -((l1->A * x + l1->C) / l1->B);
#endif
- x = l2->C;
- y = (l1->A * x + l1->C);
+ x = l2->C;
+ y = (l1->A * x + l1->C);
- } else {
+ }
+ else
+ {
#if FALSE
- x = (l2->B * l1->C - l1->B * l2->C) / (l2->A * l1->B - l1->A * l2->B);
- y = -((l1->A * x + l1->C) / l1->B);
+ x = (l2->B * l1->C - l1->B * l2->C) / (l2->A * l1->B - l1->A * l2->B);
+ y = -((l1->A * x + l1->C) / l1->B);
#endif
- x = (l1->C - l2->C) / (l2->A - l1->A);
- y = (l1->A * x + l1->C);
- }
- result = point_construct(x, y);
+ x = (l1->C - l2->C) / (l2->A - l1->A);
+ y = (l1->A * x + l1->C);
+ }
+ result = point_construct(x, y);
#ifdef GEODEBUG
-printf( "line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
- digits8, l1->A, digits8, l1->B, digits8, l1->C, digits8, l2->A, digits8, l2->B, digits8, l2->C);
-printf( "line_interpt- lines intersect at (%.*g,%.*g)\n", digits8, x, digits8, y);
+ printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
+ digits8, l1->A, digits8, l1->B, digits8, l1->C, digits8, l2->A, digits8, l2->B, digits8, l2->C);
+ printf("line_interpt- lines intersect at (%.*g,%.*g)\n", digits8, x, digits8, y);
#endif
- return(result);
-} /* line_interpt() */
+ return (result);
+} /* line_interpt() */
/***********************************************************************
**
- ** Routines for 2D paths (sequences of line segments, also
- ** called `polylines').
+ ** Routines for 2D paths (sequences of line segments, also
+ ** called `polylines').
**
- ** This is not a general package for geometric paths,
- ** which of course include polygons; the emphasis here
- ** is on (for example) usefulness in wire layout.
+ ** This is not a general package for geometric paths,
+ ** which of course include polygons; the emphasis here
+ ** is on (for example) usefulness in wire layout.
**
***********************************************************************/
/*----------------------------------------------------------
- * String to path / path to string conversion.
- * External format:
- * "((xcoord, ycoord),... )"
- * "[(xcoord, ycoord),... ]"
- * "(xcoord, ycoord),... "
- * "[xcoord, ycoord,... ]"
- * Also support older format:
- * "(closed, npts, xcoord, ycoord,... )"
+ * String to path / path to string conversion.
+ * External format:
+ * "((xcoord, ycoord),... )"
+ * "[(xcoord, ycoord),... ]"
+ * "(xcoord, ycoord),... "
+ * "[xcoord, ycoord,... ]"
+ * Also support older format:
+ * "(closed, npts, xcoord, ycoord,... )"
*---------------------------------------------------------*/
-PATH *path_in(char *str)
+PATH *
+path_in(char *str)
{
- PATH *path;
+ PATH *path;
- int isopen;
- char *s;
- int npts;
- int size;
- int depth = 0;
+ int isopen;
+ char *s;
+ int npts;
+ int size;
+ int depth = 0;
- if (!PointerIsValid(str))
- elog(WARN, "Bad (null) path external representation");
+ if (!PointerIsValid(str))
+ elog(WARN, "Bad (null) path external representation");
- if ((npts = pair_count(str, ',')) <= 0)
- elog(WARN, "Bad path external representation '%s'", str);
+ if ((npts = pair_count(str, ',')) <= 0)
+ elog(WARN, "Bad path external representation '%s'", str);
- s = str;
- while (isspace( *s)) s++;
+ s = str;
+ while (isspace(*s))
+ s++;
- /* skip single leading paren */
- if ((*s == LDELIM) && (strrchr( s, LDELIM) == s)) {
- s++;
- depth++;
- }
+ /* skip single leading paren */
+ if ((*s == LDELIM) && (strrchr(s, LDELIM) == s))
+ {
+ s++;
+ depth++;
+ }
- size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * npts);
- path = PALLOC(size);
+ size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * npts);
+ path = PALLOC(size);
- path->size = size;
- path->npts = npts;
+ path->size = size;
+ path->npts = npts;
- if ((!path_decode(TRUE, npts, s, &isopen, &s, &(path->p[0])))
- && (!((depth == 0) && (*s == '\0'))) && !((depth >= 1) && (*s == RDELIM)))
- elog (WARN, "Bad path external representation '%s'",str);
+ if ((!path_decode(TRUE, npts, s, &isopen, &s, &(path->p[0])))
+ && (!((depth == 0) && (*s == '\0'))) && !((depth >= 1) && (*s == RDELIM)))
+ elog(WARN, "Bad path external representation '%s'", str);
- path->closed = (! isopen);
+ path->closed = (!isopen);
- return(path);
-} /* path_in() */
+ return (path);
+} /* path_in() */
-char *path_out(PATH *path)
+char *
+path_out(PATH * path)
{
- if (!PointerIsValid(path))
- return NULL;
+ if (!PointerIsValid(path))
+ return NULL;
- return( path_encode( path->closed, path->npts, (Point *) &(path->p[0])));
-} /* path_out() */
+ return (path_encode(path->closed, path->npts, (Point *) & (path->p[0])));
+} /* path_out() */
/*----------------------------------------------------------
- * Relational operators.
- * These are based on the path cardinality,
- * as stupid as that sounds.
+ * Relational operators.
+ * These are based on the path cardinality,
+ * as stupid as that sounds.
*
- * Better relops and access methods coming soon.
+ * Better relops and access methods coming soon.
*---------------------------------------------------------*/
-bool path_n_lt(PATH *p1, PATH *p2)
+bool
+path_n_lt(PATH * p1, PATH * p2)
{
- return( (p1->npts < p2->npts ) );
+ return ((p1->npts < p2->npts));
}
-bool path_n_gt(PATH *p1, PATH *p2)
+bool
+path_n_gt(PATH * p1, PATH * p2)
{
- return( (p1->npts > p2->npts ) );
+ return ((p1->npts > p2->npts));
}
-bool path_n_eq(PATH *p1, PATH *p2)
+bool
+path_n_eq(PATH * p1, PATH * p2)
{
- return( (p1->npts == p2->npts) );
+ return ((p1->npts == p2->npts));
}
-bool path_n_le(PATH *p1, PATH *p2)
+bool
+path_n_le(PATH * p1, PATH * p2)
{
- return( (p1->npts <= p2->npts ) );
+ return ((p1->npts <= p2->npts));
}
-bool path_n_ge(PATH *p1, PATH *p2)
+bool
+path_n_ge(PATH * p1, PATH * p2)
{
- return( (p1->npts >= p2->npts ) );
+ return ((p1->npts >= p2->npts));
}
@@ -1012,1206 +1138,1350 @@ bool path_n_ge(PATH *p1, PATH *p2)
*---------------------------------------------------------*/
bool
-path_isclosed( PATH *path)
+path_isclosed(PATH * path)
{
- if (!PointerIsValid(path))
- return FALSE;
+ if (!PointerIsValid(path))
+ return FALSE;
- return(path->closed);
-} /* path_isclosed() */
+ return (path->closed);
+} /* path_isclosed() */
bool
-path_isopen( PATH *path)
+path_isopen(PATH * path)
{
- if (!PointerIsValid(path))
- return FALSE;
+ if (!PointerIsValid(path))
+ return FALSE;
- return(! path->closed);
-} /* path_isopen() */
+ return (!path->closed);
+} /* path_isopen() */
int4
-path_npoints( PATH *path)
+path_npoints(PATH * path)
{
- if (!PointerIsValid(path))
- return 0;
+ if (!PointerIsValid(path))
+ return 0;
- return(path->npts);
-} /* path_npoints() */
+ return (path->npts);
+} /* path_npoints() */
-PATH *
-path_close(PATH *path)
+PATH *
+path_close(PATH * path)
{
- PATH *result;
+ PATH *result;
- if (!PointerIsValid(path))
- return(NULL);
+ if (!PointerIsValid(path))
+ return (NULL);
- result = path_copy(path);
- result->closed = TRUE;
+ result = path_copy(path);
+ result->closed = TRUE;
- return(result);
-} /* path_close() */
+ return (result);
+} /* path_close() */
-PATH *
-path_open(PATH *path)
+PATH *
+path_open(PATH * path)
{
- PATH *result;
+ PATH *result;
- if (!PointerIsValid(path))
- return(NULL);
+ if (!PointerIsValid(path))
+ return (NULL);
- result = path_copy(path);
- result->closed = FALSE;
+ result = path_copy(path);
+ result->closed = FALSE;
- return(result);
-} /* path_open() */
+ return (result);
+} /* path_open() */
-PATH *
-path_copy(PATH *path)
+PATH *
+path_copy(PATH * path)
{
- PATH *result;
- int size;
+ PATH *result;
+ int size;
- size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * path->npts);
- result = PALLOC(size);
+ size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * path->npts);
+ result = PALLOC(size);
- memmove((char *) result, (char *) path, size);
- return(result);
-} /* path_copy() */
+ memmove((char *) result, (char *) path, size);
+ return (result);
+} /* path_copy() */
/* path_inter -
- * Does p1 intersect p2 at any point?
- * Use bounding boxes for a quick (O(n)) check, then do a
- * O(n^2) iterative edge check.
- */
-bool path_inter(PATH *p1, PATH *p2)
-{
- BOX b1, b2;
- int i, j;
- LSEG seg1, seg2;
-
- b1.high.x = b1.low.x = p1->p[0].x;
- b1.high.y = b1.low.y = p1->p[0].y;
- for (i = 1; i < p1->npts; i++) {
- b1.high.x = Max(p1->p[i].x, b1.high.x);
- b1.high.y = Max(p1->p[i].y, b1.high.y);
- b1.low.x = Min(p1->p[i].x, b1.low.x);
- b1.low.y = Min(p1->p[i].y, b1.low.y);
- }
- b2.high.x = b2.low.x = p2->p[0].x;
- b2.high.y = b2.low.y = p2->p[0].y;
- for (i = 1; i < p2->npts; i++) {
- b2.high.x = Max(p2->p[i].x, b2.high.x);
- b2.high.y = Max(p2->p[i].y, b2.high.y);
- b2.low.x = Min(p2->p[i].x, b2.low.x);
- b2.low.y = Min(p2->p[i].y, b2.low.y);
- }
- if (! box_overlap(&b1, &b2))
- return(0);
-
- /* pairwise check lseg intersections */
- for (i = 0; i < p1->npts - 1; i++) {
- for (j = 0; j < p2->npts - 1; j++) {
- statlseg_construct(&seg1, &p1->p[i], &p1->p[i+1]);
- statlseg_construct(&seg2, &p2->p[j], &p2->p[j+1]);
- if (lseg_intersect(&seg1, &seg2))
- return(1);
- }
- }
-
- /* if we dropped through, no two segs intersected */
- return(0);
+ * Does p1 intersect p2 at any point?
+ * Use bounding boxes for a quick (O(n)) check, then do a
+ * O(n^2) iterative edge check.
+ */
+bool
+path_inter(PATH * p1, PATH * p2)
+{
+ BOX b1,
+ b2;
+ int i,
+ j;
+ LSEG seg1,
+ seg2;
+
+ b1.high.x = b1.low.x = p1->p[0].x;
+ b1.high.y = b1.low.y = p1->p[0].y;
+ for (i = 1; i < p1->npts; i++)
+ {
+ b1.high.x = Max(p1->p[i].x, b1.high.x);
+ b1.high.y = Max(p1->p[i].y, b1.high.y);
+ b1.low.x = Min(p1->p[i].x, b1.low.x);
+ b1.low.y = Min(p1->p[i].y, b1.low.y);
+ }
+ b2.high.x = b2.low.x = p2->p[0].x;
+ b2.high.y = b2.low.y = p2->p[0].y;
+ for (i = 1; i < p2->npts; i++)
+ {
+ b2.high.x = Max(p2->p[i].x, b2.high.x);
+ b2.high.y = Max(p2->p[i].y, b2.high.y);
+ b2.low.x = Min(p2->p[i].x, b2.low.x);
+ b2.low.y = Min(p2->p[i].y, b2.low.y);
+ }
+ if (!box_overlap(&b1, &b2))
+ return (0);
+
+ /* pairwise check lseg intersections */
+ for (i = 0; i < p1->npts - 1; i++)
+ {
+ for (j = 0; j < p2->npts - 1; j++)
+ {
+ statlseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
+ statlseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
+ if (lseg_intersect(&seg1, &seg2))
+ return (1);
+ }
+ }
+
+ /* if we dropped through, no two segs intersected */
+ return (0);
}
/* this essentially does a cartesian product of the lsegs in the
two paths, and finds the min distance between any two lsegs */
-double *path_distance(PATH *p1, PATH *p2)
+double *
+path_distance(PATH * p1, PATH * p2)
{
- double *min = NULL, *tmp;
- int i,j;
- LSEG seg1, seg2;
+ double *min = NULL,
+ *tmp;
+ int i,
+ j;
+ LSEG seg1,
+ seg2;
/*
- statlseg_construct(&seg1, &p1->p[0], &p1->p[1]);
- statlseg_construct(&seg2, &p2->p[0], &p2->p[1]);
- min = lseg_distance(&seg1, &seg2);
+ statlseg_construct(&seg1, &p1->p[0], &p1->p[1]);
+ statlseg_construct(&seg2, &p2->p[0], &p2->p[1]);
+ min = lseg_distance(&seg1, &seg2);
*/
- for (i = 0; i < p1->npts - 1; i++)
- for (j = 0; j < p2->npts - 1; j++)
- {
- statlseg_construct(&seg1, &p1->p[i], &p1->p[i+1]);
- statlseg_construct(&seg2, &p2->p[j], &p2->p[j+1]);
-
- tmp = lseg_distance(&seg1, &seg2);
- if ((min == NULL) || (*min < *tmp)) {
- if (min != NULL) PFREE(min);
- min = tmp;
- } else {
- PFREE(tmp);
+ for (i = 0; i < p1->npts - 1; i++)
+ for (j = 0; j < p2->npts - 1; j++)
+ {
+ statlseg_construct(&seg1, &p1->p[i], &p1->p[i + 1]);
+ statlseg_construct(&seg2, &p2->p[j], &p2->p[j + 1]);
+
+ tmp = lseg_distance(&seg1, &seg2);
+ if ((min == NULL) || (*min < *tmp))
+ {
+ if (min != NULL)
+ PFREE(min);
+ min = tmp;
+ }
+ else
+ {
+ PFREE(tmp);
+ }
}
- }
- return(min);
+ return (min);
}
/*----------------------------------------------------------
- * "Arithmetic" operations.
+ * "Arithmetic" operations.
*---------------------------------------------------------*/
-double *path_length(PATH *path)
+double *
+path_length(PATH * path)
{
- double *result;
- int i;
+ double *result;
+ int i;
- result = PALLOCTYPE(double);
+ result = PALLOCTYPE(double);
- *result = 0;
- for (i = 0; i < (path->npts - 1); i++)
- *result += point_dt(&path->p[i], &path->p[i+1]);
+ *result = 0;
+ for (i = 0; i < (path->npts - 1); i++)
+ *result += point_dt(&path->p[i], &path->p[i + 1]);
- return(result);
-} /* path_length() */
+ return (result);
+} /* path_length() */
#ifdef NOT_USED
-double path_ln(PATH *path)
+double
+path_ln(PATH * path)
{
- double result;
- int i;
+ double result;
+ int i;
- result = 0;
- for (i = 0; i < (path->npts - 1); i++)
- result += point_dt(&path->p[i], &path->p[i+1]);
+ result = 0;
+ for (i = 0; i < (path->npts - 1); i++)
+ result += point_dt(&path->p[i], &path->p[i + 1]);
+
+ return (result);
+} /* path_ln() */
- return(result);
-} /* path_ln() */
#endif
/***********************************************************************
**
- ** Routines for 2D points.
+ ** Routines for 2D points.
**
***********************************************************************/
/*----------------------------------------------------------
- * String to point, point to string conversion.
- * External format:
- * "(x,y)"
- * "x,y"
+ * String to point, point to string conversion.
+ * External format:
+ * "(x,y)"
+ * "x,y"
*---------------------------------------------------------*/
-Point *
+Point *
point_in(char *str)
{
- Point *point;
+ Point *point;
+
+ double x,
+ y;
+ char *s;
- double x, y;
- char *s;
-
- if (! PointerIsValid( str))
- elog(WARN, "Bad (null) point external representation");
+ if (!PointerIsValid(str))
+ elog(WARN, "Bad (null) point external representation");
- if (! pair_decode( str, &x, &y, &s) || (strlen(s) > 0))
- elog (WARN, "Bad point external representation '%s'",str);
+ if (!pair_decode(str, &x, &y, &s) || (strlen(s) > 0))
+ elog(WARN, "Bad point external representation '%s'", str);
- point = PALLOCTYPE(Point);
+ point = PALLOCTYPE(Point);
- point->x = x;
- point->y = y;
+ point->x = x;
+ point->y = y;
- return(point);
-} /* point_in() */
+ return (point);
+} /* point_in() */
-char *
-point_out(Point *pt)
+char *
+point_out(Point * pt)
{
- if (! PointerIsValid(pt))
- return(NULL);
+ if (!PointerIsValid(pt))
+ return (NULL);
- return( path_encode( -1, 1, pt));
-} /* point_out() */
+ return (path_encode(-1, 1, pt));
+} /* point_out() */
-static Point *point_construct(double x, double y)
+static Point *
+point_construct(double x, double y)
{
- Point *result = PALLOCTYPE(Point);
+ Point *result = PALLOCTYPE(Point);
- result->x = x;
- result->y = y;
- return(result);
+ result->x = x;
+ result->y = y;
+ return (result);
}
-static Point *point_copy(Point *pt)
+static Point *
+point_copy(Point * pt)
{
- Point *result;
+ Point *result;
- if (! PointerIsValid( pt))
- return(NULL);
+ if (!PointerIsValid(pt))
+ return (NULL);
- result = PALLOCTYPE(Point);
+ result = PALLOCTYPE(Point);
- result->x = pt->x;
- result->y = pt->y;
- return(result);
+ result->x = pt->x;
+ result->y = pt->y;
+ return (result);
}
/*----------------------------------------------------------
- * Relational operators for Points.
- * Since we do have a sense of coordinates being
- * "equal" to a given accuracy (point_vert, point_horiz),
- * the other ops must preserve that sense. This means
- * that results may, strictly speaking, be a lie (unless
- * EPSILON = 0.0).
+ * Relational operators for Points.
+ * Since we do have a sense of coordinates being
+ * "equal" to a given accuracy (point_vert, point_horiz),
+ * the other ops must preserve that sense. This means
+ * that results may, strictly speaking, be a lie (unless
+ * EPSILON = 0.0).
*---------------------------------------------------------*/
-bool point_left(Point *pt1, Point *pt2)
+bool
+point_left(Point * pt1, Point * pt2)
{
- return( FPlt(pt1->x, pt2->x) );
+ return (FPlt(pt1->x, pt2->x));
}
-bool point_right(Point *pt1, Point *pt2)
+bool
+point_right(Point * pt1, Point * pt2)
{
- return( FPgt(pt1->x, pt2->x) );
+ return (FPgt(pt1->x, pt2->x));
}
-bool point_above(Point *pt1, Point *pt2)
+bool
+point_above(Point * pt1, Point * pt2)
{
- return( FPgt(pt1->y, pt2->y) );
+ return (FPgt(pt1->y, pt2->y));
}
-bool point_below(Point *pt1, Point *pt2)
+bool
+point_below(Point * pt1, Point * pt2)
{
- return( FPlt(pt1->y, pt2->y) );
+ return (FPlt(pt1->y, pt2->y));
}
-bool point_vert(Point *pt1, Point *pt2)
+bool
+point_vert(Point * pt1, Point * pt2)
{
- return( FPeq( pt1->x, pt2->x ) );
+ return (FPeq(pt1->x, pt2->x));
}
-bool point_horiz(Point *pt1, Point *pt2)
+bool
+point_horiz(Point * pt1, Point * pt2)
{
- return( FPeq( pt1->y, pt2->y ) );
+ return (FPeq(pt1->y, pt2->y));
}
-bool point_eq(Point *pt1, Point *pt2)
+bool
+point_eq(Point * pt1, Point * pt2)
{
- return( point_horiz(pt1, pt2) && point_vert(pt1, pt2) );
+ return (point_horiz(pt1, pt2) && point_vert(pt1, pt2));
}
/*----------------------------------------------------------
- * "Arithmetic" operators on points.
+ * "Arithmetic" operators on points.
*---------------------------------------------------------*/
-int32 pointdist(Point *p1, Point *p2)
+int32
+pointdist(Point * p1, Point * p2)
{
- int32 result;
-
- result = point_dt(p1, p2);
- return(result);
+ int32 result;
+
+ result = point_dt(p1, p2);
+ return (result);
}
-double *point_distance(Point *pt1, Point *pt2)
+double *
+point_distance(Point * pt1, Point * pt2)
{
- double *result = PALLOCTYPE(double);
+ double *result = PALLOCTYPE(double);
- *result = HYPOT( pt1->x - pt2->x, pt1->y - pt2->y );
- return(result);
+ *result = HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
+ return (result);
}
-double point_dt(Point *pt1, Point *pt2)
+double
+point_dt(Point * pt1, Point * pt2)
{
- return( HYPOT( pt1->x - pt2->x, pt1->y - pt2->y ) );
+ return (HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
}
-double *point_slope(Point *pt1, Point *pt2)
+double *
+point_slope(Point * pt1, Point * pt2)
{
- double *result = PALLOCTYPE(double);
+ double *result = PALLOCTYPE(double);
- if (point_vert(pt1, pt2))
- *result = (double)DBL_MAX;
- else
- *result = (pt1->y - pt2->y) / (pt1->x - pt1->x);
- return(result);
+ if (point_vert(pt1, pt2))
+ *result = (double) DBL_MAX;
+ else
+ *result = (pt1->y - pt2->y) / (pt1->x - pt1->x);
+ return (result);
}
-double point_sl(Point *pt1, Point *pt2)
+double
+point_sl(Point * pt1, Point * pt2)
{
- return( point_vert(pt1, pt2)
- ? (double)DBL_MAX
- : (pt1->y - pt2->y) / (pt1->x - pt2->x) );
+ return (point_vert(pt1, pt2)
+ ? (double) DBL_MAX
+ : (pt1->y - pt2->y) / (pt1->x - pt2->x));
}
/***********************************************************************
**
- ** Routines for 2D line segments.
+ ** Routines for 2D line segments.
**
***********************************************************************/
/*----------------------------------------------------------
- * String to lseg, lseg to string conversion.
- * External forms: "[(x1, y1), (x2, y2)]"
- * "(x1, y1), (x2, y2)"
- * "x1, y1, x2, y2"
- * closed form ok "((x1, y1), (x2, y2))"
- * (old form) "(x1, y1, x2, y2)"
+ * String to lseg, lseg to string conversion.
+ * External forms: "[(x1, y1), (x2, y2)]"
+ * "(x1, y1), (x2, y2)"
+ * "x1, y1, x2, y2"
+ * closed form ok "((x1, y1), (x2, y2))"
+ * (old form) "(x1, y1, x2, y2)"
*---------------------------------------------------------*/
-LSEG *lseg_in(char *str)
+LSEG *
+lseg_in(char *str)
{
- LSEG *lseg;
+ LSEG *lseg;
+
+ int isopen;
+ char *s;
- int isopen;
- char *s;
+ if (!PointerIsValid(str))
+ elog(WARN, " Bad (null) lseg external representation", NULL);
- if (!PointerIsValid(str))
- elog (WARN," Bad (null) lseg external representation",NULL);
+ lseg = PALLOCTYPE(LSEG);
- lseg = PALLOCTYPE(LSEG);
+ if ((!path_decode(TRUE, 2, str, &isopen, &s, &(lseg->p[0])))
+ || (*s != '\0'))
+ elog(WARN, "Bad lseg external representation '%s'", str);
- if ((! path_decode(TRUE, 2, str, &isopen, &s, &(lseg->p[0])))
- || (*s != '\0'))
- elog (WARN, "Bad lseg external representation '%s'",str);
+ lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);
- lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);
-
- return(lseg);
-} /* lseg_in() */
+ return (lseg);
+} /* lseg_in() */
-char *lseg_out(LSEG *ls)
+char *
+lseg_out(LSEG * ls)
{
- if (!PointerIsValid(ls))
- return(NULL);
+ if (!PointerIsValid(ls))
+ return (NULL);
- return( path_encode( FALSE, 2, (Point *) &(ls->p[0])));
-} /* lseg_out() */
+ return (path_encode(FALSE, 2, (Point *) & (ls->p[0])));
+} /* lseg_out() */
/* lseg_construct -
- * form a LSEG from two Points.
+ * form a LSEG from two Points.
*/
-LSEG *lseg_construct(Point *pt1, Point *pt2)
+LSEG *
+lseg_construct(Point * pt1, Point * pt2)
{
- LSEG *result = PALLOCTYPE(LSEG);
+ LSEG *result = PALLOCTYPE(LSEG);
- result->p[0].x = pt1->x;
- result->p[0].y = pt1->y;
- result->p[1].x = pt2->x;
- result->p[1].y = pt2->y;
+ result->p[0].x = pt1->x;
+ result->p[0].y = pt1->y;
+ result->p[1].x = pt2->x;
+ result->p[1].y = pt2->y;
- result->m = point_sl(pt1, pt2);
-
- return(result);
+ result->m = point_sl(pt1, pt2);
+
+ return (result);
}
/* like lseg_construct, but assume space already allocated */
-static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
+static void
+statlseg_construct(LSEG * lseg, Point * pt1, Point * pt2)
{
- lseg->p[0].x = pt1->x;
- lseg->p[0].y = pt1->y;
- lseg->p[1].x = pt2->x;
- lseg->p[1].y = pt2->y;
+ lseg->p[0].x = pt1->x;
+ lseg->p[0].y = pt1->y;
+ lseg->p[1].x = pt2->x;
+ lseg->p[1].y = pt2->y;
- lseg->m = point_sl(pt1, pt2);
+ lseg->m = point_sl(pt1, pt2);
}
/*----------------------------------------------------------
- * Relative position routines.
+ * Relative position routines.
*---------------------------------------------------------*/
/*
- ** find intersection of the two lines, and see if it falls on
+ ** find intersection of the two lines, and see if it falls on
** both segments.
*/
-bool lseg_intersect(LSEG *l1, LSEG *l2)
-{
- LINE *ln;
- Point *interpt;
- bool retval;
-
- ln = line_construct_pp(&l2->p[0], &l2->p[1]);
- interpt = interpt_sl(l1, ln);
-
- if (interpt != NULL && on_ps(interpt, l2)) /* interpt on l1 and l2 */
- retval = TRUE;
- else retval = FALSE;
- if (interpt != NULL) PFREE(interpt);
- PFREE(ln);
- return(retval);
+bool
+lseg_intersect(LSEG * l1, LSEG * l2)
+{
+ LINE *ln;
+ Point *interpt;
+ bool retval;
+
+ ln = line_construct_pp(&l2->p[0], &l2->p[1]);
+ interpt = interpt_sl(l1, ln);
+
+ if (interpt != NULL && on_ps(interpt, l2)) /* interpt on l1 and l2 */
+ retval = TRUE;
+ else
+ retval = FALSE;
+ if (interpt != NULL)
+ PFREE(interpt);
+ PFREE(ln);
+ return (retval);
}
-bool lseg_parallel(LSEG *l1, LSEG *l2)
+bool
+lseg_parallel(LSEG * l1, LSEG * l2)
{
#if FALSE
- return( FPeq(l1->m, l2->m) );
+ return (FPeq(l1->m, l2->m));
#endif
- return( FPeq( point_sl( &(l1->p[0]), &(l1->p[1])),
- point_sl( &(l2->p[0]), &(l2->p[1]))) );
-} /* lseg_parallel() */
+ return (FPeq(point_sl(&(l1->p[0]), &(l1->p[1])),
+ point_sl(&(l2->p[0]), &(l2->p[1]))));
+} /* lseg_parallel() */
-bool lseg_perp(LSEG *l1, LSEG *l2)
+bool
+lseg_perp(LSEG * l1, LSEG * l2)
{
- double m1, m2;
+ double m1,
+ m2;
- m1 = point_sl( &(l1->p[0]), &(l1->p[1]));
- m2 = point_sl( &(l2->p[0]), &(l2->p[1]));
+ m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
+ m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
- if (! FPzero(m1))
- return( FPeq(m2 / m1, -1.0) );
- else if (! FPzero(m2))
- return( FPeq(m1 / m2, -1.0) );
- return(0); /* both 0.0 */
-} /* lseg_perp() */
+ if (!FPzero(m1))
+ return (FPeq(m2 / m1, -1.0));
+ else if (!FPzero(m2))
+ return (FPeq(m1 / m2, -1.0));
+ return (0); /* both 0.0 */
+} /* lseg_perp() */
-bool lseg_vertical(LSEG *lseg)
+bool
+lseg_vertical(LSEG * lseg)
{
- return( FPeq(lseg->p[0].x, lseg->p[1].x) );
+ return (FPeq(lseg->p[0].x, lseg->p[1].x));
}
-bool lseg_horizontal(LSEG *lseg)
+bool
+lseg_horizontal(LSEG * lseg)
{
- return( FPeq(lseg->p[0].y, lseg->p[1].y) );
+ return (FPeq(lseg->p[0].y, lseg->p[1].y));
}
-bool lseg_eq(LSEG *l1, LSEG *l2)
+bool
+lseg_eq(LSEG * l1, LSEG * l2)
{
- return( FPeq(l1->p[0].x, l2->p[0].x) &&
- FPeq(l1->p[1].y, l2->p[1].y) &&
- FPeq(l1->p[0].x, l2->p[0].x) &&
- FPeq(l1->p[1].y, l2->p[1].y) );
+ return (FPeq(l1->p[0].x, l2->p[0].x) &&
+ FPeq(l1->p[1].y, l2->p[1].y) &&
+ FPeq(l1->p[0].x, l2->p[0].x) &&
+ FPeq(l1->p[1].y, l2->p[1].y));
}
/*----------------------------------------------------------
- * Line arithmetic routines.
+ * Line arithmetic routines.
*---------------------------------------------------------*/
/* lseg_distance -
- * If two segments don't intersect, then the closest
- * point will be from one of the endpoints to the other
- * segment.
+ * If two segments don't intersect, then the closest
+ * point will be from one of the endpoints to the other
+ * segment.
*/
-double *lseg_distance(LSEG *l1, LSEG *l2)
+double *
+lseg_distance(LSEG * l1, LSEG * l2)
{
- double *result = PALLOCTYPE(double);
+ double *result = PALLOCTYPE(double);
- *result = lseg_dt( l1, l2);
+ *result = lseg_dt(l1, l2);
- return(result);
+ return (result);
}
/* distance between l1, l2 */
static double
-lseg_dt(LSEG *l1, LSEG *l2)
-{
- double *d, result;
-
- if (lseg_intersect(l1, l2))
- return(0.0);
-
- d = dist_ps(&l1->p[0], l2);
- result = *d;
- PFREE(d);
- d = dist_ps(&l1->p[1], l2);
- result = Min(result, *d);
- PFREE(d);
+lseg_dt(LSEG * l1, LSEG * l2)
+{
+ double *d,
+ result;
+
+ if (lseg_intersect(l1, l2))
+ return (0.0);
+
+ d = dist_ps(&l1->p[0], l2);
+ result = *d;
+ PFREE(d);
+ d = dist_ps(&l1->p[1], l2);
+ result = Min(result, *d);
+ PFREE(d);
#if FALSE
/* XXX Why are we checking distances from all endpoints to the other segment?
* One set of endpoints should be sufficient - tgl 97/07/03
*/
- d = dist_ps(&l2->p[0], l1);
- result = Min(result, *d);
- PFREE(d);
- d = dist_ps(&l2->p[1], l1);
- result = Min(result, *d);
- PFREE(d);
+ d = dist_ps(&l2->p[0], l1);
+ result = Min(result, *d);
+ PFREE(d);
+ d = dist_ps(&l2->p[1], l1);
+ result = Min(result, *d);
+ PFREE(d);
#endif
-
- return(result);
-} /* lseg_dt() */
+
+ return (result);
+} /* lseg_dt() */
-Point *
-lseg_center(LSEG *lseg)
+Point *
+lseg_center(LSEG * lseg)
{
- Point *result;
+ Point *result;
- if (!PointerIsValid(lseg))
- return(NULL);
+ if (!PointerIsValid(lseg))
+ return (NULL);
- result = PALLOCTYPE(Point);
+ result = PALLOCTYPE(Point);
- result->x = (lseg->p[0].x - lseg->p[1].x) / 2;
- result->y = (lseg->p[0].y - lseg->p[1].y) / 2;
+ result->x = (lseg->p[0].x - lseg->p[1].x) / 2;
+ result->y = (lseg->p[0].y - lseg->p[1].y) / 2;
- return(result);
-} /* lseg_center() */
+ return (result);
+} /* lseg_center() */
/* lseg_interpt -
- * Find the intersection point of two segments (if any).
- * Find the intersection of the appropriate lines; if the
- * point is not on a given segment, there is no valid segment
- * intersection point at all.
+ * Find the intersection point of two segments (if any).
+ * Find the intersection of the appropriate lines; if the
+ * point is not on a given segment, there is no valid segment
+ * intersection point at all.
* If there is an intersection, then check explicitly for matching
- * endpoints since there may be rounding effects with annoying
- * lsb residue. - tgl 1997-07-09
- */
-Point *
-lseg_interpt(LSEG *l1, LSEG *l2)
-{
- Point *result;
- LINE *tmp1, *tmp2;
-
- if (!PointerIsValid(l1) || !PointerIsValid(l2))
- return(NULL);
-
- tmp1 = line_construct_pp(&l1->p[0], &l1->p[1]);
- tmp2 = line_construct_pp(&l2->p[0], &l2->p[1]);
- result = line_interpt(tmp1, tmp2);
- if (PointerIsValid(result)) {
- if (on_ps(result, l1)) {
- if ((FPeq( l1->p[0].x, l2->p[0].x) && FPeq( l1->p[0].y, l2->p[0].y))
- || (FPeq( l1->p[0].x, l2->p[1].x) && FPeq( l1->p[0].y, l2->p[1].y))) {
- result->x = l1->p[0].x;
- result->y = l1->p[0].y;
-
- } else if ((FPeq( l1->p[1].x, l2->p[0].x) && FPeq( l1->p[1].y, l2->p[0].y))
- || (FPeq( l1->p[1].x, l2->p[1].x) && FPeq( l1->p[1].y, l2->p[1].y))) {
- result->x = l1->p[1].x;
- result->y = l1->p[1].y;
- }
- } else {
- PFREE(result);
- result = NULL;
- }
- }
- PFREE(tmp1);
- PFREE(tmp2);
-
- return(result);
-} /* lseg_interpt() */
+ * endpoints since there may be rounding effects with annoying
+ * lsb residue. - tgl 1997-07-09
+ */
+Point *
+lseg_interpt(LSEG * l1, LSEG * l2)
+{
+ Point *result;
+ LINE *tmp1,
+ *tmp2;
+
+ if (!PointerIsValid(l1) || !PointerIsValid(l2))
+ return (NULL);
+
+ tmp1 = line_construct_pp(&l1->p[0], &l1->p[1]);
+ tmp2 = line_construct_pp(&l2->p[0], &l2->p[1]);
+ result = line_interpt(tmp1, tmp2);
+ if (PointerIsValid(result))
+ {
+ if (on_ps(result, l1))
+ {
+ if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y))
+ || (FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
+ {
+ result->x = l1->p[0].x;
+ result->y = l1->p[0].y;
+
+ }
+ else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y))
+ || (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
+ {
+ result->x = l1->p[1].x;
+ result->y = l1->p[1].y;
+ }
+ }
+ else
+ {
+ PFREE(result);
+ result = NULL;
+ }
+ }
+ PFREE(tmp1);
+ PFREE(tmp2);
+
+ return (result);
+} /* lseg_interpt() */
/***********************************************************************
**
- ** Routines for position comparisons of differently-typed
- ** 2D objects.
+ ** Routines for position comparisons of differently-typed
+ ** 2D objects.
**
***********************************************************************/
-#define ABOVE 1
-#define BELOW 0
-#define UNDEF -1
+#define ABOVE 1
+#define BELOW 0
+#define UNDEF -1
/*---------------------------------------------------------------------
- * dist_
- * Minimum distance from one object to another.
+ * dist_
+ * Minimum distance from one object to another.
*-------------------------------------------------------------------*/
-double *dist_pl(Point *pt, LINE *line)
+double *
+dist_pl(Point * pt, LINE * line)
{
- double *result = PALLOCTYPE(double);
+ double *result = PALLOCTYPE(double);
- *result = (line->A * pt->x + line->B * pt->y + line->C) /
- HYPOT(line->A, line->B);
-
- return(result);
+ *result = (line->A * pt->x + line->B * pt->y + line->C) /
+ HYPOT(line->A, line->B);
+
+ return (result);
}
-double *dist_ps(Point *pt, LSEG *lseg)
+double *
+dist_ps(Point * pt, LSEG * lseg)
{
- double m; /* slope of perp. */
- LINE *ln;
- double *result, *tmpdist;
- Point *ip;
+ double m; /* slope of perp. */
+ LINE *ln;
+ double *result,
+ *tmpdist;
+ Point *ip;
/*
* Construct a line perpendicular to the input segment
* and through the input point
*/
- if (lseg->p[1].x == lseg->p[0].x) {
- m = 0;
- } else if (lseg->p[1].y == lseg->p[0].y) { /* slope is infinite */
- m = (double)DBL_MAX;
- } else {
+ if (lseg->p[1].x == lseg->p[0].x)
+ {
+ m = 0;
+ }
+ else if (lseg->p[1].y == lseg->p[0].y)
+ { /* slope is infinite */
+ m = (double) DBL_MAX;
+ }
+ else
+ {
#if FALSE
- m = (-1) * (lseg->p[1].y - lseg->p[0].y) /
- (lseg->p[1].x - lseg->p[0].x);
+ m = (-1) * (lseg->p[1].y - lseg->p[0].y) /
+ (lseg->p[1].x - lseg->p[0].x);
#endif
- m = ((lseg->p[0].y - lseg->p[1].y) / (lseg->p[1].x - lseg->p[0].x));
- }
- ln = line_construct_pm(pt, m);
+ m = ((lseg->p[0].y - lseg->p[1].y) / (lseg->p[1].x - lseg->p[0].x));
+ }
+ ln = line_construct_pm(pt, m);
#ifdef GEODEBUG
-printf( "dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
- ln->A, ln->B, ln->C, pt->x, pt->y, m);
+ printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
+ ln->A, ln->B, ln->C, pt->x, pt->y, m);
#endif
/*
* Calculate distance to the line segment
- * or to the endpoints of the segment.
+ * or to the endpoints of the segment.
*/
- /* intersection is on the line segment? */
- if ((ip = interpt_sl(lseg, ln)) != NULL) {
- result = point_distance(pt, ip);
+ /* intersection is on the line segment? */
+ if ((ip = interpt_sl(lseg, ln)) != NULL)
+ {
+ result = point_distance(pt, ip);
#ifdef GEODEBUG
-printf( "dist_ps- distance is %f to intersection point is (%f,%f)\n",
- *result, ip->x, ip->y);
+ printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
+ *result, ip->x, ip->y);
#endif
- /* otherwise, intersection is not on line segment */
- } else {
- result = point_distance(pt, &lseg->p[0]);
- tmpdist = point_distance(pt, &lseg->p[1]);
- if (*tmpdist < *result) *result = *tmpdist;
- PFREE (tmpdist);
- }
-
- if (ip != NULL) PFREE(ip);
- PFREE(ln);
- return (result);
+ /* otherwise, intersection is not on line segment */
+ }
+ else
+ {
+ result = point_distance(pt, &lseg->p[0]);
+ tmpdist = point_distance(pt, &lseg->p[1]);
+ if (*tmpdist < *result)
+ *result = *tmpdist;
+ PFREE(tmpdist);
+ }
+
+ if (ip != NULL)
+ PFREE(ip);
+ PFREE(ln);
+ return (result);
}
/*
- ** Distance from a point to a path
- */
-double *dist_ppath(Point *pt, PATH *path)
-{
- double *result;
- double *tmp;
- int i;
- LSEG lseg;
-
- switch (path->npts) {
- /* no points in path? then result is undefined... */
- case 0:
- result = NULL;
- break;
- /* one point in path? then get distance between two points... */
- case 1:
- result = point_distance(pt, &path->p[0]);
- break;
- default:
- /* make sure the path makes sense... */
- Assert(path->npts > 1);
- /*
- * the distance from a point to a path is the smallest distance
- * from the point to any of its constituent segments.
- */
- result = PALLOCTYPE(double);
- for (i = 0; i < path->npts - 1; i++) {
- statlseg_construct(&lseg, &path->p[i], &path->p[i+1]);
- tmp = dist_ps(pt, &lseg);
- if (i == 0 || *tmp < *result)
- *result = *tmp;
- PFREE(tmp);
+ ** Distance from a point to a path
+ */
+double *
+dist_ppath(Point * pt, PATH * path)
+{
+ double *result;
+ double *tmp;
+ int i;
+ LSEG lseg;
+
+ switch (path->npts)
+ {
+ /* no points in path? then result is undefined... */
+ case 0:
+ result = NULL;
+ break;
+ /* one point in path? then get distance between two points... */
+ case 1:
+ result = point_distance(pt, &path->p[0]);
+ break;
+ default:
+ /* make sure the path makes sense... */
+ Assert(path->npts > 1);
+
+ /*
+ * the distance from a point to a path is the smallest distance
+ * from the point to any of its constituent segments.
+ */
+ result = PALLOCTYPE(double);
+ for (i = 0; i < path->npts - 1; i++)
+ {
+ statlseg_construct(&lseg, &path->p[i], &path->p[i + 1]);
+ tmp = dist_ps(pt, &lseg);
+ if (i == 0 || *tmp < *result)
+ *result = *tmp;
+ PFREE(tmp);
+ }
+ break;
}
- break;
- }
- return(result);
+ return (result);
}
-double *dist_pb(Point *pt, BOX *box)
+double *
+dist_pb(Point * pt, BOX * box)
{
- Point *tmp;
- double *result;
-
- tmp = close_pb(pt, box);
- result = point_distance(tmp, pt);
- PFREE(tmp);
+ Point *tmp;
+ double *result;
+
+ tmp = close_pb(pt, box);
+ result = point_distance(tmp, pt);
+ PFREE(tmp);
- return(result);
+ return (result);
}
-double *dist_sl(LSEG *lseg, LINE *line)
+double *
+dist_sl(LSEG * lseg, LINE * line)
{
- double *result, *d2;
+ double *result,
+ *d2;
- if (inter_sl(lseg, line)) {
- result = PALLOCTYPE(double);
- *result = 0.0;
+ if (inter_sl(lseg, line))
+ {
+ result = PALLOCTYPE(double);
+ *result = 0.0;
- } else {
- result = dist_pl(&lseg->p[0], line);
- d2 = dist_pl(&lseg->p[1], line);
- if (*d2 > *result) {
- PFREE( result);
- result = d2;
- } else {
- PFREE( d2);
}
- }
-
- return(result);
+ else
+ {
+ result = dist_pl(&lseg->p[0], line);
+ d2 = dist_pl(&lseg->p[1], line);
+ if (*d2 > *result)
+ {
+ PFREE(result);
+ result = d2;
+ }
+ else
+ {
+ PFREE(d2);
+ }
+ }
+
+ return (result);
}
-double *dist_sb(LSEG *lseg, BOX *box)
+double *
+dist_sb(LSEG * lseg, BOX * box)
{
- Point *tmp;
- double *result;
-
- tmp = close_sb(lseg, box);
- if (tmp == NULL) {
- result = PALLOCTYPE(double);
- *result = 0.0;
- } else {
- result = dist_pb(tmp, box);
- PFREE(tmp);
- }
-
- return(result);
+ Point *tmp;
+ double *result;
+
+ tmp = close_sb(lseg, box);
+ if (tmp == NULL)
+ {
+ result = PALLOCTYPE(double);
+ *result = 0.0;
+ }
+ else
+ {
+ result = dist_pb(tmp, box);
+ PFREE(tmp);
+ }
+
+ return (result);
}
-double *dist_lb(LINE *line, BOX *box)
+double *
+dist_lb(LINE * line, BOX * box)
{
- Point *tmp;
- double *result;
-
- tmp = close_lb(line, box);
- if (tmp == NULL) {
- result = PALLOCTYPE(double);
- *result = 0.0;
- } else {
- result = dist_pb(tmp, box);
- PFREE(tmp);
- }
-
- return(result);
+ Point *tmp;
+ double *result;
+
+ tmp = close_lb(line, box);
+ if (tmp == NULL)
+ {
+ result = PALLOCTYPE(double);
+ *result = 0.0;
+ }
+ else
+ {
+ result = dist_pb(tmp, box);
+ PFREE(tmp);
+ }
+
+ return (result);
}
-double *
-dist_cpoly(CIRCLE *circle, POLYGON *poly)
+double *
+dist_cpoly(CIRCLE * circle, POLYGON * poly)
{
- double *result;
- int i;
- double *d;
- LSEG seg;
+ double *result;
+ int i;
+ double *d;
+ LSEG seg;
- if (!PointerIsValid(circle) || !PointerIsValid(poly))
- elog (WARN, "Invalid (null) input for distance", NULL);
+ if (!PointerIsValid(circle) || !PointerIsValid(poly))
+ elog(WARN, "Invalid (null) input for distance", NULL);
- if (point_inside( &(circle->center), poly->npts, poly->p)) {
+ if (point_inside(&(circle->center), poly->npts, poly->p))
+ {
#ifdef GEODEBUG
-printf( "dist_cpoly- center inside of polygon\n");
+ printf("dist_cpoly- center inside of polygon\n");
#endif
- result = PALLOCTYPE(double);
+ result = PALLOCTYPE(double);
- *result = 0;
- return(result);
- }
-
- /* initialize distance with segment between first and last points */
- seg.p[0].x = poly->p[0].x;
- seg.p[0].y = poly->p[0].y;
- seg.p[1].x = poly->p[poly->npts-1].x;
- seg.p[1].y = poly->p[poly->npts-1].y;
- result = dist_ps( &(circle->center), &seg);
+ *result = 0;
+ return (result);
+ }
+
+ /* initialize distance with segment between first and last points */
+ seg.p[0].x = poly->p[0].x;
+ seg.p[0].y = poly->p[0].y;
+ seg.p[1].x = poly->p[poly->npts - 1].x;
+ seg.p[1].y = poly->p[poly->npts - 1].y;
+ result = dist_ps(&(circle->center), &seg);
#ifdef GEODEBUG
-printf( "dist_cpoly- segment 0/n distance is %f\n", *result);
+ printf("dist_cpoly- segment 0/n distance is %f\n", *result);
#endif
- /* check distances for other segments */
- for (i = 0; (i < poly->npts - 1); i++) {
- seg.p[0].x = poly->p[i].x;
- seg.p[0].y = poly->p[i].y;
- seg.p[1].x = poly->p[i+1].x;
- seg.p[1].y = poly->p[i+1].y;
- d = dist_ps( &(circle->center), &seg);
+ /* check distances for other segments */
+ for (i = 0; (i < poly->npts - 1); i++)
+ {
+ seg.p[0].x = poly->p[i].x;
+ seg.p[0].y = poly->p[i].y;
+ seg.p[1].x = poly->p[i + 1].x;
+ seg.p[1].y = poly->p[i + 1].y;
+ d = dist_ps(&(circle->center), &seg);
#ifdef GEODEBUG
-printf( "dist_cpoly- segment %d distance is %f\n", (i+1), *d);
+ printf("dist_cpoly- segment %d distance is %f\n", (i + 1), *d);
#endif
- if (*d < *result) *result = *d;
- PFREE(d);
- }
+ if (*d < *result)
+ *result = *d;
+ PFREE(d);
+ }
- *result -= circle->radius;
- if (*result < 0) *result = 0;
+ *result -= circle->radius;
+ if (*result < 0)
+ *result = 0;
- return(result);
-} /* dist_cpoly() */
+ return (result);
+} /* dist_cpoly() */
/*---------------------------------------------------------------------
- * interpt_
- * Intersection point of objects.
- * We choose to ignore the "point" of intersection between
- * lines and boxes, since there are typically two.
+ * interpt_
+ * Intersection point of objects.
+ * We choose to ignore the "point" of intersection between
+ * lines and boxes, since there are typically two.
*-------------------------------------------------------------------*/
-static Point *interpt_sl(LSEG *lseg, LINE *line)
+static Point *
+interpt_sl(LSEG * lseg, LINE * line)
{
- LINE *tmp;
- Point *p;
-
- tmp = line_construct_pp(&lseg->p[0], &lseg->p[1]);
- p = line_interpt(tmp, line);
+ LINE *tmp;
+ Point *p;
+
+ tmp = line_construct_pp(&lseg->p[0], &lseg->p[1]);
+ p = line_interpt(tmp, line);
#ifdef GEODEBUG
-printf( "interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
- digits8, lseg->p[0].x, digits8, lseg->p[0].y, digits8, lseg->p[1].x, digits8, lseg->p[1].y);
-printf( "interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
- digits8, tmp->A, digits8, tmp->B, digits8, tmp->C);
+ printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
+ digits8, lseg->p[0].x, digits8, lseg->p[0].y, digits8, lseg->p[1].x, digits8, lseg->p[1].y);
+ printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
+ digits8, tmp->A, digits8, tmp->B, digits8, tmp->C);
#endif
- if (PointerIsValid(p)) {
+ if (PointerIsValid(p))
+ {
#ifdef GEODEBUG
-printf( "interpt_sl- intersection point is (%.*g %.*g)\n", digits8, p->x, digits8, p->y);
+ printf("interpt_sl- intersection point is (%.*g %.*g)\n", digits8, p->x, digits8, p->y);
#endif
- if (on_ps(p, lseg)) {
+ if (on_ps(p, lseg))
+ {
#ifdef GEODEBUG
-printf( "interpt_sl- intersection point is on segment\n");
+ printf("interpt_sl- intersection point is on segment\n");
#endif
- } else {
- PFREE(p);
- p = NULL;
+ }
+ else
+ {
+ PFREE(p);
+ p = NULL;
+ }
}
- }
-
- PFREE(tmp);
- return(p);
+
+ PFREE(tmp);
+ return (p);
}
/*---------------------------------------------------------------------
- * close_
- * Point of closest proximity between objects.
+ * close_
+ * Point of closest proximity between objects.
*-------------------------------------------------------------------*/
-/* close_pl -
- * The intersection point of a perpendicular of the line
- * through the point.
+/* close_pl -
+ * The intersection point of a perpendicular of the line
+ * through the point.
*/
-Point *close_pl(Point *pt, LINE *line)
+Point *
+close_pl(Point * pt, LINE * line)
{
- Point *result;
- LINE *tmp;
- double invm;
-
- result = PALLOCTYPE(Point);
+ Point *result;
+ LINE *tmp;
+ double invm;
+
+ result = PALLOCTYPE(Point);
#if FALSE
- if (FPeq(line->A, -1.0) && FPzero(line->B)) { /* vertical */
- }
+ if (FPeq(line->A, -1.0) && FPzero(line->B))
+ { /* vertical */
+ }
#endif
- if (line_vertical(line)) {
- result->x = line->C;
- result->y = pt->y;
- return(result);
+ if (line_vertical(line))
+ {
+ result->x = line->C;
+ result->y = pt->y;
+ return (result);
#if FALSE
- } else if (FPzero(line->m)) { /* horizontal */
+ }
+ else if (FPzero(line->m))
+ { /* horizontal */
#endif
- } else if (line_horizontal(line)) {
- result->x = pt->x;
- result->y = line->C;
- return(result);
- }
- /* drop a perpendicular and find the intersection point */
+ }
+ else if (line_horizontal(line))
+ {
+ result->x = pt->x;
+ result->y = line->C;
+ return (result);
+ }
+ /* drop a perpendicular and find the intersection point */
#if FALSE
- invm = -1.0 / line->m;
+ invm = -1.0 / line->m;
#endif
- /* invert and flip the sign on the slope to get a perpendicular */
- invm = line->B / line->A;
- tmp = line_construct_pm(pt, invm);
- result = line_interpt(tmp, line);
- return(result);
-} /* close_pl() */
-
-
-/* close_ps -
- * Take the closest endpoint if the point is left, right,
- * above, or below the segment, otherwise find the intersection
- * point of the segment and its perpendicular through the point.
- */
-Point *close_ps(Point *pt, LSEG *lseg)
-{
- Point *result;
- LINE *tmp;
- double invm;
- int xh, yh;
-
- result = NULL;
- xh = lseg->p[0].x < lseg->p[1].x;
- yh = lseg->p[0].y < lseg->p[1].y;
- if (pt->x < lseg->p[!xh].x)
- result = point_copy(&lseg->p[!xh]);
- else if (pt->x > lseg->p[xh].x)
- result = point_copy(&lseg->p[xh]);
- else if (pt->y < lseg->p[!yh].y)
- result = point_copy(&lseg->p[!yh]);
- else if (pt->y > lseg->p[yh].y)
- result = point_copy(&lseg->p[yh]);
- if (result)
- return(result);
+ /* invert and flip the sign on the slope to get a perpendicular */
+ invm = line->B / line->A;
+ tmp = line_construct_pm(pt, invm);
+ result = line_interpt(tmp, line);
+ return (result);
+} /* close_pl() */
+
+
+/* close_ps -
+ * Take the closest endpoint if the point is left, right,
+ * above, or below the segment, otherwise find the intersection
+ * point of the segment and its perpendicular through the point.
+ */
+Point *
+close_ps(Point * pt, LSEG * lseg)
+{
+ Point *result;
+ LINE *tmp;
+ double invm;
+ int xh,
+ yh;
+
+ result = NULL;
+ xh = lseg->p[0].x < lseg->p[1].x;
+ yh = lseg->p[0].y < lseg->p[1].y;
+ if (pt->x < lseg->p[!xh].x)
+ result = point_copy(&lseg->p[!xh]);
+ else if (pt->x > lseg->p[xh].x)
+ result = point_copy(&lseg->p[xh]);
+ else if (pt->y < lseg->p[!yh].y)
+ result = point_copy(&lseg->p[!yh]);
+ else if (pt->y > lseg->p[yh].y)
+ result = point_copy(&lseg->p[yh]);
+ if (result)
+ return (result);
#if FALSE
- if (FPeq(lseg->p[0].x, lseg->p[1].x)) /* vertical */
+ if (FPeq(lseg->p[0].x, lseg->p[1].x)) /* vertical */
#endif
- if (lseg_vertical(lseg)) {
- result->x = lseg->p[0].x;
- result->y = pt->y;
- return(result);
+ if (lseg_vertical(lseg))
+ {
+ result->x = lseg->p[0].x;
+ result->y = pt->y;
+ return (result);
#if FALSE
- } else if (FPzero(lseg->m)) { /* horizontal */
+ }
+ else if (FPzero(lseg->m))
+ { /* horizontal */
#endif
- } else if (lseg_horizontal(lseg)) {
- result->x = pt->x;
- result->y = lseg->p[0].y;
- return(result);
- }
-
+ }
+ else if (lseg_horizontal(lseg))
+ {
+ result->x = pt->x;
+ result->y = lseg->p[0].y;
+ return (result);
+ }
+
#if FALSE
- invm = -1.0 / lseg->m;
+ invm = -1.0 / lseg->m;
#endif
- invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
- tmp = line_construct_pm(pt, invm);
- result = interpt_sl(lseg, tmp);
- return(result);
-} /* close_ps() */
+ invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
+ tmp = line_construct_pm(pt, invm);
+ result = interpt_sl(lseg, tmp);
+ return (result);
+} /* close_ps() */
-Point *close_pb(Point *pt, BOX *box)
+Point *
+close_pb(Point * pt, BOX * box)
{
- /* think about this one for a while */
- elog(WARN, "close_pb not implemented", NULL);
+ /* think about this one for a while */
+ elog(WARN, "close_pb not implemented", NULL);
- return(NULL);
+ return (NULL);
}
-Point *close_sl(LSEG *lseg, LINE *line)
+Point *
+close_sl(LSEG * lseg, LINE * line)
{
- Point *result;
- double *d1, *d2;
+ Point *result;
+ double *d1,
+ *d2;
- result = interpt_sl(lseg, line);
- if (result)
- return(result);
- d1 = dist_pl(&lseg->p[0], line);
- d2 = dist_pl(&lseg->p[1], line);
- if (d1 < d2)
- result = point_copy(&lseg->p[0]);
- else
- result = point_copy(&lseg->p[1]);
-
- PFREE(d1);
- PFREE(d2);
- return(result);
+ result = interpt_sl(lseg, line);
+ if (result)
+ return (result);
+ d1 = dist_pl(&lseg->p[0], line);
+ d2 = dist_pl(&lseg->p[1], line);
+ if (d1 < d2)
+ result = point_copy(&lseg->p[0]);
+ else
+ result = point_copy(&lseg->p[1]);
+
+ PFREE(d1);
+ PFREE(d2);
+ return (result);
}
-Point *close_sb(LSEG *lseg, BOX *box)
+Point *
+close_sb(LSEG * lseg, BOX * box)
{
- /* think about this one for a while */
- elog(WARN, "close_sb not implemented", NULL);
+ /* think about this one for a while */
+ elog(WARN, "close_sb not implemented", NULL);
- return(NULL);
+ return (NULL);
}
-Point *close_lb(LINE *line, BOX *box)
+Point *
+close_lb(LINE * line, BOX * box)
{
- /* think about this one for a while */
- elog(WARN, "close_lb not implemented", NULL);
+ /* think about this one for a while */
+ elog(WARN, "close_lb not implemented", NULL);
- return(NULL);
+ return (NULL);
}
/*---------------------------------------------------------------------
- * on_
- * Whether one object lies completely within another.
+ * on_
+ * Whether one object lies completely within another.
*-------------------------------------------------------------------*/
/* on_pl -
- * Does the point satisfy the equation?
+ * Does the point satisfy the equation?
*/
-bool on_pl(Point *pt, LINE *line)
+bool
+on_pl(Point * pt, LINE * line)
{
- if (!PointerIsValid(pt) || !PointerIsValid(line))
- return(FALSE);
+ if (!PointerIsValid(pt) || !PointerIsValid(line))
+ return (FALSE);
- return( FPzero(line->A * pt->x + line->B * pt->y + line->C) );
+ return (FPzero(line->A * pt->x + line->B * pt->y + line->C));
}
/* on_ps -
- * Determine colinearity by detecting a triangle inequality.
+ * Determine colinearity by detecting a triangle inequality.
* This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
*/
-bool on_ps(Point *pt, LSEG *lseg)
+bool
+on_ps(Point * pt, LSEG * lseg)
{
- if (!PointerIsValid(pt) || !PointerIsValid(lseg))
- return(FALSE);
+ if (!PointerIsValid(pt) || !PointerIsValid(lseg))
+ return (FALSE);
- return( FPeq (point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
- point_dt(&lseg->p[0], &lseg->p[1])) );
+ return (FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
+ point_dt(&lseg->p[0], &lseg->p[1])));
}
-bool on_pb(Point *pt, BOX *box)
+bool
+on_pb(Point * pt, BOX * box)
{
- if (!PointerIsValid(pt) || !PointerIsValid(box))
- return(FALSE);
+ if (!PointerIsValid(pt) || !PointerIsValid(box))
+ return (FALSE);
- return( pt->x <= box->high.x && pt->x >= box->low.x &&
- pt->y <= box->high.y && pt->y >= box->low.y );
+ return (pt->x <= box->high.x && pt->x >= box->low.x &&
+ pt->y <= box->high.y && pt->y >= box->low.y);
}
-/* on_ppath -
- * Whether a point lies within (on) a polyline.
- * If open, we have to (groan) check each segment.
+/* on_ppath -
+ * Whether a point lies within (on) a polyline.
+ * If open, we have to (groan) check each segment.
* (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
- * If closed, we use the old O(n) ray method for point-in-polygon.
- * The ray is horizontal, from pt out to the right.
- * Each segment that crosses the ray counts as an
- * intersection; note that an endpoint or edge may touch
- * but not cross.
- * (we can do p-in-p in lg(n), but it takes preprocessing)
+ * If closed, we use the old O(n) ray method for point-in-polygon.
+ * The ray is horizontal, from pt out to the right.
+ * Each segment that crosses the ray counts as an
+ * intersection; note that an endpoint or edge may touch
+ * but not cross.
+ * (we can do p-in-p in lg(n), but it takes preprocessing)
*/
-#define NEXT(A) ((A+1) % path->npts) /* cyclic "i+1" */
+#define NEXT(A) ((A+1) % path->npts) /* cyclic "i+1" */
-bool on_ppath(Point *pt, PATH *path)
+bool
+on_ppath(Point * pt, PATH * path)
{
#if FALSE
- int above, next, /* is the seg above the ray? */
- inter, /* # of times path crosses ray */
- hi; /* index inc of higher seg (0,1) */
- double x, yh, yl, xh, xl;
+ int above,
+ next, /* is the seg above the ray? */
+ inter, /* # of times path crosses ray */
+ hi; /* index inc of higher seg (0,1) */
+ double x,
+ yh,
+ yl,
+ xh,
+ xl;
+
#endif
- int i, n;
- double a, b;
-
- if (!PointerIsValid(pt) || !PointerIsValid(path))
- return(FALSE);
-
- if (! path->closed) { /*-- OPEN --*/
- n = path->npts - 1;
- a = point_dt(pt, &path->p[0]);
- for (i = 0; i < n; i++) {
- b = point_dt(pt, &path->p[i+1]);
- if (FPeq(a+b,
- point_dt(&path->p[i], &path->p[i+1])))
- return(1);
- a = b;
- }
- return(0);
- }
-
- return(point_inside( pt, path->npts, path->p));
+ int i,
+ n;
+ double a,
+ b;
+
+ if (!PointerIsValid(pt) || !PointerIsValid(path))
+ return (FALSE);
+
+ if (!path->closed)
+ { /*-- OPEN --*/
+ n = path->npts - 1;
+ a = point_dt(pt, &path->p[0]);
+ for (i = 0; i < n; i++)
+ {
+ b = point_dt(pt, &path->p[i + 1]);
+ if (FPeq(a + b,
+ point_dt(&path->p[i], &path->p[i + 1])))
+ return (1);
+ a = b;
+ }
+ return (0);
+ }
+
+ return (point_inside(pt, path->npts, path->p));
#if FALSE
- inter = 0; /*-- CLOSED --*/
- above = FPgt(path->p[0].y, pt->y) ? ABOVE :
- FPlt(path->p[0].y, pt->y) ? BELOW : UNDEF;
-
- for (i = 0; i < path->npts; i++) {
- hi = path->p[i].y < path->p[NEXT(i)].y;
- /* must take care of wrap around to original vertex for closed paths */
- yh = (i+hi < path->npts) ? path->p[i+hi].y : path->p[0].y;
- yl = (i+!hi < path->npts) ? path->p[i+!hi].y : path->p[0].y;
- hi = path->p[i].x < path->p[NEXT(i)].x;
- xh = (i+hi < path->npts) ? path->p[i+hi].x : path->p[0].x;
- xl = (i+!hi < path->npts) ? path->p[i+!hi].x : path->p[0].x;
- /* skip seg if it doesn't touch the ray */
-
- if (FPeq(yh, yl)) /* horizontal seg? */
- if (FPge(pt->x, xl) && FPle(pt->x, xh) &&
- FPeq(pt->y, yh))
- return(1); /* pt lies on seg */
- else
- continue; /* skip other hz segs */
- if (FPlt(yh, pt->y) || /* pt is strictly below seg */
- FPgt(yl, pt->y)) /* strictly above */
- continue;
-
- /* seg touches the ray, find out where */
-
- x = FPeq(xh, xl) /* vertical seg? */
- ? path->p[i].x
- : (pt->y - path->p[i].y) /
- point_sl(&path->p[i],
- &path->p[NEXT(i)]) +
- path->p[i].x;
- if (FPeq(x, pt->x)) /* pt lies on this seg */
- return(1);
-
- /* does the seg actually cross the ray? */
-
- next = FPgt(path->p[NEXT(i)].y, pt->y) ? ABOVE :
- FPlt(path->p[NEXT(i)].y, pt->y) ? BELOW : above;
- inter += FPge(x, pt->x) && next != above;
- above = next;
- }
- return( above == UNDEF || /* path is horizontal */
- inter % 2); /* odd # of intersections */
+ inter = 0; /*-- CLOSED --*/
+ above = FPgt(path->p[0].y, pt->y) ? ABOVE :
+ FPlt(path->p[0].y, pt->y) ? BELOW : UNDEF;
+
+ for (i = 0; i < path->npts; i++)
+ {
+ hi = path->p[i].y < path->p[NEXT(i)].y;
+
+ /*
+ * must take care of wrap around to original vertex for closed
+ * paths
+ */
+ yh = (i + hi < path->npts) ? path->p[i + hi].y : path->p[0].y;
+ yl = (i + !hi < path->npts) ? path->p[i + !hi].y : path->p[0].y;
+ hi = path->p[i].x < path->p[NEXT(i)].x;
+ xh = (i + hi < path->npts) ? path->p[i + hi].x : path->p[0].x;
+ xl = (i + !hi < path->npts) ? path->p[i + !hi].x : path->p[0].x;
+ /* skip seg if it doesn't touch the ray */
+
+ if (FPeq(yh, yl)) /* horizontal seg? */
+ if (FPge(pt->x, xl) && FPle(pt->x, xh) &&
+ FPeq(pt->y, yh))
+ return (1); /* pt lies on seg */
+ else
+ continue; /* skip other hz segs */
+ if (FPlt(yh, pt->y) || /* pt is strictly below seg */
+ FPgt(yl, pt->y)) /* strictly above */
+ continue;
+
+ /* seg touches the ray, find out where */
+
+ x = FPeq(xh, xl) /* vertical seg? */
+ ? path->p[i].x
+ : (pt->y - path->p[i].y) /
+ point_sl(&path->p[i],
+ &path->p[NEXT(i)]) +
+ path->p[i].x;
+ if (FPeq(x, pt->x)) /* pt lies on this seg */
+ return (1);
+
+ /* does the seg actually cross the ray? */
+
+ next = FPgt(path->p[NEXT(i)].y, pt->y) ? ABOVE :
+ FPlt(path->p[NEXT(i)].y, pt->y) ? BELOW : above;
+ inter += FPge(x, pt->x) && next != above;
+ above = next;
+ }
+ return (above == UNDEF || /* path is horizontal */
+ inter % 2); /* odd # of intersections */
#endif
-} /* on_ppath() */
+} /* on_ppath() */
-bool on_sl(LSEG *lseg, LINE *line)
+bool
+on_sl(LSEG * lseg, LINE * line)
{
- if (!PointerIsValid(lseg) || !PointerIsValid(line))
- return(FALSE);
+ if (!PointerIsValid(lseg) || !PointerIsValid(line))
+ return (FALSE);
- return( on_pl(&lseg->p[0], line) && on_pl(&lseg->p[1], line) );
-} /* on_sl() */
+ return (on_pl(&lseg->p[0], line) && on_pl(&lseg->p[1], line));
+} /* on_sl() */
-bool on_sb(LSEG *lseg, BOX *box)
+bool
+on_sb(LSEG * lseg, BOX * box)
{
- if (!PointerIsValid(lseg) || !PointerIsValid(box))
- return(FALSE);
+ if (!PointerIsValid(lseg) || !PointerIsValid(box))
+ return (FALSE);
- return( on_pb(&lseg->p[0], box) && on_pb(&lseg->p[1], box) );
-} /* on_sb() */
+ return (on_pb(&lseg->p[0], box) && on_pb(&lseg->p[1], box));
+} /* on_sb() */
/*---------------------------------------------------------------------
- * inter_
- * Whether one object intersects another.
+ * inter_
+ * Whether one object intersects another.
*-------------------------------------------------------------------*/
-bool inter_sl(LSEG *lseg, LINE *line)
+bool
+inter_sl(LSEG * lseg, LINE * line)
{
- Point *tmp;
+ Point *tmp;
- if (!PointerIsValid(lseg) || !PointerIsValid(line))
- return(FALSE);
+ if (!PointerIsValid(lseg) || !PointerIsValid(line))
+ return (FALSE);
- tmp = interpt_sl(lseg, line);
- if (tmp) {
- PFREE(tmp);
- return(1);
- }
- return(0);
+ tmp = interpt_sl(lseg, line);
+ if (tmp)
+ {
+ PFREE(tmp);
+ return (1);
+ }
+ return (0);
}
/* XXX segment and box should be able to intersect; tgl - 97/01/09 */
-bool inter_sb(LSEG *lseg, BOX *box)
+bool
+inter_sb(LSEG * lseg, BOX * box)
{
- return(0);
+ return (0);
}
/* XXX line and box should be able to intersect; tgl - 97/01/09 */
-bool inter_lb(LINE *line, BOX *box)
+bool
+inter_lb(LINE * line, BOX * box)
{
- return(0);
+ return (0);
}
/*------------------------------------------------------------------
* The following routines define a data type and operator class for
- * POLYGONS .... Part of which (the polygon's bounding box) is built on
+ * POLYGONS .... Part of which (the polygon's bounding box) is built on
* top of the BOX data type.
*
* make_bound_box - create the bounding box for the input polygon
@@ -2220,77 +2490,91 @@ bool inter_lb(LINE *line, BOX *box)
/*---------------------------------------------------------------------
* Make the smallest bounding box for the given polygon.
*---------------------------------------------------------------------*/
-static void make_bound_box(POLYGON *poly)
-{
- int i;
- double x1,y1,x2,y2;
+static void
+make_bound_box(POLYGON * poly)
+{
+ int i;
+ double x1,
+ y1,
+ x2,
+ y2;
+
+ if (poly->npts > 0)
+ {
+ x2 = x1 = poly->p[0].x;
+ y2 = y1 = poly->p[0].y;
+ for (i = 1; i < poly->npts; i++)
+ {
+ if (poly->p[i].x < x1)
+ x1 = poly->p[i].x;
+ if (poly->p[i].x > x2)
+ x2 = poly->p[i].x;
+ if (poly->p[i].y < y1)
+ y1 = poly->p[i].y;
+ if (poly->p[i].y > y2)
+ y2 = poly->p[i].y;
+ }
- if (poly->npts > 0) {
- x2 = x1 = poly->p[0].x;
- y2 = y1 = poly->p[0].y;
- for (i = 1; i < poly->npts; i++) {
- if (poly->p[i].x < x1) x1 = poly->p[i].x;
- if (poly->p[i].x > x2) x2 = poly->p[i].x;
- if (poly->p[i].y < y1) y1 = poly->p[i].y;
- if (poly->p[i].y > y2) y2 = poly->p[i].y;
+ box_fill(&(poly->boundbox), x1, x2, y1, y2);
+ }
+ else
+ {
+ elog(WARN, "Unable to create bounding box for empty polygon", NULL);
}
-
- box_fill(&(poly->boundbox), x1, x2, y1, y2);
- } else {
- elog (WARN, "Unable to create bounding box for empty polygon", NULL);
- }
}
/*------------------------------------------------------------------
* poly_in - read in the polygon from a string specification
*
- * External format:
- * "((x0,y0),...,(xn,yn))"
- * "x0,y0,...,xn,yn"
- * also supports the older style "(x1,...,xn,y1,...yn)"
+ * External format:
+ * "((x0,y0),...,(xn,yn))"
+ * "x0,y0,...,xn,yn"
+ * also supports the older style "(x1,...,xn,y1,...yn)"
*------------------------------------------------------------------*/
-POLYGON *poly_in(char *str)
+POLYGON *
+poly_in(char *str)
{
- POLYGON *poly;
- int npts;
- int size;
- int isopen;
- char *s;
+ POLYGON *poly;
+ int npts;
+ int size;
+ int isopen;
+ char *s;
- if (!PointerIsValid(str))
- elog (WARN," Bad (null) polygon external representation");
+ if (!PointerIsValid(str))
+ elog(WARN, " Bad (null) polygon external representation");
- if ((npts = pair_count(str, ',')) <= 0)
- elog(WARN, "Bad polygon external representation '%s'", str);
+ if ((npts = pair_count(str, ',')) <= 0)
+ elog(WARN, "Bad polygon external representation '%s'", str);
- size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * npts);
- poly = PALLOC(size);
+ size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * npts);
+ poly = PALLOC(size);
- memset((char *) poly, 0, size); /* zero any holes */
- poly->size = size;
- poly->npts = npts;
+ memset((char *) poly, 0, size); /* zero any holes */
+ poly->size = size;
+ poly->npts = npts;
- if ((! path_decode(FALSE, npts, str, &isopen, &s, &(poly->p[0])))
- || (*s != '\0'))
- elog (WARN, "Bad polygon external representation '%s'",str);
+ if ((!path_decode(FALSE, npts, str, &isopen, &s, &(poly->p[0])))
+ || (*s != '\0'))
+ elog(WARN, "Bad polygon external representation '%s'", str);
- make_bound_box(poly);
+ make_bound_box(poly);
- return( poly);
-} /* poly_in() */
+ return (poly);
+} /* poly_in() */
/*---------------------------------------------------------------
- * poly_out - convert internal POLYGON representation to the
- * character string format "((f8,f8),...,(f8,f8))"
- * also support old format "(f8,f8,...,f8,f8)"
+ * poly_out - convert internal POLYGON representation to the
+ * character string format "((f8,f8),...,(f8,f8))"
+ * also support old format "(f8,f8,...,f8,f8)"
*---------------------------------------------------------------*/
-char *poly_out(POLYGON *poly)
+char *
+poly_out(POLYGON * poly)
{
- if (!PointerIsValid(poly))
- return NULL;
+ if (!PointerIsValid(poly))
+ return NULL;
- return( path_encode( TRUE, poly->npts, &(poly->p[0])));
-} /* poly_out() */
+ return (path_encode(TRUE, poly->npts, &(poly->p[0])));
+} /* poly_out() */
/*-------------------------------------------------------
@@ -2298,9 +2582,10 @@ char *poly_out(POLYGON *poly)
* the right most point of A left of the left most point
* of B?
*-------------------------------------------------------*/
-bool poly_left(POLYGON *polya, POLYGON *polyb)
+bool
+poly_left(POLYGON * polya, POLYGON * polyb)
{
- return (polya->boundbox.high.x < polyb->boundbox.low.x);
+ return (polya->boundbox.high.x < polyb->boundbox.low.x);
}
/*-------------------------------------------------------
@@ -2308,9 +2593,10 @@ bool poly_left(POLYGON *polya, POLYGON *polyb)
* the left most point of A left of the right most point
* of B?
*-------------------------------------------------------*/
-bool poly_overleft(POLYGON *polya, POLYGON *polyb)
+bool
+poly_overleft(POLYGON * polya, POLYGON * polyb)
{
- return (polya->boundbox.low.x <= polyb->boundbox.high.x);
+ return (polya->boundbox.low.x <= polyb->boundbox.high.x);
}
/*-------------------------------------------------------
@@ -2318,9 +2604,10 @@ bool poly_overleft(POLYGON *polya, POLYGON *polyb)
* the left most point of A right of the right most point
* of B?
*-------------------------------------------------------*/
-bool poly_right(POLYGON *polya, POLYGON *polyb)
+bool
+poly_right(POLYGON * polya, POLYGON * polyb)
{
- return( polya->boundbox.low.x > polyb->boundbox.high.x);
+ return (polya->boundbox.low.x > polyb->boundbox.high.x);
}
/*-------------------------------------------------------
@@ -2328,45 +2615,49 @@ bool poly_right(POLYGON *polya, POLYGON *polyb)
* the right most point of A right of the left most point
* of B?
*-------------------------------------------------------*/
-bool poly_overright(POLYGON *polya, POLYGON *polyb)
+bool
+poly_overright(POLYGON * polya, POLYGON * polyb)
{
- return( polya->boundbox.high.x > polyb->boundbox.low.x);
+ return (polya->boundbox.high.x > polyb->boundbox.low.x);
}
/*-------------------------------------------------------
* Is polygon A the same as polygon B? i.e. are all the
* points the same?
* Check all points for matches in both forward and reverse
- * direction since polygons are non-directional and are
- * closed shapes.
+ * direction since polygons are non-directional and are
+ * closed shapes.
*-------------------------------------------------------*/
-bool poly_same(POLYGON *polya, POLYGON *polyb)
+bool
+poly_same(POLYGON * polya, POLYGON * polyb)
{
- if (! PointerIsValid( polya) || ! PointerIsValid( polyb))
- return FALSE;
+ if (!PointerIsValid(polya) || !PointerIsValid(polyb))
+ return FALSE;
- if (polya->npts != polyb->npts)
- return FALSE;
+ if (polya->npts != polyb->npts)
+ return FALSE;
- return(plist_same( polya->npts, polya->p, polyb->p));
+ return (plist_same(polya->npts, polya->p, polyb->p));
#if FALSE
- for (i = 0; i < polya->npts; i++) {
- if ((polya->p[i].x != polyb->p[i].x)
- || (polya->p[i].y != polyb->p[i].y))
- return FALSE;
- }
- return TRUE;
+ for (i = 0; i < polya->npts; i++)
+ {
+ if ((polya->p[i].x != polyb->p[i].x)
+ || (polya->p[i].y != polyb->p[i].y))
+ return FALSE;
+ }
+ return TRUE;
#endif
-} /* poly_same() */
+} /* poly_same() */
/*-----------------------------------------------------------------
* Determine if polygon A overlaps polygon B by determining if
* their bounding boxes overlap.
*-----------------------------------------------------------------*/
-bool poly_overlap(POLYGON *polya, POLYGON *polyb)
+bool
+poly_overlap(POLYGON * polya, POLYGON * polyb)
{
- return box_overlap(&(polya->boundbox), &(polyb->boundbox));
+ return box_overlap(&(polya->boundbox), &(polyb->boundbox));
}
@@ -2375,484 +2666,504 @@ bool poly_overlap(POLYGON *polya, POLYGON *polyb)
* bounding box contains B's bounding box.
*-----------------------------------------------------------------*/
#if FALSE
-bool poly_contain(POLYGON *polya, POLYGON *polyb)
+bool
+poly_contain(POLYGON * polya, POLYGON * polyb)
{
- return box_contain(&(polya->boundbox), &(polyb->boundbox));
+ return box_contain(&(polya->boundbox), &(polyb->boundbox));
}
+
#endif
bool
-poly_contain(POLYGON *polya, POLYGON *polyb)
+poly_contain(POLYGON * polya, POLYGON * polyb)
{
- int i;
+ int i;
- if (!PointerIsValid(polya) || !PointerIsValid(polyb))
- return(FALSE);
+ if (!PointerIsValid(polya) || !PointerIsValid(polyb))
+ return (FALSE);
- if (box_contain(&(polya->boundbox), &(polyb->boundbox))) {
- for (i = 0; i < polyb->npts; i++) {
- if (point_inside(&(polyb->p[i]), polya->npts, &(polya->p[0])) == 0) {
+ if (box_contain(&(polya->boundbox), &(polyb->boundbox)))
+ {
+ for (i = 0; i < polyb->npts; i++)
+ {
+ if (point_inside(&(polyb->p[i]), polya->npts, &(polya->p[0])) == 0)
+ {
#if GEODEBUG
-printf( "poly_contain- point (%f,%f) not in polygon\n", polyb->p[i].x, polyb->p[i].y);
+ printf("poly_contain- point (%f,%f) not in polygon\n", polyb->p[i].x, polyb->p[i].y);
#endif
- return(FALSE);
- }
- }
- for (i = 0; i < polya->npts; i++) {
- if (point_inside(&(polya->p[i]), polyb->npts, &(polyb->p[0])) == 1) {
+ return (FALSE);
+ }
+ }
+ for (i = 0; i < polya->npts; i++)
+ {
+ if (point_inside(&(polya->p[i]), polyb->npts, &(polyb->p[0])) == 1)
+ {
#if GEODEBUG
-printf( "poly_contain- point (%f,%f) in polygon\n", polya->p[i].x, polya->p[i].y);
+ printf("poly_contain- point (%f,%f) in polygon\n", polya->p[i].x, polya->p[i].y);
#endif
- return(FALSE);
- }
+ return (FALSE);
+ }
+ }
+ return (TRUE);
}
- return(TRUE);
- }
#if GEODEBUG
-printf( "poly_contain- bound box ((%f,%f),(%f,%f)) not inside ((%f,%f),(%f,%f))\n",
- polyb->boundbox.low.x,polyb->boundbox.low.y,polyb->boundbox.high.x,polyb->boundbox.high.y,
- polya->boundbox.low.x,polya->boundbox.low.y,polya->boundbox.high.x,polya->boundbox.high.y);
+ printf("poly_contain- bound box ((%f,%f),(%f,%f)) not inside ((%f,%f),(%f,%f))\n",
+ polyb->boundbox.low.x, polyb->boundbox.low.y, polyb->boundbox.high.x, polyb->boundbox.high.y,
+ polya->boundbox.low.x, polya->boundbox.low.y, polya->boundbox.high.x, polya->boundbox.high.y);
#endif
- return(FALSE);
-} /* poly_contain() */
+ return (FALSE);
+} /* poly_contain() */
/*-----------------------------------------------------------------
- * Determine if polygon A is contained by polygon B by determining
+ * Determine if polygon A is contained by polygon B by determining
* if A's bounding box is contained by B's bounding box.
*-----------------------------------------------------------------*/
#if FALSE
-bool poly_contained(POLYGON *polya, POLYGON *polyb)
+bool
+poly_contained(POLYGON * polya, POLYGON * polyb)
{
- return(box_contained(&(polya->boundbox), &(polyb->boundbox)));
+ return (box_contained(&(polya->boundbox), &(polyb->boundbox)));
}
+
#endif
-bool poly_contained(POLYGON *polya, POLYGON *polyb)
+bool
+poly_contained(POLYGON * polya, POLYGON * polyb)
{
- return(poly_contain(polyb, polya));
-} /* poly_contained() */
+ return (poly_contain(polyb, polya));
+} /* poly_contained() */
/* poly_contain_pt()
* Test to see if the point is inside the polygon.
* Code adapted from integer-based routines in
- * Wn: A Server for the HTTP
- * File: wn/image.c
- * Version 1.15.1
- * Copyright (C) 1995 <by John Franks>
+ * Wn: A Server for the HTTP
+ * File: wn/image.c
+ * Version 1.15.1
+ * Copyright (C) 1995 <by John Franks>
* (code offered for use by J. Franks in Linux Journal letter.)
*/
bool
-poly_contain_pt( POLYGON *poly, Point *p)
+poly_contain_pt(POLYGON * poly, Point * p)
{
- if (!PointerIsValid(poly) || !PointerIsValid(p))
- return(FALSE);
+ if (!PointerIsValid(poly) || !PointerIsValid(p))
+ return (FALSE);
- return(point_inside(p, poly->npts, &(poly->p[0])) != 0);
-} /* poly_contain_pt() */
+ return (point_inside(p, poly->npts, &(poly->p[0])) != 0);
+} /* poly_contain_pt() */
bool
-pt_contained_poly( Point *p, POLYGON *poly)
+pt_contained_poly(Point * p, POLYGON * poly)
{
- if (!PointerIsValid(p) || !PointerIsValid(poly))
- return(FALSE);
+ if (!PointerIsValid(p) || !PointerIsValid(poly))
+ return (FALSE);
- return(poly_contain_pt( poly, p));
-} /* pt_contained_poly() */
+ return (poly_contain_pt(poly, p));
+} /* pt_contained_poly() */
-double *
-poly_distance( POLYGON *polya, POLYGON *polyb)
+double *
+poly_distance(POLYGON * polya, POLYGON * polyb)
{
- double *result;
+ double *result;
- if (!PointerIsValid(polya) || !PointerIsValid(polyb))
- return(NULL);
+ if (!PointerIsValid(polya) || !PointerIsValid(polyb))
+ return (NULL);
- result = PALLOCTYPE(double);
+ result = PALLOCTYPE(double);
- *result = 0;
+ *result = 0;
- return(result);
-} /* poly_distance() */
+ return (result);
+} /* poly_distance() */
/***********************************************************************
**
- ** Routines for 2D points.
+ ** Routines for 2D points.
**
***********************************************************************/
-Point *
-point(float8 *x, float8 *y)
+Point *
+point(float8 * x, float8 * y)
{
- if (! (PointerIsValid(x) && PointerIsValid(y)))
- return(NULL);
+ if (!(PointerIsValid(x) && PointerIsValid(y)))
+ return (NULL);
- return(point_construct(*x, *y));
-} /* point() */
+ return (point_construct(*x, *y));
+} /* point() */
-Point *
-point_add(Point *p1, Point *p2)
+Point *
+point_add(Point * p1, Point * p2)
{
- Point *result;
+ Point *result;
- if (! (PointerIsValid(p1) && PointerIsValid(p2)))
- return(NULL);
+ if (!(PointerIsValid(p1) && PointerIsValid(p2)))
+ return (NULL);
- result = PALLOCTYPE(Point);
+ result = PALLOCTYPE(Point);
- result->x = (p1->x + p2->x);
- result->y = (p1->y + p2->y);
+ result->x = (p1->x + p2->x);
+ result->y = (p1->y + p2->y);
- return(result);
-} /* point_add() */
+ return (result);
+} /* point_add() */
-Point *
-point_sub(Point *p1, Point *p2)
+Point *
+point_sub(Point * p1, Point * p2)
{
- Point *result;
+ Point *result;
- if (! (PointerIsValid(p1) && PointerIsValid(p2)))
- return(NULL);
+ if (!(PointerIsValid(p1) && PointerIsValid(p2)))
+ return (NULL);
- result = PALLOCTYPE(Point);
+ result = PALLOCTYPE(Point);
- result->x = (p1->x - p2->x);
- result->y = (p1->y - p2->y);
+ result->x = (p1->x - p2->x);
+ result->y = (p1->y - p2->y);
- return(result);
-} /* point_sub() */
+ return (result);
+} /* point_sub() */
-Point *
-point_mul(Point *p1, Point *p2)
+Point *
+point_mul(Point * p1, Point * p2)
{
- Point *result;
+ Point *result;
- if (! (PointerIsValid(p1) && PointerIsValid(p2)))
- return(NULL);
+ if (!(PointerIsValid(p1) && PointerIsValid(p2)))
+ return (NULL);
- result = PALLOCTYPE(Point);
+ result = PALLOCTYPE(Point);
- result->x = (p1->x*p2->x) - (p1->y*p2->y);
- result->y = (p1->x*p2->y) + (p1->y*p2->x);
+ result->x = (p1->x * p2->x) - (p1->y * p2->y);
+ result->y = (p1->x * p2->y) + (p1->y * p2->x);
- return(result);
-} /* point_mul() */
+ return (result);
+} /* point_mul() */
-Point *
-point_div(Point *p1, Point *p2)
+Point *
+point_div(Point * p1, Point * p2)
{
- Point *result;
- double div;
+ Point *result;
+ double div;
- if (! (PointerIsValid(p1) && PointerIsValid(p2)))
- return(NULL);
+ if (!(PointerIsValid(p1) && PointerIsValid(p2)))
+ return (NULL);
- result = PALLOCTYPE(Point);
+ result = PALLOCTYPE(Point);
- div = (p2->x*p2->x) + (p2->y*p2->y);
+ div = (p2->x * p2->x) + (p2->y * p2->y);
- if (div == 0.0)
- elog(WARN,"point_div: divide by 0.0 error");
+ if (div == 0.0)
+ elog(WARN, "point_div: divide by 0.0 error");
- result->x = ((p1->x*p2->x) + (p1->y*p2->y)) / div;
- result->y = ((p2->x*p1->y) - (p2->y*p1->x)) / div;
+ result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
+ result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
- return(result);
-} /* point_div() */
+ return (result);
+} /* point_div() */
/***********************************************************************
**
- ** Routines for 2D boxes.
+ ** Routines for 2D boxes.
**
***********************************************************************/
-BOX *
-box(Point *p1, Point *p2)
+BOX *
+box(Point * p1, Point * p2)
{
- BOX *result;
+ BOX *result;
- if (! (PointerIsValid(p1) && PointerIsValid(p2)))
- return(NULL);
+ if (!(PointerIsValid(p1) && PointerIsValid(p2)))
+ return (NULL);
- result = box_construct( p1->x, p2->x, p1->y, p2->y);
+ result = box_construct(p1->x, p2->x, p1->y, p2->y);
- return(result);
-} /* box() */
+ return (result);
+} /* box() */
-BOX *
-box_add(BOX *box, Point *p)
+BOX *
+box_add(BOX * box, Point * p)
{
- BOX *result;
+ BOX *result;
- if (! (PointerIsValid(box) && PointerIsValid(p)))
- return(NULL);
+ if (!(PointerIsValid(box) && PointerIsValid(p)))
+ return (NULL);
- result = box_construct( (box->high.x + p->x), (box->low.x + p->x),
- (box->high.y + p->y), (box->low.y + p->y));
+ result = box_construct((box->high.x + p->x), (box->low.x + p->x),
+ (box->high.y + p->y), (box->low.y + p->y));
- return(result);
-} /* box_add() */
+ return (result);
+} /* box_add() */
-BOX *
-box_sub(BOX *box, Point *p)
+BOX *
+box_sub(BOX * box, Point * p)
{
- BOX *result;
+ BOX *result;
- if (! (PointerIsValid(box) && PointerIsValid(p)))
- return(NULL);
+ if (!(PointerIsValid(box) && PointerIsValid(p)))
+ return (NULL);
- result = box_construct( (box->high.x - p->x), (box->low.x - p->x),
- (box->high.y - p->y), (box->low.y - p->y));
+ result = box_construct((box->high.x - p->x), (box->low.x - p->x),
+ (box->high.y - p->y), (box->low.y - p->y));
- return(result);
-} /* box_sub() */
+ return (result);
+} /* box_sub() */
-BOX *
-box_mul(BOX *box, Point *p)
+BOX *
+box_mul(BOX * box, Point * p)
{
- BOX *result;
- Point *high, *low;
+ BOX *result;
+ Point *high,
+ *low;
- if (! (PointerIsValid(box) && PointerIsValid(p)))
- return(NULL);
+ if (!(PointerIsValid(box) && PointerIsValid(p)))
+ return (NULL);
- high = point_mul( &box->high, p);
- low = point_mul( &box->low, p);
+ high = point_mul(&box->high, p);
+ low = point_mul(&box->low, p);
- result = box_construct( high->x, low->x, high->y, low->y);
- PFREE( high);
- PFREE( low);
+ result = box_construct(high->x, low->x, high->y, low->y);
+ PFREE(high);
+ PFREE(low);
- return(result);
-} /* box_mul() */
+ return (result);
+} /* box_mul() */
-BOX *
-box_div(BOX *box, Point *p)
+BOX *
+box_div(BOX * box, Point * p)
{
- BOX *result;
- Point *high, *low;
+ BOX *result;
+ Point *high,
+ *low;
- if (! (PointerIsValid(box) && PointerIsValid(p)))
- return(NULL);
+ if (!(PointerIsValid(box) && PointerIsValid(p)))
+ return (NULL);
- high = point_div( &box->high, p);
- low = point_div( &box->low, p);
+ high = point_div(&box->high, p);
+ low = point_div(&box->low, p);
- result = box_construct( high->x, low->x, high->y, low->y);
- PFREE( high);
- PFREE( low);
+ result = box_construct(high->x, low->x, high->y, low->y);
+ PFREE(high);
+ PFREE(low);
- return(result);
-} /* box_div() */
+ return (result);
+} /* box_div() */
/***********************************************************************
**
- ** Routines for 2D lines.
- ** Lines are not intended to be used as ADTs per se,
- ** but their ops are useful tools for other ADT ops. Thus,
- ** there are few relops.
+ ** Routines for 2D lines.
+ ** Lines are not intended to be used as ADTs per se,
+ ** but their ops are useful tools for other ADT ops. Thus,
+ ** there are few relops.
**
***********************************************************************/
/***********************************************************************
**
- ** Routines for 2D paths.
+ ** Routines for 2D paths.
**
***********************************************************************/
/* path_add()
* Concatenate two paths (only if they are both open).
*/
-PATH *
-path_add(PATH *p1, PATH *p2)
+PATH *
+path_add(PATH * p1, PATH * p2)
{
- PATH *result;
- int size;
- int i;
+ PATH *result;
+ int size;
+ int i;
- if (! (PointerIsValid(p1) && PointerIsValid(p2))
- || p1->closed || p2->closed)
- return(NULL);
+ if (!(PointerIsValid(p1) && PointerIsValid(p2))
+ || p1->closed || p2->closed)
+ return (NULL);
- size = offsetof(PATH, p[0]) + (sizeof(p1->p[0]) * (p1->npts+p2->npts));
- result = PALLOC(size);
+ size = offsetof(PATH, p[0]) + (sizeof(p1->p[0]) * (p1->npts + p2->npts));
+ result = PALLOC(size);
- result->size = size;
- result->npts = (p1->npts+p2->npts);
- result->closed = p1->closed;
+ result->size = size;
+ result->npts = (p1->npts + p2->npts);
+ result->closed = p1->closed;
- for (i=0; i<p1->npts; i++) {
- result->p[i].x = p1->p[i].x;
- result->p[i].y = p1->p[i].y;
- }
- for (i=0; i<p2->npts; i++) {
- result->p[i+p1->npts].x = p2->p[i].x;
- result->p[i+p1->npts].y = p2->p[i].y;
- }
+ for (i = 0; i < p1->npts; i++)
+ {
+ result->p[i].x = p1->p[i].x;
+ result->p[i].y = p1->p[i].y;
+ }
+ for (i = 0; i < p2->npts; i++)
+ {
+ result->p[i + p1->npts].x = p2->p[i].x;
+ result->p[i + p1->npts].y = p2->p[i].y;
+ }
- return(result);
-} /* path_add() */
+ return (result);
+} /* path_add() */
/* path_add_pt()
* Translation operator.
*/
-PATH *
-path_add_pt(PATH *path, Point *point)
+PATH *
+path_add_pt(PATH * path, Point * point)
{
- PATH *result;
- int i;
+ PATH *result;
+ int i;
- if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
- return(NULL);
+ if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
+ return (NULL);
- result = path_copy(path);
+ result = path_copy(path);
- for (i=0; i<path->npts; i++) {
- result->p[i].x += point->x;
- result->p[i].y += point->y;
- }
+ for (i = 0; i < path->npts; i++)
+ {
+ result->p[i].x += point->x;
+ result->p[i].y += point->y;
+ }
- return(result);
-} /* path_add_pt() */
+ return (result);
+} /* path_add_pt() */
-PATH *
-path_sub_pt(PATH *path, Point *point)
+PATH *
+path_sub_pt(PATH * path, Point * point)
{
- PATH *result;
- int i;
+ PATH *result;
+ int i;
- if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
- return(NULL);
+ if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
+ return (NULL);
- result = path_copy(path);
+ result = path_copy(path);
- for (i=0; i<path->npts; i++) {
- result->p[i].x -= point->x;
- result->p[i].y -= point->y;
- }
+ for (i = 0; i < path->npts; i++)
+ {
+ result->p[i].x -= point->x;
+ result->p[i].y -= point->y;
+ }
- return(result);
-} /* path_sub_pt() */
+ return (result);
+} /* path_sub_pt() */
/* path_mul_pt()
* Rotation and scaling operators.
*/
-PATH *
-path_mul_pt(PATH *path, Point *point)
+PATH *
+path_mul_pt(PATH * path, Point * point)
{
- PATH *result;
- Point *p;
- int i;
+ PATH *result;
+ Point *p;
+ int i;
- if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
- return(NULL);
+ if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
+ return (NULL);
- result = path_copy(path);
+ result = path_copy(path);
- for (i=0; i<path->npts; i++) {
- p = point_mul( &path->p[i], point);
- result->p[i].x = p->x;
- result->p[i].y = p->y;
- PFREE(p);
- }
+ for (i = 0; i < path->npts; i++)
+ {
+ p = point_mul(&path->p[i], point);
+ result->p[i].x = p->x;
+ result->p[i].y = p->y;
+ PFREE(p);
+ }
- return(result);
-} /* path_mul_pt() */
+ return (result);
+} /* path_mul_pt() */
-PATH *
-path_div_pt(PATH *path, Point *point)
+PATH *
+path_div_pt(PATH * path, Point * point)
{
- PATH *result;
- Point *p;
- int i;
+ PATH *result;
+ Point *p;
+ int i;
- if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
- return(NULL);
+ if ((!PointerIsValid(path)) || (!PointerIsValid(point)))
+ return (NULL);
- result = path_copy(path);
+ result = path_copy(path);
- for (i=0; i<path->npts; i++) {
- p = point_div( &path->p[i], point);
- result->p[i].x = p->x;
- result->p[i].y = p->y;
- PFREE(p);
- }
+ for (i = 0; i < path->npts; i++)
+ {
+ p = point_div(&path->p[i], point);
+ result->p[i].x = p->x;
+ result->p[i].y = p->y;
+ PFREE(p);
+ }
- return(result);
-} /* path_div_pt() */
+ return (result);
+} /* path_div_pt() */
bool
-path_contain_pt( PATH *path, Point *p)
+path_contain_pt(PATH * path, Point * p)
{
- if (!PointerIsValid(path) || !PointerIsValid(p))
- return(FALSE);
+ if (!PointerIsValid(path) || !PointerIsValid(p))
+ return (FALSE);
- return( (path->closed? (point_inside(p, path->npts, &(path->p[0])) != 0): FALSE));
-} /* path_contain_pt() */
+ return ((path->closed ? (point_inside(p, path->npts, &(path->p[0])) != 0) : FALSE));
+} /* path_contain_pt() */
bool
-pt_contained_path( Point *p, PATH *path)
+pt_contained_path(Point * p, PATH * path)
{
- if (!PointerIsValid(p) || !PointerIsValid(path))
- return(FALSE);
+ if (!PointerIsValid(p) || !PointerIsValid(path))
+ return (FALSE);
- return( path_contain_pt( path, p));
-} /* pt_contained_path() */
+ return (path_contain_pt(path, p));
+} /* pt_contained_path() */
-Point *
-path_center(PATH *path)
+Point *
+path_center(PATH * path)
{
- Point *result;
+ Point *result;
- if (!PointerIsValid(path))
- return(NULL);
+ if (!PointerIsValid(path))
+ return (NULL);
- elog(WARN, "path_center not implemented", NULL);
+ elog(WARN, "path_center not implemented", NULL);
- result = PALLOCTYPE(Point);
- result = NULL;
+ result = PALLOCTYPE(Point);
+ result = NULL;
- return(result);
-} /* path_center() */
+ return (result);
+} /* path_center() */
-POLYGON *path_poly(PATH *path)
+POLYGON *
+path_poly(PATH * path)
{
- POLYGON *poly;
- int size;
- int i;
+ POLYGON *poly;
+ int size;
+ int i;
- if (!PointerIsValid(path))
- return(NULL);
+ if (!PointerIsValid(path))
+ return (NULL);
- if (!path->closed)
- elog(WARN, "Open path cannot be converted to polygon",NULL);
+ if (!path->closed)
+ elog(WARN, "Open path cannot be converted to polygon", NULL);
- size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * path->npts);
- poly = PALLOC(size);
+ size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * path->npts);
+ poly = PALLOC(size);
- poly->size = size;
- poly->npts = path->npts;
+ poly->size = size;
+ poly->npts = path->npts;
- for (i=0; i<path->npts; i++) {
- poly->p[i].x = path->p[i].x;
- poly->p[i].y = path->p[i].y;
- }
+ for (i = 0; i < path->npts; i++)
+ {
+ poly->p[i].x = path->p[i].x;
+ poly->p[i].y = path->p[i].y;
+ }
- make_bound_box(poly);
+ make_bound_box(poly);
- return(poly);
-} /* path_polygon() */
+ return (poly);
+} /* path_polygon() */
/* upgradepath()
@@ -2860,157 +3171,163 @@ POLYGON *path_poly(PATH *path)
*
* Old-style: '(closed,#pts,x1,y1,...)' where closed is a boolean flag
* New-style: '((x1,y1),...)' for closed path
- * '[(x1,y1),...]' for open path
+ * '[(x1,y1),...]' for open path
*/
PATH
-*upgradepath(PATH *path)
+* upgradepath(PATH * path)
{
- PATH *result;
- int size, npts;
- int i;
+ PATH *result;
+ int size,
+ npts;
+ int i;
- if (!PointerIsValid(path) || (path->npts < 2))
- return(NULL);
+ if (!PointerIsValid(path) || (path->npts < 2))
+ return (NULL);
- if (! isoldpath(path))
- elog(WARN,"upgradepath: path already upgraded?",NULL);
+ if (!isoldpath(path))
+ elog(WARN, "upgradepath: path already upgraded?", NULL);
- npts = (path->npts-1);
- size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * npts);
- result = PALLOC(size);
- memset((char *) result, 0, size);
+ npts = (path->npts - 1);
+ size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * npts);
+ result = PALLOC(size);
+ memset((char *) result, 0, size);
- result->size = size;
- result->npts = npts;
- result->closed = (path->p[0].x != 0);
+ result->size = size;
+ result->npts = npts;
+ result->closed = (path->p[0].x != 0);
- for (i=0; i<result->npts; i++) {
- result->p[i].x = path->p[i+1].x;
- result->p[i].y = path->p[i+1].y;
- }
+ for (i = 0; i < result->npts; i++)
+ {
+ result->p[i].x = path->p[i + 1].x;
+ result->p[i].y = path->p[i + 1].y;
+ }
- return(result);
-} /* upgradepath() */
+ return (result);
+} /* upgradepath() */
bool
-isoldpath(PATH *path)
+isoldpath(PATH * path)
{
- if (!PointerIsValid(path) || (path->npts < 2))
- return(FALSE);
+ if (!PointerIsValid(path) || (path->npts < 2))
+ return (FALSE);
- return(path->npts == (path->p[0].y+1));
-} /* isoldpath() */
+ return (path->npts == (path->p[0].y + 1));
+} /* isoldpath() */
/***********************************************************************
**
- ** Routines for 2D polygons.
+ ** Routines for 2D polygons.
**
***********************************************************************/
int4
-poly_npoints(POLYGON *poly)
+poly_npoints(POLYGON * poly)
{
- if (!PointerIsValid(poly))
- return(0);
+ if (!PointerIsValid(poly))
+ return (0);
- return(poly->npts);
-} /* poly_npoints() */
+ return (poly->npts);
+} /* poly_npoints() */
-Point *
-poly_center(POLYGON *poly)
+Point *
+poly_center(POLYGON * poly)
{
- Point *result;
- CIRCLE *circle;
+ Point *result;
+ CIRCLE *circle;
- if (!PointerIsValid(poly))
- return(NULL);
+ if (!PointerIsValid(poly))
+ return (NULL);
- if (PointerIsValid(circle = poly_circle(poly))) {
- result = circle_center(circle);
- PFREE(circle);
+ if (PointerIsValid(circle = poly_circle(poly)))
+ {
+ result = circle_center(circle);
+ PFREE(circle);
- } else {
- result = NULL;
- }
+ }
+ else
+ {
+ result = NULL;
+ }
- return(result);
-} /* poly_center() */
+ return (result);
+} /* poly_center() */
-BOX *
-poly_box(POLYGON *poly)
+BOX *
+poly_box(POLYGON * poly)
{
- BOX *box;
+ BOX *box;
- if (!PointerIsValid(poly) || (poly->npts < 1))
- return(NULL);
+ if (!PointerIsValid(poly) || (poly->npts < 1))
+ return (NULL);
- box = box_copy( &poly->boundbox);
+ box = box_copy(&poly->boundbox);
- return(box);
-} /* poly_box() */
+ return (box);
+} /* poly_box() */
/* box_poly()
* Convert a box to a polygon.
*/
-POLYGON *
-box_poly(BOX *box)
+POLYGON *
+box_poly(BOX * box)
{
- POLYGON *poly;
- int size;
+ POLYGON *poly;
+ int size;
- if (!PointerIsValid(box))
- return(NULL);
+ if (!PointerIsValid(box))
+ return (NULL);
- /* map four corners of the box to a polygon */
- size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * 4);
- poly = PALLOC(size);
+ /* map four corners of the box to a polygon */
+ size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * 4);
+ poly = PALLOC(size);
- poly->size = size;
- poly->npts = 4;
+ poly->size = size;
+ poly->npts = 4;
- poly->p[0].x = box->low.x;
- poly->p[0].y = box->low.y;
- poly->p[1].x = box->low.x;
- poly->p[1].y = box->high.y;
- poly->p[2].x = box->high.x;
- poly->p[2].y = box->high.y;
- poly->p[3].x = box->high.x;
- poly->p[3].y = box->low.y;
+ poly->p[0].x = box->low.x;
+ poly->p[0].y = box->low.y;
+ poly->p[1].x = box->low.x;
+ poly->p[1].y = box->high.y;
+ poly->p[2].x = box->high.x;
+ poly->p[2].y = box->high.y;
+ poly->p[3].x = box->high.x;
+ poly->p[3].y = box->low.y;
- box_fill( &poly->boundbox, box->high.x, box->low.x, box->high.y, box->low.y);
+ box_fill(&poly->boundbox, box->high.x, box->low.x, box->high.y, box->low.y);
- return(poly);
-} /* box_poly() */
+ return (poly);
+} /* box_poly() */
-PATH *
-poly_path(POLYGON *poly)
+PATH *
+poly_path(POLYGON * poly)
{
- PATH *path;
- int size;
- int i;
+ PATH *path;
+ int size;
+ int i;
- if (!PointerIsValid(poly) || (poly->npts < 0))
- return(NULL);
+ if (!PointerIsValid(poly) || (poly->npts < 0))
+ return (NULL);
- size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * poly->npts);
- path = PALLOC(size);
+ size = offsetof(PATH, p[0]) + (sizeof(path->p[0]) * poly->npts);
+ path = PALLOC(size);
- path->size = size;
- path->npts = poly->npts;
- path->closed = TRUE;
+ path->size = size;
+ path->npts = poly->npts;
+ path->closed = TRUE;
- for (i=0; i<poly->npts; i++) {
- path->p[i].x = poly->p[i].x;
- path->p[i].y = poly->p[i].y;
- }
+ for (i = 0; i < poly->npts; i++)
+ {
+ path->p[i].x = poly->p[i].x;
+ path->p[i].y = poly->p[i].y;
+ }
- return(path);
-} /* poly_path() */
+ return (path);
+} /* poly_path() */
/* upgradepoly()
@@ -3019,86 +3336,98 @@ poly_path(POLYGON *poly)
* New-style: '(x1,y1,x2,y2,...)'
*/
POLYGON
-*upgradepoly(POLYGON *poly)
+* upgradepoly(POLYGON * poly)
{
- POLYGON *result;
- int size;
- int n2, i, ii;
+ POLYGON *result;
+ int size;
+ int n2,
+ i,
+ ii;
- if (!PointerIsValid(poly) || (poly->npts < 1))
- return(NULL);
+ if (!PointerIsValid(poly) || (poly->npts < 1))
+ return (NULL);
- size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * poly->npts);
- result = PALLOC(size);
- memset((char *) result, 0, size);
+ size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * poly->npts);
+ result = PALLOC(size);
+ memset((char *) result, 0, size);
- result->size = size;
- result->npts = poly->npts;
+ result->size = size;
+ result->npts = poly->npts;
- n2 = poly->npts/2;
+ n2 = poly->npts / 2;
- for (i=0; i<n2; i++) {
- result->p[2*i].x = poly->p[i].x; /* even indices */
- result->p[2*i+1].x = poly->p[i].y; /* odd indices */
- }
+ for (i = 0; i < n2; i++)
+ {
+ result->p[2 * i].x = poly->p[i].x; /* even indices */
+ result->p[2 * i + 1].x = poly->p[i].y; /* odd indices */
+ }
- if ((ii = ((poly->npts % 2)? 1: 0))) {
- result->p[poly->npts-1].x = poly->p[n2].x;
- result->p[0].y = poly->p[n2].y;
- }
+ if ((ii = ((poly->npts % 2) ? 1 : 0)))
+ {
+ result->p[poly->npts - 1].x = poly->p[n2].x;
+ result->p[0].y = poly->p[n2].y;
+ }
- for (i=0; i<n2; i++) {
- result->p[2*i+ii].y = poly->p[i+n2+ii].x; /* even (+offset) indices */
- result->p[2*i+ii+1].y = poly->p[i+n2+ii].y; /* odd (+offset) indices */
- }
+ for (i = 0; i < n2; i++)
+ {
+ result->p[2 * i + ii].y = poly->p[i + n2 + ii].x; /* even (+offset)
+ * indices */
+ result->p[2 * i + ii + 1].y = poly->p[i + n2 + ii].y; /* odd (+offset) indices */
+ }
- return(result);
-} /* upgradepoly() */
+ return (result);
+} /* upgradepoly() */
/* revertpoly()
* Reverse effect of upgradepoly().
*/
POLYGON
-*revertpoly(POLYGON *poly)
+* revertpoly(POLYGON * poly)
{
- POLYGON *result;
- int size;
- int n2, i, ii;
+ POLYGON *result;
+ int size;
+ int n2,
+ i,
+ ii;
- if (!PointerIsValid(poly) || (poly->npts < 1))
- return(NULL);
+ if (!PointerIsValid(poly) || (poly->npts < 1))
+ return (NULL);
- size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * poly->npts);
- result = PALLOC(size);
- memset((char *) result, 0, size);
+ size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * poly->npts);
+ result = PALLOC(size);
+ memset((char *) result, 0, size);
- result->size = size;
- result->npts = poly->npts;
+ result->size = size;
+ result->npts = poly->npts;
- n2 = poly->npts/2;
+ n2 = poly->npts / 2;
- for (i=0; i<n2; i++) {
- result->p[i].x = poly->p[2*i].x; /* even indices */
- result->p[i].y = poly->p[2*i+1].x; /* odd indices */
- }
+ for (i = 0; i < n2; i++)
+ {
+ result->p[i].x = poly->p[2 * i].x; /* even indices */
+ result->p[i].y = poly->p[2 * i + 1].x; /* odd indices */
+ }
- if ((ii = ((poly->npts % 2)? 1: 0))) {
- result->p[n2].x = poly->p[poly->npts-1].x;
- result->p[n2].y = poly->p[0].y;
- }
+ if ((ii = ((poly->npts % 2) ? 1 : 0)))
+ {
+ result->p[n2].x = poly->p[poly->npts - 1].x;
+ result->p[n2].y = poly->p[0].y;
+ }
- for (i=0; i<n2; i++) {
- result->p[i+n2+ii].x = poly->p[2*i+ii].y; /* even (+offset) indices */
- result->p[i+n2+ii].y = poly->p[2*i+ii+1].y; /* odd (+offset) indices */
- }
+ for (i = 0; i < n2; i++)
+ {
+ result->p[i + n2 + ii].x = poly->p[2 * i + ii].y; /* even (+offset)
+ * indices */
+ result->p[i + n2 + ii].y = poly->p[2 * i + ii + 1].y; /* odd (+offset) indices */
+ }
- return(result);
-} /* revertpoly() */
+ return (result);
+} /* revertpoly() */
/***********************************************************************
**
- ** Routines for circles.
+ ** Routines for circles.
**
***********************************************************************/
@@ -3106,594 +3435,645 @@ POLYGON
* Formatting and conversion routines.
*---------------------------------------------------------*/
-/* circle_in - convert a string to internal form.
+/* circle_in - convert a string to internal form.
*
- * External format: (center and radius of circle)
- * "((f8,f8)<f8>)"
- * also supports quick entry style "(f8,f8,f8)"
+ * External format: (center and radius of circle)
+ * "((f8,f8)<f8>)"
+ * also supports quick entry style "(f8,f8,f8)"
*/
-CIRCLE *circle_in(char *str)
-{
- CIRCLE *circle;
-
- char *s, *cp;
- int depth = 0;
-
- if (!PointerIsValid(str))
- elog (WARN," Bad (null) circle external representation",NULL);
-
- circle = PALLOCTYPE(CIRCLE);
-
- s = str;
- while (isspace( *s)) s++;
- if ((*s == LDELIM_C) || (*s == LDELIM)) {
- depth++;
- cp = (s+1);
- while (isspace( *cp)) cp++;
- if (*cp == LDELIM) {
- s = cp;
+CIRCLE *
+circle_in(char *str)
+{
+ CIRCLE *circle;
+
+ char *s,
+ *cp;
+ int depth = 0;
+
+ if (!PointerIsValid(str))
+ elog(WARN, " Bad (null) circle external representation", NULL);
+
+ circle = PALLOCTYPE(CIRCLE);
+
+ s = str;
+ while (isspace(*s))
+ s++;
+ if ((*s == LDELIM_C) || (*s == LDELIM))
+ {
+ depth++;
+ cp = (s + 1);
+ while (isspace(*cp))
+ cp++;
+ if (*cp == LDELIM)
+ {
+ s = cp;
+ }
}
- }
-
- if (! pair_decode( s, &circle->center.x, &circle->center.y, &s))
- elog (WARN, "Bad circle external representation '%s'",str);
-
- if (*s == DELIM) s++;
- while (isspace( *s)) s++;
- if ((! single_decode( s, &circle->radius, &s)) || (circle->radius < 0))
- elog (WARN, "Bad circle external representation '%s'",str);
-
- while (depth > 0) {
- if ((*s == RDELIM)
- || ((*s == RDELIM_C) && (depth == 1))) {
- depth--;
- s++;
- while (isspace( *s)) s++;
- } else {
- elog (WARN, "Bad circle external representation '%s'",str);
+ if (!pair_decode(s, &circle->center.x, &circle->center.y, &s))
+ elog(WARN, "Bad circle external representation '%s'", str);
+
+ if (*s == DELIM)
+ s++;
+ while (isspace(*s))
+ s++;
+
+ if ((!single_decode(s, &circle->radius, &s)) || (circle->radius < 0))
+ elog(WARN, "Bad circle external representation '%s'", str);
+
+ while (depth > 0)
+ {
+ if ((*s == RDELIM)
+ || ((*s == RDELIM_C) && (depth == 1)))
+ {
+ depth--;
+ s++;
+ while (isspace(*s))
+ s++;
+ }
+ else
+ {
+ elog(WARN, "Bad circle external representation '%s'", str);
+ }
}
- }
- if (*s != '\0')
- elog (WARN, "Bad circle external representation '%s'",str);
+ if (*s != '\0')
+ elog(WARN, "Bad circle external representation '%s'", str);
- return(circle);
-} /* circle_in() */
+ return (circle);
+} /* circle_in() */
-/* circle_out - convert a circle to external form.
+/* circle_out - convert a circle to external form.
*/
-char *circle_out(CIRCLE *circle)
+char *
+circle_out(CIRCLE * circle)
{
- char *result;
- char *cp;
+ char *result;
+ char *cp;
- if (!PointerIsValid(circle))
- return(NULL);
+ if (!PointerIsValid(circle))
+ return (NULL);
- result = PALLOC(3*(P_MAXLEN+1)+3);
+ result = PALLOC(3 * (P_MAXLEN + 1) + 3);
- cp = result;
- *cp++ = LDELIM_C;
- *cp++ = LDELIM;
- if (! pair_encode( circle->center.x, circle->center.y, cp))
- elog (WARN, "Unable to format circle", NULL);
+ cp = result;
+ *cp++ = LDELIM_C;
+ *cp++ = LDELIM;
+ if (!pair_encode(circle->center.x, circle->center.y, cp))
+ elog(WARN, "Unable to format circle", NULL);
- cp += strlen(cp);
- *cp++ = RDELIM;
- *cp++ = DELIM;
- if (! single_encode( circle->radius, cp))
- elog (WARN, "Unable to format circle", NULL);
+ cp += strlen(cp);
+ *cp++ = RDELIM;
+ *cp++ = DELIM;
+ if (!single_encode(circle->radius, cp))
+ elog(WARN, "Unable to format circle", NULL);
- cp += strlen(cp);
- *cp++ = RDELIM_C;
- *cp = '\0';
+ cp += strlen(cp);
+ *cp++ = RDELIM_C;
+ *cp = '\0';
- return(result);
-} /* circle_out() */
+ return (result);
+} /* circle_out() */
/*----------------------------------------------------------
- * Relational operators for CIRCLEs.
- * <, >, <=, >=, and == are based on circle area.
+ * Relational operators for CIRCLEs.
+ * <, >, <=, >=, and == are based on circle area.
*---------------------------------------------------------*/
-/* circles identical?
+/* circles identical?
*/
-bool circle_same(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_same(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPeq(circle1->radius,circle2->radius)
- && FPeq(circle1->center.x,circle2->center.x)
- && FPeq(circle1->center.y,circle2->center.y));
+ return (FPeq(circle1->radius, circle2->radius)
+ && FPeq(circle1->center.x, circle2->center.x)
+ && FPeq(circle1->center.y, circle2->center.y));
}
-/* circle_overlap - does circle1 overlap circle2?
+/* circle_overlap - does circle1 overlap circle2?
*/
-bool circle_overlap(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_overlap(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPle(point_dt(&circle1->center,&circle2->center),(circle1->radius+circle2->radius)));
+ return (FPle(point_dt(&circle1->center, &circle2->center), (circle1->radius + circle2->radius)));
}
-/* circle_overleft - is the right edge of circle1 to the left of
- * the right edge of circle2?
+/* circle_overleft - is the right edge of circle1 to the left of
+ * the right edge of circle2?
*/
-bool circle_overleft(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_overleft(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPle((circle1->center.x+circle1->radius),(circle2->center.x+circle2->radius)));
+ return (FPle((circle1->center.x + circle1->radius), (circle2->center.x + circle2->radius)));
}
-/* circle_left - is circle1 strictly left of circle2?
+/* circle_left - is circle1 strictly left of circle2?
*/
-bool circle_left(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_left(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPle((circle1->center.x+circle1->radius),(circle2->center.x-circle2->radius)));
+ return (FPle((circle1->center.x + circle1->radius), (circle2->center.x - circle2->radius)));
}
-/* circle_right - is circle1 strictly right of circle2?
+/* circle_right - is circle1 strictly right of circle2?
*/
-bool circle_right(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_right(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPge((circle1->center.x-circle1->radius),(circle2->center.x+circle2->radius)));
+ return (FPge((circle1->center.x - circle1->radius), (circle2->center.x + circle2->radius)));
}
-/* circle_overright - is the left edge of circle1 to the right of
- * the left edge of circle2?
+/* circle_overright - is the left edge of circle1 to the right of
+ * the left edge of circle2?
*/
-bool circle_overright(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_overright(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPge((circle1->center.x-circle1->radius),(circle2->center.x-circle2->radius)));
+ return (FPge((circle1->center.x - circle1->radius), (circle2->center.x - circle2->radius)));
}
-/* circle_contained - is circle1 contained by circle2?
+/* circle_contained - is circle1 contained by circle2?
*/
-bool circle_contained(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_contained(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPle((point_dt(&circle1->center,&circle2->center)+circle1->radius),circle2->radius));
+ return (FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
}
-/* circle_contain - does circle1 contain circle2?
+/* circle_contain - does circle1 contain circle2?
*/
-bool circle_contain(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_contain(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPle((point_dt(&circle1->center,&circle2->center)+circle2->radius),circle1->radius));
+ return (FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
}
-/* circle_positionop -
- * is circle1 entirely {above,below} circle2?
+/* circle_positionop -
+ * is circle1 entirely {above,below} circle2?
*/
-bool circle_below(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_below(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPle((circle1->center.y+circle1->radius),(circle2->center.y-circle2->radius)));
+ return (FPle((circle1->center.y + circle1->radius), (circle2->center.y - circle2->radius)));
}
-bool circle_above(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_above(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPge((circle1->center.y-circle1->radius),(circle2->center.y+circle2->radius)));
+ return (FPge((circle1->center.y - circle1->radius), (circle2->center.y + circle2->radius)));
}
-/* circle_relop - is area(circle1) relop area(circle2), within
- * our accuracy constraint?
+/* circle_relop - is area(circle1) relop area(circle2), within
+ * our accuracy constraint?
*/
-bool circle_eq(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_eq(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPeq(circle_ar(circle1), circle_ar(circle2)) );
-} /* circle_eq() */
+ return (FPeq(circle_ar(circle1), circle_ar(circle2)));
+} /* circle_eq() */
-bool circle_ne(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_ne(CIRCLE * circle1, CIRCLE * circle2)
{
- return( !circle_eq(circle1, circle2));
-} /* circle_ne() */
+ return (!circle_eq(circle1, circle2));
+} /* circle_ne() */
-bool circle_lt(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_lt(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPlt(circle_ar(circle1), circle_ar(circle2)) );
-} /* circle_lt() */
+ return (FPlt(circle_ar(circle1), circle_ar(circle2)));
+} /* circle_lt() */
-bool circle_gt(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_gt(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPgt(circle_ar(circle1), circle_ar(circle2)) );
-} /* circle_gt() */
+ return (FPgt(circle_ar(circle1), circle_ar(circle2)));
+} /* circle_gt() */
-bool circle_le(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_le(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPle(circle_ar(circle1), circle_ar(circle2)) );
-} /* circle_le() */
+ return (FPle(circle_ar(circle1), circle_ar(circle2)));
+} /* circle_le() */
-bool circle_ge(CIRCLE *circle1, CIRCLE *circle2)
+bool
+circle_ge(CIRCLE * circle1, CIRCLE * circle2)
{
- return( FPge(circle_ar(circle1), circle_ar(circle2)) );
-} /* circle_ge() */
+ return (FPge(circle_ar(circle1), circle_ar(circle2)));
+} /* circle_ge() */
/*----------------------------------------------------------
- * "Arithmetic" operators on circles.
- * circle_foo returns foo as an object (pointer) that
+ * "Arithmetic" operators on circles.
+ * circle_foo returns foo as an object (pointer) that
can be passed between languages.
- * circle_xx is an internal routine which returns the
- * actual value.
+ * circle_xx is an internal routine which returns the
+ * actual value.
*---------------------------------------------------------*/
-static CIRCLE *
-circle_copy(CIRCLE *circle)
+static CIRCLE *
+circle_copy(CIRCLE * circle)
{
- CIRCLE *result;
+ CIRCLE *result;
- if (!PointerIsValid(circle))
- return NULL;
+ if (!PointerIsValid(circle))
+ return NULL;
- result = PALLOCTYPE(CIRCLE);
+ result = PALLOCTYPE(CIRCLE);
- memmove((char *) result, (char *) circle, sizeof(CIRCLE));
- return(result);
-} /* circle_copy() */
+ memmove((char *) result, (char *) circle, sizeof(CIRCLE));
+ return (result);
+} /* circle_copy() */
/* circle_add_pt()
* Translation operator.
*/
-CIRCLE *
-circle_add_pt(CIRCLE *circle, Point *point)
+CIRCLE *
+circle_add_pt(CIRCLE * circle, Point * point)
{
- CIRCLE *result;
+ CIRCLE *result;
- if (!PointerIsValid(circle) || !PointerIsValid(point))
- return(NULL);
+ if (!PointerIsValid(circle) || !PointerIsValid(point))
+ return (NULL);
- result = circle_copy(circle);
+ result = circle_copy(circle);
- result->center.x += point->x;
- result->center.y += point->y;
+ result->center.x += point->x;
+ result->center.y += point->y;
- return(result);
-} /* circle_add_pt() */
+ return (result);
+} /* circle_add_pt() */
-CIRCLE *
-circle_sub_pt(CIRCLE *circle, Point *point)
+CIRCLE *
+circle_sub_pt(CIRCLE * circle, Point * point)
{
- CIRCLE *result;
+ CIRCLE *result;
- if (!PointerIsValid(circle) || !PointerIsValid(point))
- return(NULL);
+ if (!PointerIsValid(circle) || !PointerIsValid(point))
+ return (NULL);
- result = circle_copy(circle);
+ result = circle_copy(circle);
- result->center.x -= point->x;
- result->center.y -= point->y;
+ result->center.x -= point->x;
+ result->center.y -= point->y;
- return(result);
-} /* circle_sub_pt() */
+ return (result);
+} /* circle_sub_pt() */
/* circle_mul_pt()
* Rotation and scaling operators.
*/
-CIRCLE *
-circle_mul_pt(CIRCLE *circle, Point *point)
+CIRCLE *
+circle_mul_pt(CIRCLE * circle, Point * point)
{
- CIRCLE *result;
- Point *p;
+ CIRCLE *result;
+ Point *p;
- if (!PointerIsValid(circle) || !PointerIsValid(point))
- return(NULL);
+ if (!PointerIsValid(circle) || !PointerIsValid(point))
+ return (NULL);
- result = circle_copy(circle);
+ result = circle_copy(circle);
- p = point_mul( &circle->center, point);
- result->center.x = p->x;
- result->center.y = p->y;
- PFREE(p);
- result->radius *= HYPOT( point->x, point->y);
+ p = point_mul(&circle->center, point);
+ result->center.x = p->x;
+ result->center.y = p->y;
+ PFREE(p);
+ result->radius *= HYPOT(point->x, point->y);
- return(result);
-} /* circle_mul_pt() */
+ return (result);
+} /* circle_mul_pt() */
-CIRCLE *
-circle_div_pt(CIRCLE *circle, Point *point)
+CIRCLE *
+circle_div_pt(CIRCLE * circle, Point * point)
{
- CIRCLE *result;
- Point *p;
+ CIRCLE *result;
+ Point *p;
- if (!PointerIsValid(circle) || !PointerIsValid(point))
- return(NULL);
+ if (!PointerIsValid(circle) || !PointerIsValid(point))
+ return (NULL);
- result = circle_copy(circle);
+ result = circle_copy(circle);
- p = point_div( &circle->center, point);
- result->center.x = p->x;
- result->center.y = p->y;
- PFREE(p);
- result->radius /= HYPOT( point->x, point->y);
+ p = point_div(&circle->center, point);
+ result->center.x = p->x;
+ result->center.y = p->y;
+ PFREE(p);
+ result->radius /= HYPOT(point->x, point->y);
- return(result);
-} /* circle_div_pt() */
+ return (result);
+} /* circle_div_pt() */
-/* circle_area - returns the area of the circle.
+/* circle_area - returns the area of the circle.
*/
-double *circle_area(CIRCLE *circle)
+double *
+circle_area(CIRCLE * circle)
{
- double *result;
+ double *result;
- result = PALLOCTYPE(double);
- *result = circle_ar(circle);
+ result = PALLOCTYPE(double);
+ *result = circle_ar(circle);
- return(result);
+ return (result);
}
-/* circle_diameter - returns the diameter of the circle.
+/* circle_diameter - returns the diameter of the circle.
*/
-double *circle_diameter(CIRCLE *circle)
+double *
+circle_diameter(CIRCLE * circle)
{
- double *result;
+ double *result;
- result = PALLOCTYPE(double);
- *result = (2*circle->radius);
+ result = PALLOCTYPE(double);
+ *result = (2 * circle->radius);
- return(result);
+ return (result);
}
-/* circle_radius - returns the radius of the circle.
+/* circle_radius - returns the radius of the circle.
*/
-double *circle_radius(CIRCLE *circle)
+double *
+circle_radius(CIRCLE * circle)
{
- double *result;
+ double *result;
- result = PALLOCTYPE(double);
- *result = circle->radius;
+ result = PALLOCTYPE(double);
+ *result = circle->radius;
- return(result);
+ return (result);
}
-/* circle_distance - returns the distance between
- * two circles.
+/* circle_distance - returns the distance between
+ * two circles.
*/
-double *circle_distance(CIRCLE *circle1, CIRCLE *circle2)
+double *
+circle_distance(CIRCLE * circle1, CIRCLE * circle2)
{
- double *result;
+ double *result;
- result = PALLOCTYPE(double);
- *result = (point_dt(&circle1->center,&circle2->center)
- - (circle1->radius + circle2->radius));
- if (*result < 0) *result = 0;
+ result = PALLOCTYPE(double);
+ *result = (point_dt(&circle1->center, &circle2->center)
+ - (circle1->radius + circle2->radius));
+ if (*result < 0)
+ *result = 0;
- return(result);
-} /* circle_distance() */
+ return (result);
+} /* circle_distance() */
bool
-circle_contain_pt(CIRCLE *circle, Point *point)
+circle_contain_pt(CIRCLE * circle, Point * point)
{
- bool within;
- double *d;
+ bool within;
+ double *d;
- if (!PointerIsValid(circle) || !PointerIsValid(point))
- return(FALSE);
+ if (!PointerIsValid(circle) || !PointerIsValid(point))
+ return (FALSE);
- d = point_distance(&(circle->center), point);
- within = (*d <= circle->radius);
- PFREE(d);
+ d = point_distance(&(circle->center), point);
+ within = (*d <= circle->radius);
+ PFREE(d);
- return(within);
-} /* circle_contain_pt() */
+ return (within);
+} /* circle_contain_pt() */
bool
-pt_contained_circle(Point *point, CIRCLE *circle)
+pt_contained_circle(Point * point, CIRCLE * circle)
{
- return(circle_contain_pt(circle,point));
-} /* circle_contain_pt() */
+ return (circle_contain_pt(circle, point));
+} /* circle_contain_pt() */
-/* dist_pc - returns the distance between
- * a point and a circle.
+/* dist_pc - returns the distance between
+ * a point and a circle.
*/
-double *dist_pc(Point *point, CIRCLE *circle)
+double *
+dist_pc(Point * point, CIRCLE * circle)
{
- double *result;
+ double *result;
- result = PALLOCTYPE(double);
+ result = PALLOCTYPE(double);
- *result = (point_dt(point,&circle->center) - circle->radius);
- if (*result < 0) *result = 0;
+ *result = (point_dt(point, &circle->center) - circle->radius);
+ if (*result < 0)
+ *result = 0;
- return(result);
-} /* dist_pc() */
+ return (result);
+} /* dist_pc() */
-/* circle_center - returns the center point of the circle.
+/* circle_center - returns the center point of the circle.
*/
-Point *circle_center(CIRCLE *circle)
+Point *
+circle_center(CIRCLE * circle)
{
- Point *result;
+ Point *result;
- result = PALLOCTYPE(Point);
- result->x = circle->center.x;
- result->y = circle->center.y;
+ result = PALLOCTYPE(Point);
+ result->x = circle->center.x;
+ result->y = circle->center.y;
- return(result);
+ return (result);
}
-/* circle_ar - returns the area of the circle.
+/* circle_ar - returns the area of the circle.
*/
-static double circle_ar(CIRCLE *circle)
+static double
+circle_ar(CIRCLE * circle)
{
- return(PI*(circle->radius*circle->radius));
+ return (PI * (circle->radius * circle->radius));
}
-/* circle_dt - returns the distance between the
- * center points of two circlees.
+/* circle_dt - returns the distance between the
+ * center points of two circlees.
*/
#ifdef NOT_USED
-double circle_dt(CIRCLE *circle1, CIRCLE *circle2)
+double
+circle_dt(CIRCLE * circle1, CIRCLE * circle2)
{
- double result;
+ double result;
- result = point_dt(&circle1->center,&circle2->center);
+ result = point_dt(&circle1->center, &circle2->center);
- return(result);
+ return (result);
}
+
#endif
/*----------------------------------------------------------
- * Conversion operators.
+ * Conversion operators.
*---------------------------------------------------------*/
-CIRCLE *circle(Point *center, float8 *radius)
+CIRCLE *
+circle(Point * center, float8 * radius)
{
- CIRCLE *result;
+ CIRCLE *result;
- if (! (PointerIsValid(center) && PointerIsValid(radius)))
- return(NULL);
+ if (!(PointerIsValid(center) && PointerIsValid(radius)))
+ return (NULL);
- result = PALLOCTYPE(CIRCLE);
+ result = PALLOCTYPE(CIRCLE);
- result->center.x = center->x;
- result->center.y = center->y;
- result->radius = *radius;
+ result->center.x = center->x;
+ result->center.y = center->y;
+ result->radius = *radius;
- return(result);
+ return (result);
}
-BOX *
-circle_box(CIRCLE *circle)
+BOX *
+circle_box(CIRCLE * circle)
{
- BOX *box;
- double delta;
+ BOX *box;
+ double delta;
- if (!PointerIsValid(circle))
- return(NULL);
+ if (!PointerIsValid(circle))
+ return (NULL);
- box = PALLOCTYPE(BOX);
+ box = PALLOCTYPE(BOX);
- delta = circle->radius / sqrt(2.0e0);
+ delta = circle->radius / sqrt(2.0e0);
- box->high.x = circle->center.x + delta;
- box->low.x = circle->center.x - delta;
- box->high.y = circle->center.y + delta;
- box->low.y = circle->center.y - delta;
+ box->high.x = circle->center.x + delta;
+ box->low.x = circle->center.x - delta;
+ box->high.y = circle->center.y + delta;
+ box->low.y = circle->center.y - delta;
- return(box);
-} /* circle_box() */
+ return (box);
+} /* circle_box() */
/* box_circle()
* Convert a box to a circle.
*/
-CIRCLE *
-box_circle(BOX *box)
+CIRCLE *
+box_circle(BOX * box)
{
- CIRCLE *circle;
+ CIRCLE *circle;
- if (!PointerIsValid(box))
- return(NULL);
+ if (!PointerIsValid(box))
+ return (NULL);
- circle = PALLOCTYPE(CIRCLE);
+ circle = PALLOCTYPE(CIRCLE);
- circle->center.x = (box->high.x + box->low.x) / 2;
- circle->center.y = (box->high.y + box->low.y) / 2;
+ circle->center.x = (box->high.x + box->low.x) / 2;
+ circle->center.y = (box->high.y + box->low.y) / 2;
- circle->radius = point_dt(&circle->center, &box->high);
+ circle->radius = point_dt(&circle->center, &box->high);
- return(circle);
-} /* box_circle() */
+ return (circle);
+} /* box_circle() */
-POLYGON *circle_poly(int npts, CIRCLE *circle)
+POLYGON *
+circle_poly(int npts, CIRCLE * circle)
{
- POLYGON *poly;
- int size;
- int i;
- double angle;
+ POLYGON *poly;
+ int size;
+ int i;
+ double angle;
- if (!PointerIsValid(circle))
- return(NULL);
+ if (!PointerIsValid(circle))
+ return (NULL);
- if (FPzero(circle->radius) || (npts < 2))
- elog (WARN, "Unable to convert circle to polygon", NULL);
+ if (FPzero(circle->radius) || (npts < 2))
+ elog(WARN, "Unable to convert circle to polygon", NULL);
- size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * npts);
- poly = PALLOC(size);
+ size = offsetof(POLYGON, p[0]) + (sizeof(poly->p[0]) * npts);
+ poly = PALLOC(size);
- memset((char *) poly, 0, size); /* zero any holes */
- poly->size = size;
- poly->npts = npts;
+ memset((char *) poly, 0, size); /* zero any holes */
+ poly->size = size;
+ poly->npts = npts;
- for (i=0;i<npts;i++) {
- angle = i*(2*PI/npts);
- poly->p[i].x = circle->center.x - (circle->radius*cos(angle));
- poly->p[i].y = circle->center.y + (circle->radius*sin(angle));
- }
+ for (i = 0; i < npts; i++)
+ {
+ angle = i * (2 * PI / npts);
+ poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
+ poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
+ }
- make_bound_box(poly);
+ make_bound_box(poly);
- return(poly);
+ return (poly);
}
-/* poly_circle - convert polygon to circle
+/* poly_circle - convert polygon to circle
*
* XXX This algorithm should use weighted means of line segments
- * rather than straight average values of points - tgl 97/01/21.
+ * rather than straight average values of points - tgl 97/01/21.
*/
-CIRCLE *poly_circle(POLYGON *poly)
+CIRCLE *
+poly_circle(POLYGON * poly)
{
- CIRCLE *circle;
- int i;
+ CIRCLE *circle;
+ int i;
- if (!PointerIsValid(poly))
- return(NULL);
+ if (!PointerIsValid(poly))
+ return (NULL);
- if (poly->npts < 2)
- elog (WARN, "Unable to convert polygon to circle", NULL);
+ if (poly->npts < 2)
+ elog(WARN, "Unable to convert polygon to circle", NULL);
- circle = PALLOCTYPE(CIRCLE);
+ circle = PALLOCTYPE(CIRCLE);
- circle->center.x = 0;
- circle->center.y = 0;
- circle->radius = 0;
+ circle->center.x = 0;
+ circle->center.y = 0;
+ circle->radius = 0;
- for (i=0;i<poly->npts;i++) {
- circle->center.x += poly->p[i].x;
- circle->center.y += poly->p[i].y;
- }
- circle->center.x /= poly->npts;
- circle->center.y /= poly->npts;
+ for (i = 0; i < poly->npts; i++)
+ {
+ circle->center.x += poly->p[i].x;
+ circle->center.y += poly->p[i].y;
+ }
+ circle->center.x /= poly->npts;
+ circle->center.y /= poly->npts;
- for (i=0;i<poly->npts;i++) {
- circle->radius += point_dt( &poly->p[i], &circle->center);
- }
- circle->radius /= poly->npts;
+ for (i = 0; i < poly->npts; i++)
+ {
+ circle->radius += point_dt(&poly->p[i], &circle->center);
+ }
+ circle->radius /= poly->npts;
- if (FPzero(circle->radius))
- elog (WARN, "Unable to convert polygon to circle", NULL);
+ if (FPzero(circle->radius))
+ elog(WARN, "Unable to convert polygon to circle", NULL);
- return(circle);
-} /* poly_circle() */
+ return (circle);
+} /* poly_circle() */
/***********************************************************************
**
- ** Private routines for multiple types.
+ ** Private routines for multiple types.
**
***********************************************************************/
#define HIT_IT INT_MAX
static int
-point_inside( Point *p, int npts, Point plist[])
+point_inside(Point * p, int npts, Point plist[])
{
- double x0, y0;
- double px, py;
+ double x0,
+ y0;
+ double px,
+ py;
- int i;
- double x, y;
- int cross, crossnum;
+ int i;
+ double x,
+ y;
+ int cross,
+ crossnum;
/*
* We calculate crossnum, which is twice the crossing number of a
@@ -3704,36 +4084,41 @@ point_inside( Point *p, int npts, Point plist[])
* positive X-axis.
*/
- crossnum = 0;
- i = 0;
- if (npts <= 0) return 0;
+ crossnum = 0;
+ i = 0;
+ if (npts <= 0)
+ return 0;
+
+ x0 = plist[0].x - p->x;
+ y0 = plist[0].y - p->y;
- x0 = plist[0].x - p->x;
- y0 = plist[0].y - p->y;
+ px = x0;
+ py = y0;
+ for (i = 1; i < npts; i++)
+ {
+ x = plist[i].x - p->x;
+ y = plist[i].y - p->y;
- px = x0;
- py = y0;
- for (i = 1; i < npts; i++) {
- x = plist[i].x - p->x;
- y = plist[i].y - p->y;
+ if ((cross = lseg_crossing(x, y, px, py)) == HIT_IT)
+ {
+ return 2;
+ }
+ crossnum += cross;
- if ( (cross = lseg_crossing( x, y, px, py)) == HIT_IT ) {
- return 2;
+ px = x;
+ py = y;
+ }
+ if ((cross = lseg_crossing(x0, y0, px, py)) == HIT_IT)
+ {
+ return 2;
}
crossnum += cross;
-
- px = x;
- py = y;
- }
- if ( (cross = lseg_crossing( x0, y0, px, py)) == HIT_IT ) {
- return 2;
- }
- crossnum += cross;
- if ( crossnum != 0 ) {
- return 1;
- }
- return 0;
-} /* point_inside() */
+ if (crossnum != 0)
+ {
+ return 1;
+ }
+ return 0;
+} /* point_inside() */
/* lseg_crossing()
@@ -3745,91 +4130,115 @@ point_inside( Point *p, int npts, Point plist[])
*/
static int
-lseg_crossing( double x, double y, double px, double py)
+lseg_crossing(double x, double y, double px, double py)
{
- double z;
- int sgn;
+ double z;
+ int sgn;
- /* If (px,py) = (0,0) and not first call we have already sent HIT_IT */
+ /* If (px,py) = (0,0) and not first call we have already sent HIT_IT */
- if (FPzero( y)) {
- if (FPzero( x)) {
- return(HIT_IT);
+ if (FPzero(y))
+ {
+ if (FPzero(x))
+ {
+ return (HIT_IT);
- } else if (FPgt( x, 0)) {
- if (FPzero( py)) return(FPgt( px, 0)? 0 : HIT_IT);
- return(FPlt( py, 0)? 1 : -1);
+ }
+ else if (FPgt(x, 0))
+ {
+ if (FPzero(py))
+ return (FPgt(px, 0) ? 0 : HIT_IT);
+ return (FPlt(py, 0) ? 1 : -1);
- } else { /* x < 0 */
- if (FPzero( py)) return(FPlt( px, 0)? 0 : HIT_IT);
- return(0);
+ }
+ else
+ { /* x < 0 */
+ if (FPzero(py))
+ return (FPlt(px, 0) ? 0 : HIT_IT);
+ return (0);
+ }
}
- }
- /* Now we know y != 0; set sgn to sign of y */
- sgn = (FPgt( y, 0)? 1 : -1);
- if (FPzero( py)) return(FPlt( px, 0)? 0 : sgn);
+ /* Now we know y != 0; set sgn to sign of y */
+ sgn = (FPgt(y, 0) ? 1 : -1);
+ if (FPzero(py))
+ return (FPlt(px, 0) ? 0 : sgn);
- if (FPgt( (sgn * py), 0)) { /* y and py have same sign */
- return(0);
+ if (FPgt((sgn * py), 0))
+ { /* y and py have same sign */
+ return (0);
- } else { /* y and py have opposite signs */
- if (FPge( x, 0) && FPgt( px, 0)) return(2 * sgn);
- if (FPlt( x, 0) && FPle( px, 0)) return(0);
-
- z = (x-px) * y - (y-py) * x;
- if (FPzero( z)) return(HIT_IT);
- return( FPgt( (sgn*z), 0)? 0 : 2 * sgn);
- }
-} /* lseg_crossing() */
+ }
+ else
+ { /* y and py have opposite signs */
+ if (FPge(x, 0) && FPgt(px, 0))
+ return (2 * sgn);
+ if (FPlt(x, 0) && FPle(px, 0))
+ return (0);
+
+ z = (x - px) * y - (y - py) * x;
+ if (FPzero(z))
+ return (HIT_IT);
+ return (FPgt((sgn * z), 0) ? 0 : 2 * sgn);
+ }
+} /* lseg_crossing() */
-static bool
+static bool
plist_same(int npts, Point p1[], Point p2[])
{
- int i, ii, j;
-
- /* find match for first point */
- for (i = 0; i < npts; i++) {
- if ((FPeq( p2[i].x, p1[0].x))
- && (FPeq( p2[i].y, p1[0].y))) {
-
- /* match found? then look forward through remaining points */
- for (ii = 1, j = i+1; ii < npts; ii++, j++) {
- if (j >= npts) j = 0;
- if ((!FPeq( p2[j].x, p1[ii].x))
- || (!FPeq( p2[j].y, p1[ii].y))) {
+ int i,
+ ii,
+ j;
+
+ /* find match for first point */
+ for (i = 0; i < npts; i++)
+ {
+ if ((FPeq(p2[i].x, p1[0].x))
+ && (FPeq(p2[i].y, p1[0].y)))
+ {
+
+ /* match found? then look forward through remaining points */
+ for (ii = 1, j = i + 1; ii < npts; ii++, j++)
+ {
+ if (j >= npts)
+ j = 0;
+ if ((!FPeq(p2[j].x, p1[ii].x))
+ || (!FPeq(p2[j].y, p1[ii].y)))
+ {
#ifdef GEODEBUG
-printf( "plist_same- %d failed forward match with %d\n", j, ii);
+ printf("plist_same- %d failed forward match with %d\n", j, ii);
#endif
- break;
- }
- }
+ break;
+ }
+ }
#ifdef GEODEBUG
-printf( "plist_same- ii = %d/%d after forward match\n", ii, npts);
+ printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
#endif
- if (ii == npts)
- return(TRUE);
-
- /* match not found forwards? then look backwards */
- for (ii = 1, j = i-1; ii < npts; ii++, j--) {
- if (j < 0) j = (npts-1);
- if ((!FPeq( p2[j].x, p1[ii].x))
- || (!FPeq( p2[j].y, p1[ii].y))) {
+ if (ii == npts)
+ return (TRUE);
+
+ /* match not found forwards? then look backwards */
+ for (ii = 1, j = i - 1; ii < npts; ii++, j--)
+ {
+ if (j < 0)
+ j = (npts - 1);
+ if ((!FPeq(p2[j].x, p1[ii].x))
+ || (!FPeq(p2[j].y, p1[ii].y)))
+ {
#ifdef GEODEBUG
-printf( "plist_same- %d failed reverse match with %d\n", j, ii);
+ printf("plist_same- %d failed reverse match with %d\n", j, ii);
#endif
- break;
- }
- }
+ break;
+ }
+ }
#ifdef GEODEBUG
-printf( "plist_same- ii = %d/%d after reverse match\n", ii, npts);
+ printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
#endif
- if (ii == npts)
- return(TRUE);
+ if (ii == npts)
+ return (TRUE);
+ }
}
- }
-
- return(FALSE);
-} /* plist_same() */
+ return (FALSE);
+} /* plist_same() */
diff --git a/src/backend/utils/adt/geo_selfuncs.c b/src/backend/utils/adt/geo_selfuncs.c
index f0f7bc48d5f..240639d6eda 100644
--- a/src/backend/utils/adt/geo_selfuncs.c
+++ b/src/backend/utils/adt/geo_selfuncs.c
@@ -1,16 +1,16 @@
/*-------------------------------------------------------------------------
*
* geo-selfuncs.c--
- * Selectivity routines registered in the operator catalog in the
- * "oprrest" and "oprjoin" attributes.
+ * Selectivity routines registered in the operator catalog in the
+ * "oprrest" and "oprjoin" attributes.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.3 1997/08/19 21:34:40 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/geo_selfuncs.c,v 1.4 1997/09/07 04:50:20 momjian Exp $
*
- * XXX These are totally bogus.
+ * XXX These are totally bogus.
*
*-------------------------------------------------------------------------
*/
@@ -22,112 +22,116 @@
#include "utils/builtins.h"
float64
-areasel(Oid opid,
- Oid relid,
- AttrNumber attno,
- char *value,
- int32 flag)
+areasel(Oid opid,
+ Oid relid,
+ AttrNumber attno,
+ char *value,
+ int32 flag)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 4.0;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ *result = 1.0 / 4.0;
+ return (result);
}
float64
areajoinsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- char *value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ char *value,
+ int32 flag)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 4.0;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ *result = 1.0 / 4.0;
+ return (result);
}
/*
- * Selectivity functions for rtrees. These are bogus -- unless we know
- * the actual key distribution in the index, we can't make a good prediction
- * of the selectivity of these operators.
+ * Selectivity functions for rtrees. These are bogus -- unless we know
+ * the actual key distribution in the index, we can't make a good prediction
+ * of the selectivity of these operators.
*
- * In general, rtrees need to search multiple subtrees in order to guarantee
- * that all occurrences of the same key have been found. Because of this,
- * the heuristic selectivity functions we return are higher than they would
- * otherwise be.
+ * In general, rtrees need to search multiple subtrees in order to guarantee
+ * that all occurrences of the same key have been found. Because of this,
+ * the heuristic selectivity functions we return are higher than they would
+ * otherwise be.
*/
/*
- * left_sel -- How likely is a box to be strictly left of (right of, above,
- * below) a given box?
+ * left_sel -- How likely is a box to be strictly left of (right of, above,
+ * below) a given box?
*/
#ifdef NOT_USED
float64
leftsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- char *value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ char *value,
+ int32 flag)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 6.0;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ *result = 1.0 / 6.0;
+ return (result);
}
+
#endif
#ifdef NOT_USED
float64
leftjoinsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- char *value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ char *value,
+ int32 flag)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 6.0;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ *result = 1.0 / 6.0;
+ return (result);
}
+
#endif
/*
- * contsel -- How likely is a box to contain (be contained by) a given box?
+ * contsel -- How likely is a box to contain (be contained by) a given box?
*/
#ifdef NOT_USED
float64
contsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- char *value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ char *value,
+ int32 flag)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 10.0;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ *result = 1.0 / 10.0;
+ return (result);
}
+
#endif
#ifdef NOT_USED
float64
contjoinsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- char *value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ char *value,
+ int32 flag)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 10.0;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ *result = 1.0 / 10.0;
+ return (result);
}
+
#endif
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index 57f5b32d132..c7ea5f71fcc 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -1,29 +1,29 @@
/*-------------------------------------------------------------------------
*
* int.c--
- * Functions for the built-in integer types.
+ * Functions for the built-in integer types.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.4 1997/03/14 23:20:26 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.5 1997/09/07 04:50:21 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* OLD COMMENTS
- * I/O routines:
- * int2in, int2out, int28in, int28out, int4in, int4out
- * Conversion routines:
- * itoi
- * Boolean operators:
- * inteq, intne, intlt, intle, intgt, intge
- * Arithmetic operators:
- * intpl, intmi, int4mul, intdiv
+ * I/O routines:
+ * int2in, int2out, int28in, int28out, int4in, int4out
+ * Conversion routines:
+ * itoi
+ * Boolean operators:
+ * inteq, intne, intlt, intle, intgt, intge
+ * Arithmetic operators:
+ * intpl, intmi, int4mul, intdiv
*
- * Arithmetic operators:
- * intmod, int4fac
+ * Arithmetic operators:
+ * intmod, int4fac
*
* XXX makes massive and possibly unwarranted type promotion assumptions.
* fix me when we figure out what we want to do about ANSIfication...
@@ -32,311 +32,482 @@
#include "postgres.h"
#include "fmgr.h"
-#include "utils/builtins.h" /* where the declarations go */
+#include "utils/builtins.h" /* where the declarations go */
-/*****************************************************************************
- * USER I/O ROUTINES *
+/*****************************************************************************
+ * USER I/O ROUTINES *
*****************************************************************************/
/*
- * int2in - converts "num" to short
+ * int2in - converts "num" to short
*/
-int32 int2in(char *num)
+int32
+int2in(char *num)
{
- return((int32) pg_atoi(num, sizeof(int16), '\0'));
+ return ((int32) pg_atoi(num, sizeof(int16), '\0'));
}
/*
- * int2out - converts short to "num"
+ * int2out - converts short to "num"
*/
-char *int2out(int16 sh)
+char *
+int2out(int16 sh)
{
- char *result;
-
- result = (char *)palloc(7); /* assumes sign, 5 digits, '\0' */
- itoa((int) sh, result);
- return(result);
+ char *result;
+
+ result = (char *) palloc(7);/* assumes sign, 5 digits, '\0' */
+ itoa((int) sh, result);
+ return (result);
}
/*
- * int28in - converts "num num ..." to internal form
+ * int28in - converts "num num ..." to internal form
*
- * Note:
- * Fills any nonexistent digits with NULLs.
+ * Note:
+ * Fills any nonexistent digits with NULLs.
*/
-int16 *int28in(char *shs)
-{
- register int16 (*result)[];
- int nums;
-
- if (shs == NULL)
- return(NULL);
- result = (int16 (*)[]) palloc(sizeof(int16 [8]));
- if ((nums = sscanf(shs, "%hd%hd%hd%hd%hd%hd%hd%hd",
- *result,
- *result + 1,
- *result + 2,
- *result + 3,
- *result + 4,
- *result + 5,
- *result + 6,
- *result + 7)) != 8) {
- do
- (*result)[nums++] = 0;
- while (nums < 8);
- }
- return((int16 *) result);
+int16 *
+int28in(char *shs)
+{
+ register int16(*result)[];
+ int nums;
+
+ if (shs == NULL)
+ return (NULL);
+ result = (int16(*)[]) palloc(sizeof(int16[8]));
+ if ((nums = sscanf(shs, "%hd%hd%hd%hd%hd%hd%hd%hd",
+ *result,
+ *result + 1,
+ *result + 2,
+ *result + 3,
+ *result + 4,
+ *result + 5,
+ *result + 6,
+ *result + 7)) != 8)
+ {
+ do
+ (*result)[nums++] = 0;
+ while (nums < 8);
+ }
+ return ((int16 *) result);
}
/*
- * int28out - converts internal form to "num num ..."
+ * int28out - converts internal form to "num num ..."
*/
-char *int28out(int16 (*shs)[])
-{
- register int num;
- register int16 *sp;
- register char *rp;
- char *result;
-
- if (shs == NULL) {
- result = (char *)palloc(2);
- result[0] = '-';
- result[1] = '\0';
- return(result);
- }
- rp = result = (char *)palloc(8 * 7); /* assumes sign, 5 digits, ' ' */
- sp = *shs;
- for (num = 8; num != 0; num--) {
- itoa(*sp++, rp);
- while (*++rp != '\0')
- ;
- *rp++ = ' ';
- }
- *--rp = '\0';
- return(result);
+char *
+int28out(int16(*shs)[])
+{
+ register int num;
+ register int16 *sp;
+ register char *rp;
+ char *result;
+
+ if (shs == NULL)
+ {
+ result = (char *) palloc(2);
+ result[0] = '-';
+ result[1] = '\0';
+ return (result);
+ }
+ rp = result = (char *) palloc(8 * 7); /* assumes sign, 5 digits,
+ * ' ' */
+ sp = *shs;
+ for (num = 8; num != 0; num--)
+ {
+ itoa(*sp++, rp);
+ while (*++rp != '\0')
+ ;
+ *rp++ = ' ';
+ }
+ *--rp = '\0';
+ return (result);
}
/*
- * int28in - converts "num num ..." to internal form
+ * int28in - converts "num num ..." to internal form
*
- * Note:
- * Fills any nonexistent digits with NULLs.
+ * Note:
+ * Fills any nonexistent digits with NULLs.
*/
-int32 *int44in(char *input_string)
-{
- int32 *foo = (int32 *)palloc(4*sizeof(int32));
- register int i = 0;
-
- i = sscanf(input_string,
- "%d, %d, %d, %d",
- &foo[0],
- &foo[1],
- &foo[2],
- &foo[3]);
- while (i < 4)
- foo[i++] = 0;
-
- return(foo);
+int32 *
+int44in(char *input_string)
+{
+ int32 *foo = (int32 *) palloc(4 * sizeof(int32));
+ register int i = 0;
+
+ i = sscanf(input_string,
+ "%d, %d, %d, %d",
+ &foo[0],
+ &foo[1],
+ &foo[2],
+ &foo[3]);
+ while (i < 4)
+ foo[i++] = 0;
+
+ return (foo);
}
/*
- * int28out - converts internal form to "num num ..."
+ * int28out - converts internal form to "num num ..."
*/
-char *int44out(int32 an_array[])
-{
- int temp = 4;
- char *output_string = NULL;
- int i;
-
- if ( temp > 0 ) {
- char *walk;
- output_string = (char *)palloc(16*temp); /* assume 15 digits + sign */
- walk = output_string;
- for ( i = 0 ; i < temp ; i++ ) {
- itoa(an_array[i],walk);
- while (*++walk != '\0')
- ;
- *walk++ = ' ';
+char *
+int44out(int32 an_array[])
+{
+ int temp = 4;
+ char *output_string = NULL;
+ int i;
+
+ if (temp > 0)
+ {
+ char *walk;
+
+ output_string = (char *) palloc(16 * temp); /* assume 15 digits +
+ * sign */
+ walk = output_string;
+ for (i = 0; i < temp; i++)
+ {
+ itoa(an_array[i], walk);
+ while (*++walk != '\0')
+ ;
+ *walk++ = ' ';
+ }
+ *--walk = '\0';
}
- *--walk = '\0';
- }
- return(output_string);
+ return (output_string);
}
-/*****************************************************************************
- * PUBLIC ROUTINES *
+/*****************************************************************************
+ * PUBLIC ROUTINES *
*****************************************************************************/
/*
- * int4in - converts "num" to int4
+ * int4in - converts "num" to int4
*/
-int32 int4in(char *num)
+int32
+int4in(char *num)
{
- return(pg_atoi(num, sizeof(int32), '\0'));
+ return (pg_atoi(num, sizeof(int32), '\0'));
}
/*
- * int4out - converts int4 to "num"
+ * int4out - converts int4 to "num"
*/
-char *int4out(int32 l)
+char *
+int4out(int32 l)
{
- char *result;
-
- result = (char *)palloc(12); /* assumes sign, 10 digits, '\0' */
- ltoa(l, result);
- return(result);
+ char *result;
+
+ result = (char *) palloc(12); /* assumes sign, 10 digits, '\0' */
+ ltoa(l, result);
+ return (result);
}
/*
- * ===================
- * CONVERSION ROUTINES
- * ===================
+ * ===================
+ * CONVERSION ROUTINES
+ * ===================
*/
-int32 i2toi4(int16 arg1)
+int32
+i2toi4(int16 arg1)
{
- return((int32) arg1);
+ return ((int32) arg1);
}
-int16 i4toi2(int32 arg1)
+int16
+i4toi2(int32 arg1)
{
- if (arg1< -0x8000)
- elog(NOTICE, "i4toi2: \"%d\" causes int2 underflow", arg1);
- if (arg1 > 0x7FFF)
- elog(NOTICE, "i4toi2: \"%d\" causes int2 overflow", arg1);
-
- return((int16) arg1);
+ if (arg1 < -0x8000)
+ elog(NOTICE, "i4toi2: \"%d\" causes int2 underflow", arg1);
+ if (arg1 > 0x7FFF)
+ elog(NOTICE, "i4toi2: \"%d\" causes int2 overflow", arg1);
+
+ return ((int16) arg1);
}
/*
- * =========================
- * BOOLEAN OPERATOR ROUTINES
- * =========================
+ * =========================
+ * BOOLEAN OPERATOR ROUTINES
+ * =========================
*/
/*
- * inteq - returns 1 iff arg1 == arg2
- * intne - returns 1 iff arg1 != arg2
- * intlt - returns 1 iff arg1 < arg2
- * intle - returns 1 iff arg1 <= arg2
- * intgt - returns 1 iff arg1 > arg2
- * intge - returns 1 iff arg1 >= arg2
+ * inteq - returns 1 iff arg1 == arg2
+ * intne - returns 1 iff arg1 != arg2
+ * intlt - returns 1 iff arg1 < arg2
+ * intle - returns 1 iff arg1 <= arg2
+ * intgt - returns 1 iff arg1 > arg2
+ * intge - returns 1 iff arg1 >= arg2
*/
-bool int4eq(int32 arg1, int32 arg2) { return(arg1 == arg2); }
-bool int4ne(int32 arg1, int32 arg2) { return(arg1 != arg2); }
-bool int4lt(int32 arg1, int32 arg2) { return(arg1 < arg2); }
-bool int4le(int32 arg1, int32 arg2) { return(arg1 <= arg2); }
-bool int4gt(int32 arg1, int32 arg2) { return(arg1 > arg2); }
-bool int4ge(int32 arg1, int32 arg2) { return(arg1 >= arg2); }
-
-bool int2eq(int16 arg1, int16 arg2) { return(arg1 == arg2); }
-bool int2ne(int16 arg1, int16 arg2) { return(arg1 != arg2); }
-bool int2lt(int16 arg1, int16 arg2) { return(arg1 < arg2); }
-bool int2le(int16 arg1, int16 arg2) { return(arg1 <= arg2); }
-bool int2gt(int16 arg1, int16 arg2) { return(arg1 > arg2); }
-bool int2ge(int16 arg1, int16 arg2) { return(arg1 >= arg2); }
-
-bool int24eq(int32 arg1, int32 arg2) { return(arg1 == arg2); }
-bool int24ne(int32 arg1, int32 arg2) { return(arg1 != arg2); }
-bool int24lt(int32 arg1, int32 arg2) { return(arg1 < arg2); }
-bool int24le(int32 arg1, int32 arg2) { return(arg1 <= arg2); }
-bool int24gt(int32 arg1, int32 arg2) { return(arg1 > arg2); }
-bool int24ge(int32 arg1, int32 arg2) { return(arg1 >= arg2); }
-
-bool int42eq(int32 arg1, int32 arg2) { return(arg1 == arg2); }
-bool int42ne(int32 arg1, int32 arg2) { return(arg1 != arg2); }
-bool int42lt(int32 arg1, int32 arg2) { return(arg1 < arg2); }
-bool int42le(int32 arg1, int32 arg2) { return(arg1 <= arg2); }
-bool int42gt(int32 arg1, int32 arg2) { return(arg1 > arg2); }
-bool int42ge(int32 arg1, int32 arg2) { return(arg1 >= arg2); }
-
-
-bool keyfirsteq(int16 *arg1, int16 arg2) { return(*arg1 == arg2); }
+bool int4eq(int32 arg1, int32 arg2)
+{
+ return (arg1 == arg2);
+}
+bool int4ne(int32 arg1, int32 arg2)
+{
+ return (arg1 != arg2);
+}
+bool int4lt(int32 arg1, int32 arg2)
+{
+ return (arg1 < arg2);
+}
+bool int4le(int32 arg1, int32 arg2)
+{
+ return (arg1 <= arg2);
+}
+bool int4gt(int32 arg1, int32 arg2)
+{
+ return (arg1 > arg2);
+}
+bool int4ge(int32 arg1, int32 arg2)
+{
+ return (arg1 >= arg2);
+}
+
+bool int2eq(int16 arg1, int16 arg2)
+{
+ return (arg1 == arg2);
+}
+bool int2ne(int16 arg1, int16 arg2)
+{
+ return (arg1 != arg2);
+}
+bool int2lt(int16 arg1, int16 arg2)
+{
+ return (arg1 < arg2);
+}
+bool int2le(int16 arg1, int16 arg2)
+{
+ return (arg1 <= arg2);
+}
+bool int2gt(int16 arg1, int16 arg2)
+{
+ return (arg1 > arg2);
+}
+bool int2ge(int16 arg1, int16 arg2)
+{
+ return (arg1 >= arg2);
+}
+
+bool int24eq(int32 arg1, int32 arg2)
+{
+ return (arg1 == arg2);
+}
+bool int24ne(int32 arg1, int32 arg2)
+{
+ return (arg1 != arg2);
+}
+bool int24lt(int32 arg1, int32 arg2)
+{
+ return (arg1 < arg2);
+}
+bool int24le(int32 arg1, int32 arg2)
+{
+ return (arg1 <= arg2);
+}
+bool int24gt(int32 arg1, int32 arg2)
+{
+ return (arg1 > arg2);
+}
+bool int24ge(int32 arg1, int32 arg2)
+{
+ return (arg1 >= arg2);
+}
+
+bool int42eq(int32 arg1, int32 arg2)
+{
+ return (arg1 == arg2);
+}
+bool int42ne(int32 arg1, int32 arg2)
+{
+ return (arg1 != arg2);
+}
+bool int42lt(int32 arg1, int32 arg2)
+{
+ return (arg1 < arg2);
+}
+bool int42le(int32 arg1, int32 arg2)
+{
+ return (arg1 <= arg2);
+}
+bool int42gt(int32 arg1, int32 arg2)
+{
+ return (arg1 > arg2);
+}
+bool int42ge(int32 arg1, int32 arg2)
+{
+ return (arg1 >= arg2);
+}
+
+
+bool keyfirsteq(int16 * arg1, int16 arg2)
+{
+ return (*arg1 == arg2);
+}
/*
- * int[24]pl - returns arg1 + arg2
- * int[24]mi - returns arg1 - arg2
- * int[24]mul - returns arg1 * arg2
- * int[24]div - returns arg1 / arg2
+ * int[24]pl - returns arg1 + arg2
+ * int[24]mi - returns arg1 - arg2
+ * int[24]mul - returns arg1 * arg2
+ * int[24]div - returns arg1 / arg2
*/
-int32 int4um(int32 arg) { return(-arg); }
-int32 int4pl(int32 arg1, int32 arg2) { return(arg1 + arg2); }
-int32 int4mi(int32 arg1, int32 arg2) { return(arg1 - arg2); }
-int32 int4mul(int32 arg1, int32 arg2) { return(arg1 * arg2); }
-int32 int4div(int32 arg1, int32 arg2) { return(arg1 / arg2); }
-int32 int4inc(int32 arg) { return(arg + (int32)1); }
-
-int16 int2um(int16 arg) { return(-arg); }
-int16 int2pl(int16 arg1, int16 arg2) { return(arg1 + arg2); }
-int16 int2mi(int16 arg1, int16 arg2) { return(arg1 - arg2); }
-int16 int2mul(int16 arg1, int16 arg2) { return(arg1 * arg2); }
-int16 int2div(int16 arg1, int16 arg2) { return(arg1 / arg2); }
-int16 int2inc(int16 arg) { return(arg + (int16)1); }
-
-int32 int24pl(int32 arg1, int32 arg2) { return(arg1 + arg2); }
-int32 int24mi(int32 arg1, int32 arg2) { return(arg1 - arg2); }
-int32 int24mul(int32 arg1, int32 arg2) { return(arg1 * arg2); }
-int32 int24div(int32 arg1, int32 arg2) { return(arg1 / arg2); }
-
-int32 int42pl(int32 arg1, int32 arg2) { return(arg1 + arg2); }
-int32 int42mi(int32 arg1, int32 arg2) { return(arg1 - arg2); }
-int32 int42mul(int32 arg1, int32 arg2) { return(arg1 * arg2); }
-int32 int42div(int32 arg1, int32 arg2) { return(arg1 / arg2); }
-
+int32 int4um(int32 arg)
+{
+ return (-arg);
+}
+int32 int4pl(int32 arg1, int32 arg2)
+{
+ return (arg1 + arg2);
+}
+int32 int4mi(int32 arg1, int32 arg2)
+{
+ return (arg1 - arg2);
+}
+int32 int4mul(int32 arg1, int32 arg2)
+{
+ return (arg1 * arg2);
+}
+int32 int4div(int32 arg1, int32 arg2)
+{
+ return (arg1 / arg2);
+}
+int32 int4inc(int32 arg)
+{
+ return (arg + (int32) 1);
+}
+
+int16 int2um(int16 arg)
+{
+ return (-arg);
+}
+int16 int2pl(int16 arg1, int16 arg2)
+{
+ return (arg1 + arg2);
+}
+int16 int2mi(int16 arg1, int16 arg2)
+{
+ return (arg1 - arg2);
+}
+int16 int2mul(int16 arg1, int16 arg2)
+{
+ return (arg1 * arg2);
+}
+int16 int2div(int16 arg1, int16 arg2)
+{
+ return (arg1 / arg2);
+}
+int16 int2inc(int16 arg)
+{
+ return (arg + (int16) 1);
+}
+
+int32 int24pl(int32 arg1, int32 arg2)
+{
+ return (arg1 + arg2);
+}
+int32 int24mi(int32 arg1, int32 arg2)
+{
+ return (arg1 - arg2);
+}
+int32 int24mul(int32 arg1, int32 arg2)
+{
+ return (arg1 * arg2);
+}
+int32 int24div(int32 arg1, int32 arg2)
+{
+ return (arg1 / arg2);
+}
+
+int32 int42pl(int32 arg1, int32 arg2)
+{
+ return (arg1 + arg2);
+}
+int32 int42mi(int32 arg1, int32 arg2)
+{
+ return (arg1 - arg2);
+}
+int32 int42mul(int32 arg1, int32 arg2)
+{
+ return (arg1 * arg2);
+}
+int32 int42div(int32 arg1, int32 arg2)
+{
+ return (arg1 / arg2);
+}
+
/*
- * int[24]mod - returns arg1 mod arg2
+ * int[24]mod - returns arg1 mod arg2
*/
-int32 int4mod(int32 arg1, int32 arg2) { return(arg1 % arg2); }
-int32 int2mod(int16 arg1, int16 arg2) { return(arg1 % arg2); }
-int32 int24mod(int32 arg1, int32 arg2) { return(arg1 % arg2); }
-int32 int42mod(int32 arg1, int32 arg2) { return(arg1 % arg2); }
-
+int32 int4mod(int32 arg1, int32 arg2)
+{
+ return (arg1 % arg2);
+}
+int32 int2mod(int16 arg1, int16 arg2)
+{
+ return (arg1 % arg2);
+}
+int32 int24mod(int32 arg1, int32 arg2)
+{
+ return (arg1 % arg2);
+}
+int32 int42mod(int32 arg1, int32 arg2)
+{
+ return (arg1 % arg2);
+}
+
/*
- * int[24]fac - returns arg1!
+ * int[24]fac - returns arg1!
*/
-int32 int4fac(int32 arg1)
+int32
+int4fac(int32 arg1)
{
- int32 result;
-
- if (arg1 < 1)
- result = 0;
- else
- for (result = 1; arg1 > 0; --arg1)
- result *= arg1;
- return(result);
+ int32 result;
+
+ if (arg1 < 1)
+ result = 0;
+ else
+ for (result = 1; arg1 > 0; --arg1)
+ result *= arg1;
+ return (result);
}
-int32 int2fac(int16 arg1)
+int32
+int2fac(int16 arg1)
{
- int16 result;
-
- if (arg1 < 1)
- result = 0;
- else
- for (result = 1; arg1 > 0; --arg1)
- result *= arg1;
- return(result);
+ int16 result;
+
+ if (arg1 < 1)
+ result = 0;
+ else
+ for (result = 1; arg1 > 0; --arg1)
+ result *= arg1;
+ return (result);
}
-int16 int2larger(int16 arg1, int16 arg2)
+int16
+int2larger(int16 arg1, int16 arg2)
{
- return ((arg1 > arg2) ? arg1 : arg2);
+ return ((arg1 > arg2) ? arg1 : arg2);
}
-int16 int2smaller(int16 arg1, int16 arg2)
+int16
+int2smaller(int16 arg1, int16 arg2)
{
- return ((arg1 < arg2) ? arg1 : arg2);
+ return ((arg1 < arg2) ? arg1 : arg2);
}
-int32 int4larger(int32 arg1, int32 arg2)
+int32
+int4larger(int32 arg1, int32 arg2)
{
- return ((arg1 > arg2) ? arg1 : arg2);
+ return ((arg1 > arg2) ? arg1 : arg2);
}
-int32 int4smaller(int32 arg1, int32 arg2)
+int32
+int4smaller(int32 arg1, int32 arg2)
{
- return ((arg1 < arg2) ? arg1 : arg2);
+ return ((arg1 < arg2) ? arg1 : arg2);
}
diff --git a/src/backend/utils/adt/like.c b/src/backend/utils/adt/like.c
index 50b31514b2a..a3fdbce8855 100644
--- a/src/backend/utils/adt/like.c
+++ b/src/backend/utils/adt/like.c
@@ -1,225 +1,236 @@
/*-------------------------------------------------------------------------
*
* like.c--
- * like expression handling code.
+ * like expression handling code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * /usr/local/devel/pglite/cvs/src/backend/utils/adt/like.c,v 1.1 1995/07/30 23:55:36 emkxp01 Exp
+ * /usr/local/devel/pglite/cvs/src/backend/utils/adt/like.c,v 1.1 1995/07/30 23:55:36 emkxp01 Exp
*
*
- * NOTES
- * A big hack of the regexp.c code!! Contributed by
- * Keith Parks <[email protected]> (7/95).
+ * NOTES
+ * A big hack of the regexp.c code!! Contributed by
+ * Keith Parks <[email protected]> (7/95).
*
*
*-------------------------------------------------------------------------
*/
#include <string.h>
-#include "postgres.h" /* postgres system include file */
+#include "postgres.h" /* postgres system include file */
#include "utils/palloc.h"
-#include "utils/builtins.h" /* where the function declarations go */
+#include "utils/builtins.h" /* where the function declarations go */
-static int like(char *text, char *p);
+static int like(char *text, char *p);
/*
- * interface routines called by the function manager
+ * interface routines called by the function manager
*/
/*
fixedlen_like:
a generic fixed length like routine
- s - the string to match against (not necessarily null-terminated)
- p - the pattern
- charlen - the length of the string
+ s - the string to match against (not necessarily null-terminated)
+ p - the pattern
+ charlen - the length of the string
*/
-static bool
-fixedlen_like(char *s, struct varlena* p, int charlen)
+static bool
+fixedlen_like(char *s, struct varlena * p, int charlen)
{
- char *sterm, *pterm;
- int result;
-
- if (!s || !p)
- return FALSE;
-
- /* be sure sterm is null-terminated */
- sterm = (char *) palloc(charlen + 1);
- strNcpy(sterm, s, charlen);
-
- /* p is a text = varlena, not a string so we have to make
- * a string from the vl_data field of the struct. */
-
- /* palloc the length of the text + the null character */
- pterm = (char *) palloc(VARSIZE(p) - VARHDRSZ + 1);
- memmove(pterm, VARDATA(p), VARSIZE(p) - VARHDRSZ);
- *(pterm + VARSIZE(p) - VARHDRSZ) = (char)NULL;
-
- /* do the regexp matching */
- result = like(sterm, pterm);
-
- pfree(sterm);
- pfree(pterm);
-
- return ((bool) result);
+ char *sterm,
+ *pterm;
+ int result;
+
+ if (!s || !p)
+ return FALSE;
+
+ /* be sure sterm is null-terminated */
+ sterm = (char *) palloc(charlen + 1);
+ strNcpy(sterm, s, charlen);
+
+ /*
+ * p is a text = varlena, not a string so we have to make a string
+ * from the vl_data field of the struct.
+ */
+
+ /* palloc the length of the text + the null character */
+ pterm = (char *) palloc(VARSIZE(p) - VARHDRSZ + 1);
+ memmove(pterm, VARDATA(p), VARSIZE(p) - VARHDRSZ);
+ *(pterm + VARSIZE(p) - VARHDRSZ) = (char) NULL;
+
+ /* do the regexp matching */
+ result = like(sterm, pterm);
+
+ pfree(sterm);
+ pfree(pterm);
+
+ return ((bool) result);
}
-bool
-char2like(uint16 arg1, struct varlena *p)
+bool
+char2like(uint16 arg1, struct varlena * p)
{
- char *s = (char *) &arg1;
- return (fixedlen_like(s, p, 2));
-}
+ char *s = (char *) &arg1;
-bool
-char2nlike(uint16 arg1, struct varlena *p)
+ return (fixedlen_like(s, p, 2));
+}
+
+bool
+char2nlike(uint16 arg1, struct varlena * p)
{
- return (!char2like(arg1, p));
+ return (!char2like(arg1, p));
}
-bool
-char4like(uint32 arg1, struct varlena *p)
+bool
+char4like(uint32 arg1, struct varlena * p)
{
- char *s = (char *) &arg1;
- return (fixedlen_like(s, p, 4));
+ char *s = (char *) &arg1;
+
+ return (fixedlen_like(s, p, 4));
}
-bool
-char4nlike(uint32 arg1, struct varlena *p)
+bool
+char4nlike(uint32 arg1, struct varlena * p)
{
- return (!char4like(arg1, p));
+ return (!char4like(arg1, p));
}
-bool
-char8like(char *s, struct varlena *p)
+bool
+char8like(char *s, struct varlena * p)
{
- return (fixedlen_like(s, p, 8));
+ return (fixedlen_like(s, p, 8));
}
-bool
-char8nlike(char *s, struct varlena *p)
+bool
+char8nlike(char *s, struct varlena * p)
{
- return (!char8like(s, p));
+ return (!char8like(s, p));
}
-bool
-char16like(char *s, struct varlena *p)
+bool
+char16like(char *s, struct varlena * p)
{
- return (fixedlen_like(s, p, 16));
+ return (fixedlen_like(s, p, 16));
}
-bool
-char16nlike(char *s, struct varlena *p)
+
+bool
+char16nlike(char *s, struct varlena * p)
{
- return (!char16like(s, p));
+ return (!char16like(s, p));
}
-bool
-namelike(NameData *n, struct varlena *p)
+bool
+namelike(NameData * n, struct varlena * p)
{
- if (!n) return FALSE;
- return (fixedlen_like(n->data, p, NAMEDATALEN));
+ if (!n)
+ return FALSE;
+ return (fixedlen_like(n->data, p, NAMEDATALEN));
}
-bool
-namenlike(NameData *s, struct varlena *p)
+bool
+namenlike(NameData * s, struct varlena * p)
{
- return (!namelike(s, p));
+ return (!namelike(s, p));
}
-bool
-textlike(struct varlena *s, struct varlena *p)
+bool
+textlike(struct varlena * s, struct varlena * p)
{
- if (!s) return FALSE;
- return (fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ));
+ if (!s)
+ return FALSE;
+ return (fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ));
}
-bool textnlike(struct varlena *s, struct varlena *p)
+bool
+textnlike(struct varlena * s, struct varlena * p)
{
- return (!textlike(s, p));
+ return (!textlike(s, p));
}
-/* $Revision: 1.6 $
-** "like.c" A first attempt at a LIKE operator for Postgres95.
+/* $Revision: 1.7 $
+** "like.c" A first attempt at a LIKE operator for Postgres95.
+**
+** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
+** Rich $alz is now <[email protected]>.
+** Special thanks to Lars Mathiesen <[email protected]> for the LABORT code.
+**
+** This code was shamelessly stolen from the "pql" code by myself and
+** slightly modified :)
+**
+** All references to the word "star" were replaced by "percent"
+** All references to the word "wild" were replaced by "like"
+**
+** All the nice shell RE matching stuff was replaced by just "_" and "%"
**
-** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
-** Rich $alz is now <[email protected]>.
-** Special thanks to Lars Mathiesen <[email protected]> for the LABORT code.
-**
-** This code was shamelessly stolen from the "pql" code by myself and
-** slightly modified :)
-**
-** All references to the word "star" were replaced by "percent"
-** All references to the word "wild" were replaced by "like"
-**
-** All the nice shell RE matching stuff was replaced by just "_" and "%"
-**
-** As I don't have a copy of the SQL standard handy I wasn't sure whether
-** to leave in the '\' escape character handling. (I suspect the standard
-** handles "%%" as a single literal percent)
+** As I don't have a copy of the SQL standard handy I wasn't sure whether
+** to leave in the '\' escape character handling. (I suspect the standard
+** handles "%%" as a single literal percent)
**
-** Keith Parks. <[email protected]>
+** Keith Parks. <[email protected]>
**
-** [SQL92 lets you specify the escape character by saying
-** LIKE <pattern> ESCAPE <escape character>. We are a small operation
-** so we force you to use '\'. - ay 7/95]
+** [SQL92 lets you specify the escape character by saying
+** LIKE <pattern> ESCAPE <escape character>. We are a small operation
+** so we force you to use '\'. - ay 7/95]
**
*/
-#define LIKE_TRUE 1
-#define LIKE_FALSE 0
-#define LIKE_ABORT -1
+#define LIKE_TRUE 1
+#define LIKE_FALSE 0
+#define LIKE_ABORT -1
/*
-** Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
+** Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
*/
static int
DoMatch(register char *text, register char *p)
{
- register int matched;
-
- for ( ; *p; text++, p++) {
- if (*text == '\0' && *p != '%')
- return LIKE_ABORT;
- switch (*p) {
- case '\\':
- /* Literal match with following character. */
- p++;
- /* FALLTHROUGH */
- default:
- if (*text != *p)
- return LIKE_FALSE;
- continue;
- case '_':
- /* Match anything. */
- continue;
- case '%':
- while (*++p == '%')
- /* Consecutive percents act just like one. */
- continue;
- if (*p == '\0')
- /* Trailing percent matches everything. */
- return LIKE_TRUE;
- while (*text)
- if ((matched = DoMatch(text++, p)) != LIKE_FALSE)
- return matched;
- return LIKE_ABORT;
+ register int matched;
+
+ for (; *p; text++, p++)
+ {
+ if (*text == '\0' && *p != '%')
+ return LIKE_ABORT;
+ switch (*p)
+ {
+ case '\\':
+ /* Literal match with following character. */
+ p++;
+ /* FALLTHROUGH */
+ default:
+ if (*text != *p)
+ return LIKE_FALSE;
+ continue;
+ case '_':
+ /* Match anything. */
+ continue;
+ case '%':
+ while (*++p == '%')
+ /* Consecutive percents act just like one. */
+ continue;
+ if (*p == '\0')
+ /* Trailing percent matches everything. */
+ return LIKE_TRUE;
+ while (*text)
+ if ((matched = DoMatch(text++, p)) != LIKE_FALSE)
+ return matched;
+ return LIKE_ABORT;
+ }
}
- }
- return *text == '\0';
+ return *text == '\0';
}
/*
-** User-level routine. Returns TRUE or FALSE.
+** User-level routine. Returns TRUE or FALSE.
*/
static int
like(char *text, char *p)
{
- if (p[0] == '%' && p[1] == '\0')
- return TRUE;
- return (DoMatch(text, p) == LIKE_TRUE);
+ if (p[0] == '%' && p[1] == '\0')
+ return TRUE;
+ return (DoMatch(text, p) == LIKE_TRUE);
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 95dfcfc8ca1..f04152cf6d2 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* misc.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/misc.c,v 1.7 1997/07/28 00:55:58 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/misc.c,v 1.8 1997/09/07 04:50:23 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,70 +18,73 @@
#include "catalog/pg_type.h"
#include "utils/builtins.h"
-#include "port-protos.h" /* For random(), sometimes */
+#include "port-protos.h" /* For random(), sometimes */
/*-------------------------------------------------------------------------
- * Check if data is Null
+ * Check if data is Null
*/
bool
-nullvalue(Datum value, bool *isNull)
+nullvalue(Datum value, bool * isNull)
{
- if (*isNull) {
- *isNull = false;
- return(true);
- }
- return(false);
-
+ if (*isNull)
+ {
+ *isNull = false;
+ return (true);
+ }
+ return (false);
+
}
/*----------------------------------------------------------------------*
- * check if data is not Null *
+ * check if data is not Null *
*--------------------------------------------------------------------- */
bool
-nonnullvalue(Datum value, bool *isNull)
+nonnullvalue(Datum value, bool * isNull)
{
- if (*isNull) {
- *isNull = false;
- return(false);
- }
- return(true);
-
+ if (*isNull)
+ {
+ *isNull = false;
+ return (false);
+ }
+ return (true);
+
}
/*
* oidrand (oid o, int4 X)-
- * takes in an oid and a int4 X, and will return 'true'
- * about 1/X of the time.
- * Useful for doing random sampling or subsetting.
- * if X == 0, this will always return true;
+ * takes in an oid and a int4 X, and will return 'true'
+ * about 1/X of the time.
+ * Useful for doing random sampling or subsetting.
+ * if X == 0, this will always return true;
*
* Example use:
- * select * from TEMP where oidrand(TEMP.oid, 10)
+ * select * from TEMP where oidrand(TEMP.oid, 10)
* will return about 1/10 of the tuples in TEMP
*
*/
-bool
+bool
oidrand(Oid o, int32 X)
{
- bool result;
+ bool result;
- if (X == 0) return true;
+ if (X == 0)
+ return true;
- result = (random() % X == 0);
- return result;
+ result = (random() % X == 0);
+ return result;
}
/*
oidsrand(int32 X) -
- seeds the random number generator
- always return true
-*/
+ seeds the random number generator
+ always return true
+*/
bool
oidsrand(int32 X)
{
- srand(X);
- return true;
+ srand(X);
+ return true;
}
@@ -89,5 +92,5 @@ oidsrand(int32 X)
int32
userfntest(int i)
{
- return (i);
+ return (i);
}
diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c
index 0e56a2816ee..9eb5ed36281 100644
--- a/src/backend/utils/adt/nabstime.c
+++ b/src/backend/utils/adt/nabstime.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* nabstime.c--
- * parse almost any absolute date getdate(3) can (& some it can't)
+ * parse almost any absolute date getdate(3) can (& some it can't)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.31 1997/08/19 21:34:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.32 1997/09/07 04:50:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,10 +19,10 @@
#include "postgres.h"
#include <miscadmin.h>
#ifdef HAVE_FLOAT_H
-# include <float.h>
+#include <float.h>
#endif
#ifdef HAVE_LIMITS_H
-# include <limits.h>
+#include <limits.h>
#endif
#ifndef USE_POSIX_TIME
#include <sys/timeb.h>
@@ -30,10 +30,10 @@
#include "utils/builtins.h"
#include "access/xact.h"
-static AbsoluteTime tm2abstime(struct tm *tm, int tz);
+static AbsoluteTime tm2abstime(struct tm * tm, int tz);
-#define MIN_DAYNUM -24856 /* December 13, 1901 */
-#define MAX_DAYNUM 24854 /* January 18, 2038 */
+#define MIN_DAYNUM -24856 /* December 13, 1901 */
+#define MAX_DAYNUM 24854 /* January 18, 2038 */
/* GetCurrentAbsoluteTime()
@@ -45,300 +45,344 @@ static AbsoluteTime tm2abstime(struct tm *tm, int tz);
AbsoluteTime
GetCurrentAbsoluteTime(void)
{
- time_t now;
+ time_t now;
#ifdef USE_POSIX_TIME
- struct tm *tm;
+ struct tm *tm;
- now = time(NULL);
-#else /* ! USE_POSIX_TIME */
- struct timeb tb; /* the old V7-ism */
+ now = time(NULL);
+#else /* ! USE_POSIX_TIME */
+ struct timeb tb; /* the old V7-ism */
- ftime(&tb);
- now = tb.time;
+ ftime(&tb);
+ now = tb.time;
#endif
- if (! HasCTZSet) {
+ if (!HasCTZSet)
+ {
#ifdef USE_POSIX_TIME
#if defined(HAVE_TZSET) && defined(HAVE_INT_TIMEZONE)
- tm = localtime(&now);
-
- CDayLight = tm->tm_isdst;
- CTimeZone = (tm->tm_isdst? (timezone - 3600): timezone);
- strcpy( CTZName, tzname[tm->tm_isdst]);
-#else /* !HAVE_TZSET */
- tm = localtime(&now);
-
- CTimeZone = - tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
- CDayLight = (tm->tm_isdst > 0);
- /* XXX is there a better way to get local timezone string w/o tzname? - tgl 97/03/18 */
- strftime( CTZName, MAXTZLEN, "%Z", tm);
- /* XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 */
- strcpy(CTZName, tm->tm_zone);
+ tm = localtime(&now);
+
+ CDayLight = tm->tm_isdst;
+ CTimeZone = (tm->tm_isdst ? (timezone - 3600) : timezone);
+ strcpy(CTZName, tzname[tm->tm_isdst]);
+#else /* !HAVE_TZSET */
+ tm = localtime(&now);
+
+ CTimeZone = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
+ CDayLight = (tm->tm_isdst > 0);
+
+ /*
+ * XXX is there a better way to get local timezone string w/o
+ * tzname? - tgl 97/03/18
+ */
+ strftime(CTZName, MAXTZLEN, "%Z", tm);
+
+ /*
+ * XXX FreeBSD man pages indicate that this should work - tgl
+ * 97/04/23
+ */
+ strcpy(CTZName, tm->tm_zone);
+#endif
+#else /* ! USE_POSIX_TIME */
+ CTimeZone = tb.timezone * 60;
+ CDayLight = (tb.dstflag != 0);
+
+ /*
+ * XXX does this work to get the local timezone string in V7? -
+ * tgl 97/03/18
+ */
+ strftime(CTZName, MAXTZLEN, "%Z", localtime(&now));
#endif
-#else /* ! USE_POSIX_TIME */
- CTimeZone = tb.timezone * 60;
- CDayLight = (tb.dstflag != 0);
- /* XXX does this work to get the local timezone string in V7? - tgl 97/03/18 */
- strftime( CTZName, MAXTZLEN, "%Z", localtime(&now));
-#endif
- };
+ };
#ifdef DATEDEBUG
-printf( "GetCurrentAbsoluteTime- timezone is %s -> %d seconds from UTC\n",
- CTZName, CTimeZone);
+ printf("GetCurrentAbsoluteTime- timezone is %s -> %d seconds from UTC\n",
+ CTZName, CTimeZone);
#endif
- return((AbsoluteTime) now);
-} /* GetCurrentAbsoluteTime() */
+ return ((AbsoluteTime) now);
+} /* GetCurrentAbsoluteTime() */
void
-GetCurrentTime(struct tm *tm)
+GetCurrentTime(struct tm * tm)
{
- int tz;
+ int tz;
- abstime2tm( GetCurrentTransactionStartTime(), &tz, tm, NULL);
+ abstime2tm(GetCurrentTransactionStartTime(), &tz, tm, NULL);
- return;
-} /* GetCurrentTime() */
+ return;
+} /* GetCurrentTime() */
void
-abstime2tm(AbsoluteTime time, int *tzp, struct tm *tm, char *tzn)
+abstime2tm(AbsoluteTime time, int *tzp, struct tm * tm, char *tzn)
{
#ifdef USE_POSIX_TIME
- struct tm *tx;
-#else /* ! USE_POSIX_TIME */
- struct timeb tb; /* the old V7-ism */
+ struct tm *tx;
- ftime(&tb);
+#else /* ! USE_POSIX_TIME */
+ struct timeb tb; /* the old V7-ism */
+
+ ftime(&tb);
#endif
#ifdef USE_POSIX_TIME
- if (tzp != NULL) {
- tx = localtime((time_t *) &time);
- } else {
- tx = gmtime((time_t *) &time);
- };
+ if (tzp != NULL)
+ {
+ tx = localtime((time_t *) & time);
+ }
+ else
+ {
+ tx = gmtime((time_t *) & time);
+ };
#else
#endif
#ifdef DATEDEBUG
#ifdef HAVE_INT_TIMEZONE
-printf( "datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s %s dst=%d\n",
- tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
- tzname[0], tzname[1], tx->tm_isdst);
+ printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s %s dst=%d\n",
+ tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
+ tzname[0], tzname[1], tx->tm_isdst);
#else
-printf( "datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s dst=%d\n",
- tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
- tx->tm_zone, tx->tm_isdst);
+ printf("datetime2tm- (localtime) %d.%02d.%02d %02d:%02d:%02d %s dst=%d\n",
+ tx->tm_year, tx->tm_mon, tx->tm_mday, tx->tm_hour, tx->tm_min, tx->tm_sec,
+ tx->tm_zone, tx->tm_isdst);
#endif
#else
#endif
- tm->tm_year = tx->tm_year+1900;
- tm->tm_mon = tx->tm_mon+1;
- tm->tm_mday = tx->tm_mday;
- tm->tm_hour = tx->tm_hour;
- tm->tm_min = tx->tm_min;
- tm->tm_sec = tx->tm_sec;
- tm->tm_isdst = tx->tm_isdst;
+ tm->tm_year = tx->tm_year + 1900;
+ tm->tm_mon = tx->tm_mon + 1;
+ tm->tm_mday = tx->tm_mday;
+ tm->tm_hour = tx->tm_hour;
+ tm->tm_min = tx->tm_min;
+ tm->tm_sec = tx->tm_sec;
+ tm->tm_isdst = tx->tm_isdst;
#ifdef USE_POSIX_TIME
#ifdef HAVE_INT_TIMEZONE
- if (tzp != NULL) *tzp = (tm->tm_isdst? (timezone - 3600): timezone);
- if (tzn != NULL) strcpy( tzn, tzname[tm->tm_isdst]);
-#else /* !HAVE_INT_TIMEZONE */
- tm->tm_gmtoff = tx->tm_gmtoff;
- tm->tm_zone = tx->tm_zone;
-
- if (tzp != NULL) *tzp = - tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
- /* XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 */
- if (tzn != NULL) strcpy( tzn, tm->tm_zone);
+ if (tzp != NULL)
+ *tzp = (tm->tm_isdst ? (timezone - 3600) : timezone);
+ if (tzn != NULL)
+ strcpy(tzn, tzname[tm->tm_isdst]);
+#else /* !HAVE_INT_TIMEZONE */
+ tm->tm_gmtoff = tx->tm_gmtoff;
+ tm->tm_zone = tx->tm_zone;
+
+ if (tzp != NULL)
+ *tzp = -tm->tm_gmtoff; /* tm_gmtoff is Sun/DEC-ism */
+ /* XXX FreeBSD man pages indicate that this should work - tgl 97/04/23 */
+ if (tzn != NULL)
+ strcpy(tzn, tm->tm_zone);
+#endif
+#else /* ! USE_POSIX_TIME */
+ if (tzp != NULL)
+ *tzp = tb.timezone * 60;
+
+ /*
+ * XXX does this work to get the local timezone string in V7? - tgl
+ * 97/03/18
+ */
+ if (tzn != NULL)
+ strftime(tzn, MAXTZLEN, "%Z", localtime(&now));
#endif
-#else /* ! USE_POSIX_TIME */
- if (tzp != NULL) *tzp = tb.timezone * 60;
- /* XXX does this work to get the local timezone string in V7? - tgl 97/03/18 */
- if (tzn != NULL) strftime( tzn, MAXTZLEN, "%Z", localtime(&now));
-#endif
- return;
-} /* abstime2tm() */
+ return;
+} /* abstime2tm() */
/* tm2abstime()
* Convert a tm structure to abstime.
* Note that tm has full year (not 1900-based) and 1-based month.
*/
-static AbsoluteTime
-tm2abstime( struct tm *tm, int tz)
+static AbsoluteTime
+tm2abstime(struct tm * tm, int tz)
{
- int day, sec;
+ int day,
+ sec;
- /* validate, before going out of range on some members */
- if (tm->tm_year < 1901 || tm->tm_year > 2038
- || tm->tm_mon < 1 || tm->tm_mon > 12
- || tm->tm_mday < 1 || tm->tm_mday > 31
- || tm->tm_hour < 0 || tm->tm_hour >= 24
- || tm->tm_min < 0 || tm->tm_min > 59
- || tm->tm_sec < 0 || tm->tm_sec > 59)
- return(INVALID_ABSTIME);
+ /* validate, before going out of range on some members */
+ if (tm->tm_year < 1901 || tm->tm_year > 2038
+ || tm->tm_mon < 1 || tm->tm_mon > 12
+ || tm->tm_mday < 1 || tm->tm_mday > 31
+ || tm->tm_hour < 0 || tm->tm_hour >= 24
+ || tm->tm_min < 0 || tm->tm_min > 59
+ || tm->tm_sec < 0 || tm->tm_sec > 59)
+ return (INVALID_ABSTIME);
- day = (date2j( tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j( 1970, 1, 1));
+ day = (date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - date2j(1970, 1, 1));
- /* check for time out of range */
- if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
- return(INVALID_ABSTIME);
+ /* check for time out of range */
+ if ((day < MIN_DAYNUM) || (day > MAX_DAYNUM))
+ return (INVALID_ABSTIME);
- /* convert to seconds */
- sec = tm->tm_sec + tz + (tm->tm_min +(day*24 + tm->tm_hour)*60)*60;
+ /* convert to seconds */
+ sec = tm->tm_sec + tz + (tm->tm_min + (day * 24 + tm->tm_hour) * 60) * 60;
- /* check for overflow */
- if ((day == MAX_DAYNUM && sec < 0) ||
- (day == MIN_DAYNUM && sec > 0))
- return(INVALID_ABSTIME);
+ /* check for overflow */
+ if ((day == MAX_DAYNUM && sec < 0) ||
+ (day == MIN_DAYNUM && sec > 0))
+ return (INVALID_ABSTIME);
- /* check for reserved values (e.g. "current" on edge of usual range */
- if (!AbsoluteTimeIsReal(sec))
- return(INVALID_ABSTIME);
+ /* check for reserved values (e.g. "current" on edge of usual range */
+ if (!AbsoluteTimeIsReal(sec))
+ return (INVALID_ABSTIME);
- return(sec);
-} /* tm2abstime() */
+ return (sec);
+} /* tm2abstime() */
/* nabstimein()
* Decode date/time string and return abstime.
*/
AbsoluteTime
-nabstimein(char* str)
+nabstimein(char *str)
{
- AbsoluteTime result;
+ AbsoluteTime result;
- double fsec;
- int tz = 0;
- struct tm date, *tm = &date;
+ double fsec;
+ int tz = 0;
+ struct tm date,
+ *tm = &date;
- char *field[MAXDATEFIELDS];
- char lowstr[MAXDATELEN+1];
- int dtype;
- int nf, ftype[MAXDATEFIELDS];
+ char *field[MAXDATEFIELDS];
+ char lowstr[MAXDATELEN + 1];
+ int dtype;
+ int nf,
+ ftype[MAXDATEFIELDS];
- if (!PointerIsValid(str))
- elog(WARN,"Bad (null) abstime external representation",NULL);
+ if (!PointerIsValid(str))
+ elog(WARN, "Bad (null) abstime external representation", NULL);
- if (strlen(str) > MAXDATELEN)
- elog( WARN, "Bad (length) abstime external representation '%s'",str);
+ if (strlen(str) > MAXDATELEN)
+ elog(WARN, "Bad (length) abstime external representation '%s'", str);
- if ((ParseDateTime( str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
- || (DecodeDateTime( field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
- elog( WARN, "Bad abstime external representation '%s'",str);
+ if ((ParseDateTime(str, lowstr, field, ftype, MAXDATEFIELDS, &nf) != 0)
+ || (DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz) != 0))
+ elog(WARN, "Bad abstime external representation '%s'", str);
#ifdef DATEDEBUG
-printf( "nabstimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE);
+ printf("nabstimein- %d fields are type %d (DTK_DATE=%d)\n", nf, dtype, DTK_DATE);
#endif
- switch (dtype) {
- case DTK_DATE:
- result = tm2abstime(tm, tz);
- break;
+ switch (dtype)
+ {
+ case DTK_DATE:
+ result = tm2abstime(tm, tz);
+ break;
- case DTK_EPOCH:
- result = EPOCH_ABSTIME;
- break;
+ case DTK_EPOCH:
+ result = EPOCH_ABSTIME;
+ break;
- case DTK_CURRENT:
- result = CURRENT_ABSTIME;
- break;
+ case DTK_CURRENT:
+ result = CURRENT_ABSTIME;
+ break;
- case DTK_LATE:
- result = NOEND_ABSTIME;
- break;
+ case DTK_LATE:
+ result = NOEND_ABSTIME;
+ break;
- case DTK_EARLY:
- result = NOSTART_ABSTIME;
- break;
+ case DTK_EARLY:
+ result = NOSTART_ABSTIME;
+ break;
- case DTK_INVALID:
- result = INVALID_ABSTIME;
- break;
+ case DTK_INVALID:
+ result = INVALID_ABSTIME;
+ break;
- default:
- elog(WARN,"Bad abstime (internal coding error) '%s'",str);
- result = INVALID_ABSTIME;
- break;
- };
+ default:
+ elog(WARN, "Bad abstime (internal coding error) '%s'", str);
+ result = INVALID_ABSTIME;
+ break;
+ };
- return result;
-} /* nabstimein() */
+ return result;
+} /* nabstimein() */
/* nabstimeout()
* Given an AbsoluteTime return the English text version of the date
*/
-char *
+char *
nabstimeout(AbsoluteTime time)
{
- char* result;
- int tz;
- double fsec = 0;
- struct tm tt, *tm = &tt;
- char buf[MAXDATELEN+1];
- char zone[MAXDATELEN+1], *tzn = zone;
-
- switch (time) {
- case EPOCH_ABSTIME: strcpy(buf, EPOCH); break;
- case INVALID_ABSTIME: strcpy(buf, INVALID); break;
- case CURRENT_ABSTIME: strcpy(buf, DCURRENT); break;
- case NOEND_ABSTIME: strcpy(buf, LATE); break;
- case NOSTART_ABSTIME: strcpy(buf, EARLY); break;
- default:
- abstime2tm( time, &tz, tm, tzn);
+ char *result;
+ int tz;
+ double fsec = 0;
+ struct tm tt,
+ *tm = &tt;
+ char buf[MAXDATELEN + 1];
+ char zone[MAXDATELEN + 1],
+ *tzn = zone;
+
+ switch (time)
+ {
+ case EPOCH_ABSTIME:
+ strcpy(buf, EPOCH);
+ break;
+ case INVALID_ABSTIME:
+ strcpy(buf, INVALID);
+ break;
+ case CURRENT_ABSTIME:
+ strcpy(buf, DCURRENT);
+ break;
+ case NOEND_ABSTIME:
+ strcpy(buf, LATE);
+ break;
+ case NOSTART_ABSTIME:
+ strcpy(buf, EARLY);
+ break;
+ default:
+ abstime2tm(time, &tz, tm, tzn);
#if DATEDEBUG
#endif
- EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
- break;
- }
+ EncodeDateTime(tm, fsec, &tz, &tzn, DateStyle, buf);
+ break;
+ }
- result = PALLOC(strlen(buf) + 1);
- strcpy(result, buf);
+ result = PALLOC(strlen(buf) + 1);
+ strcpy(result, buf);
- return(result);
-} /* nabstimeout() */
+ return (result);
+} /* nabstimeout() */
/*
- * AbsoluteTimeIsBefore -- true iff time1 is before time2.
- * AbsoluteTimeIsBefore -- true iff time1 is after time2.
+ * AbsoluteTimeIsBefore -- true iff time1 is before time2.
+ * AbsoluteTimeIsBefore -- true iff time1 is after time2.
*/
bool
AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2)
{
- Assert(AbsoluteTimeIsValid(time1));
- Assert(AbsoluteTimeIsValid(time2));
+ Assert(AbsoluteTimeIsValid(time1));
+ Assert(AbsoluteTimeIsValid(time2));
- if (time1 == CURRENT_ABSTIME)
- time1 = GetCurrentTransactionStartTime();
+ if (time1 == CURRENT_ABSTIME)
+ time1 = GetCurrentTransactionStartTime();
- if (time2 == CURRENT_ABSTIME)
- time2 = GetCurrentTransactionStartTime();
+ if (time2 == CURRENT_ABSTIME)
+ time2 = GetCurrentTransactionStartTime();
- return (time1 < time2);
+ return (time1 < time2);
}
bool
AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
{
- Assert(AbsoluteTimeIsValid(time1));
- Assert(AbsoluteTimeIsValid(time2));
+ Assert(AbsoluteTimeIsValid(time1));
+ Assert(AbsoluteTimeIsValid(time2));
- if (time1 == CURRENT_ABSTIME)
- time1 = GetCurrentTransactionStartTime();
+ if (time1 == CURRENT_ABSTIME)
+ time1 = GetCurrentTransactionStartTime();
- if (time2 == CURRENT_ABSTIME)
- time2 = GetCurrentTransactionStartTime();
+ if (time2 == CURRENT_ABSTIME)
+ time2 = GetCurrentTransactionStartTime();
- return (time1 > time2);
+ return (time1 > time2);
}
@@ -347,95 +391,95 @@ AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
bool
abstime_finite(AbsoluteTime abstime)
{
- return((abstime != INVALID_ABSTIME)
- && (abstime != NOSTART_ABSTIME) && (abstime != NOEND_ABSTIME));
-} /* abstime_datetime() */
+ return ((abstime != INVALID_ABSTIME)
+ && (abstime != NOSTART_ABSTIME) && (abstime != NOEND_ABSTIME));
+} /* abstime_datetime() */
/*
- * abstimeeq - returns 1, iff arguments are equal
- * abstimene - returns 1, iff arguments are not equal
- * abstimelt - returns 1, iff t1 less than t2
- * abstimegt - returns 1, iff t1 greater than t2
- * abstimele - returns 1, iff t1 less than or equal to t2
- * abstimege - returns 1, iff t1 greater than or equal to t2
+ * abstimeeq - returns 1, iff arguments are equal
+ * abstimene - returns 1, iff arguments are not equal
+ * abstimelt - returns 1, iff t1 less than t2
+ * abstimegt - returns 1, iff t1 greater than t2
+ * abstimele - returns 1, iff t1 less than or equal to t2
+ * abstimege - returns 1, iff t1 greater than or equal to t2
*/
bool
abstimeeq(AbsoluteTime t1, AbsoluteTime t2)
{
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- return(FALSE);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- return(t1 == t2);
+ if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
+ return (FALSE);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+ if (t2 == CURRENT_ABSTIME)
+ t2 = GetCurrentTransactionStartTime();
+
+ return (t1 == t2);
}
bool
abstimene(AbsoluteTime t1, AbsoluteTime t2)
-{
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- return(FALSE);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- return(t1 != t2);
+{
+ if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
+ return (FALSE);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+ if (t2 == CURRENT_ABSTIME)
+ t2 = GetCurrentTransactionStartTime();
+
+ return (t1 != t2);
}
bool
abstimelt(AbsoluteTime t1, AbsoluteTime t2)
-{
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- return(FALSE);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- return(t1 < t2);
+{
+ if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
+ return (FALSE);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+ if (t2 == CURRENT_ABSTIME)
+ t2 = GetCurrentTransactionStartTime();
+
+ return (t1 < t2);
}
bool
abstimegt(AbsoluteTime t1, AbsoluteTime t2)
-{
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- return(FALSE);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- return(t1 > t2);
+{
+ if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
+ return (FALSE);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+ if (t2 == CURRENT_ABSTIME)
+ t2 = GetCurrentTransactionStartTime();
+
+ return (t1 > t2);
}
bool
abstimele(AbsoluteTime t1, AbsoluteTime t2)
-{
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- return(FALSE);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- return(t1 <= t2);
+{
+ if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
+ return (FALSE);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+ if (t2 == CURRENT_ABSTIME)
+ t2 = GetCurrentTransactionStartTime();
+
+ return (t1 <= t2);
}
bool
abstimege(AbsoluteTime t1, AbsoluteTime t2)
-{
- if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
- return(FALSE);
- if (t1 == CURRENT_ABSTIME)
- t1 = GetCurrentTransactionStartTime();
- if (t2 == CURRENT_ABSTIME)
- t2 = GetCurrentTransactionStartTime();
-
- return(t1 >= t2);
+{
+ if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
+ return (FALSE);
+ if (t1 == CURRENT_ABSTIME)
+ t1 = GetCurrentTransactionStartTime();
+ if (t2 == CURRENT_ABSTIME)
+ t2 = GetCurrentTransactionStartTime();
+
+ return (t1 >= t2);
}
@@ -443,77 +487,93 @@ abstimege(AbsoluteTime t1, AbsoluteTime t2)
* Convert datetime to abstime.
*/
AbsoluteTime
-datetime_abstime(DateTime *datetime)
+datetime_abstime(DateTime * datetime)
{
- AbsoluteTime result;
-
- double fsec;
- struct tm tt, *tm = &tt;
-
- if (!PointerIsValid(datetime)) {
- result = INVALID_ABSTIME;
-
- } else if (DATETIME_IS_INVALID(*datetime)) {
- result = INVALID_ABSTIME;
-
- } else if (DATETIME_IS_NOBEGIN(*datetime)) {
- result = NOSTART_ABSTIME;
-
- } else if (DATETIME_IS_NOEND(*datetime)) {
- result = NOEND_ABSTIME;
-
- } else {
- if (DATETIME_IS_RELATIVE(*datetime)) {
- datetime2tm( SetDateTime(*datetime), NULL, tm, &fsec, NULL);
- result = tm2abstime( tm, 0);
-
- } else if (datetime2tm( *datetime, NULL, tm, &fsec, NULL) == 0) {
- result = tm2abstime( tm, 0);
-
- } else {
- result = INVALID_ABSTIME;
+ AbsoluteTime result;
+
+ double fsec;
+ struct tm tt,
+ *tm = &tt;
+
+ if (!PointerIsValid(datetime))
+ {
+ result = INVALID_ABSTIME;
+
+ }
+ else if (DATETIME_IS_INVALID(*datetime))
+ {
+ result = INVALID_ABSTIME;
+
+ }
+ else if (DATETIME_IS_NOBEGIN(*datetime))
+ {
+ result = NOSTART_ABSTIME;
+
+ }
+ else if (DATETIME_IS_NOEND(*datetime))
+ {
+ result = NOEND_ABSTIME;
+
+ }
+ else
+ {
+ if (DATETIME_IS_RELATIVE(*datetime))
+ {
+ datetime2tm(SetDateTime(*datetime), NULL, tm, &fsec, NULL);
+ result = tm2abstime(tm, 0);
+
+ }
+ else if (datetime2tm(*datetime, NULL, tm, &fsec, NULL) == 0)
+ {
+ result = tm2abstime(tm, 0);
+
+ }
+ else
+ {
+ result = INVALID_ABSTIME;
+ };
};
- };
- return(result);
-} /* datetime_abstime() */
+ return (result);
+} /* datetime_abstime() */
/* abstime_datetime()
* Convert datetime to abstime.
*/
-DateTime *
+DateTime *
abstime_datetime(AbsoluteTime abstime)
{
- DateTime *result;
+ DateTime *result;
- if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
- elog(WARN,"Unable to allocate space to convert abstime to datetime",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
+ elog(WARN, "Unable to allocate space to convert abstime to datetime", NULL);
- switch (abstime) {
- case INVALID_ABSTIME:
- DATETIME_INVALID(*result);
- break;
+ switch (abstime)
+ {
+ case INVALID_ABSTIME:
+ DATETIME_INVALID(*result);
+ break;
- case NOSTART_ABSTIME:
- DATETIME_NOBEGIN(*result);
- break;
+ case NOSTART_ABSTIME:
+ DATETIME_NOBEGIN(*result);
+ break;
- case NOEND_ABSTIME:
- DATETIME_NOEND(*result);
- break;
+ case NOEND_ABSTIME:
+ DATETIME_NOEND(*result);
+ break;
- case EPOCH_ABSTIME:
- DATETIME_EPOCH(*result);
- break;
+ case EPOCH_ABSTIME:
+ DATETIME_EPOCH(*result);
+ break;
- case CURRENT_ABSTIME:
- DATETIME_CURRENT(*result);
- break;
+ case CURRENT_ABSTIME:
+ DATETIME_CURRENT(*result);
+ break;
- default:
- *result = abstime + ((date2j( 1970, 1, 1) - date2j( 2000, 1, 1))*86400);
- break;
- };
+ default:
+ *result = abstime + ((date2j(1970, 1, 1) - date2j(2000, 1, 1)) * 86400);
+ break;
+ };
- return(result);
-} /* abstime_datetime() */
+ return (result);
+} /* abstime_datetime() */
diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c
index 7ef599b3dee..b0de03ff602 100644
--- a/src/backend/utils/adt/name.c
+++ b/src/backend/utils/adt/name.c
@@ -1,203 +1,221 @@
/*-------------------------------------------------------------------------
*
* name.c--
- * Functions for the built-in type "name".
+ * Functions for the built-in type "name".
* name replaces char16 and is carefully implemented so that it
* is a string of length NAMEDATALEN. DO NOT use hard-coded constants anywhere
* always use NAMEDATALEN as the symbolic constant! - jolly 8/21/95
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/name.c,v 1.6 1997/08/19 21:34:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/name.c,v 1.7 1997/09/07 04:50:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
-#include "utils/builtins.h" /* where the declarations go */
-#include "utils/palloc.h" /* where the declarations go */
+#include "utils/builtins.h" /* where the declarations go */
+#include "utils/palloc.h" /* where the declarations go */
-/*****************************************************************************
- * USER I/O ROUTINES (none) *
+/*****************************************************************************
+ * USER I/O ROUTINES (none) *
*****************************************************************************/
/*
- * namein - converts "..." to internal representation
+ * namein - converts "..." to internal representation
*
- * Note:
- * [Old] Currently if strlen(s) < NAMEDATALEN, the extra chars are nulls
- * Now, always NULL terminated
+ * Note:
+ * [Old] Currently if strlen(s) < NAMEDATALEN, the extra chars are nulls
+ * Now, always NULL terminated
*/
-NameData *namein(char *s)
+NameData *
+namein(char *s)
{
- NameData *result;
-
- if (s == NULL)
- return(NULL);
- result = (NameData*) palloc(NAMEDATALEN);
- /* always keep it null-padded */
- strNcpy(result->data, s, NAMEDATALEN-1);
- return(result);
+ NameData *result;
+
+ if (s == NULL)
+ return (NULL);
+ result = (NameData *) palloc(NAMEDATALEN);
+ /* always keep it null-padded */
+ strNcpy(result->data, s, NAMEDATALEN - 1);
+ return (result);
}
/*
- * nameout - converts internal reprsentation to "..."
+ * nameout - converts internal reprsentation to "..."
*/
-char *nameout(NameData *s)
+char *
+nameout(NameData * s)
{
- if (s == NULL)
- return "-";
- else
- return pstrdup(s->data);
+ if (s == NULL)
+ return "-";
+ else
+ return pstrdup(s->data);
}
-/*****************************************************************************
- * PUBLIC ROUTINES *
+/*****************************************************************************
+ * PUBLIC ROUTINES *
*****************************************************************************/
/*
- * nameeq - returns 1 iff arguments are equal
- * namene - returns 1 iff arguments are not equal
+ * nameeq - returns 1 iff arguments are equal
+ * namene - returns 1 iff arguments are not equal
*
- * BUGS:
- * Assumes that "xy\0\0a" should be equal to "xy\0b".
- * If not, can do the comparison backwards for efficiency.
+ * BUGS:
+ * Assumes that "xy\0\0a" should be equal to "xy\0b".
+ * If not, can do the comparison backwards for efficiency.
*
- * namelt - returns 1 iff a < b
- * namele - returns 1 iff a <= b
- * namegt - returns 1 iff a < b
- * namege - returns 1 iff a <= b
+ * namelt - returns 1 iff a < b
+ * namele - returns 1 iff a <= b
+ * namegt - returns 1 iff a < b
+ * namege - returns 1 iff a <= b
*
*/
-bool nameeq(NameData *arg1, NameData *arg2)
+bool
+nameeq(NameData * arg1, NameData * arg2)
{
- if (!arg1 || !arg2)
- return 0;
- else
- return ((bool) strncmp(arg1->data, arg2->data, NAMEDATALEN) == 0);
+ if (!arg1 || !arg2)
+ return 0;
+ else
+ return ((bool) strncmp(arg1->data, arg2->data, NAMEDATALEN) == 0);
}
-bool namene(NameData *arg1, NameData *arg2)
+bool
+namene(NameData * arg1, NameData * arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) != 0));
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return ((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) != 0));
}
-bool namelt(NameData *arg1, NameData *arg2)
+bool
+namelt(NameData * arg1, NameData * arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) < 0));
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return ((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) < 0));
}
-bool namele(NameData *arg1, NameData *arg2)
+bool
+namele(NameData * arg1, NameData * arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- return((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) <= 0));
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ return ((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) <= 0));
}
-bool namegt(NameData *arg1, NameData *arg2)
+bool
+namegt(NameData * arg1, NameData * arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
-
- return((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) > 0));
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+
+ return ((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) > 0));
}
-bool namege(NameData *arg1, NameData *arg2)
+bool
+namege(NameData * arg1, NameData * arg2)
{
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
-
- return((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) >= 0));
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+
+ return ((bool) (strncmp(arg1->data, arg2->data, NAMEDATALEN) >= 0));
}
/* (see char.c for comparison/operation routines) */
-int namecpy(Name n1, Name n2)
+int
+namecpy(Name n1, Name n2)
{
- if (!n1 || !n2)
- return(-1);
- strncpy(n1->data, n2->data, NAMEDATALEN);
- return(0);
+ if (!n1 || !n2)
+ return (-1);
+ strncpy(n1->data, n2->data, NAMEDATALEN);
+ return (0);
}
#ifdef NOT_USED
-int namecat(Name n1, Name n2)
+int
+namecat(Name n1, Name n2)
{
- return(namestrcat(n1, n2->data)); /* n2 can't be any longer than n1 */
+ return (namestrcat(n1, n2->data)); /* n2 can't be any longer than n1 */
}
+
#endif
-int namecmp(Name n1, Name n2)
+int
+namecmp(Name n1, Name n2)
{
- return(strncmp(n1->data, n2->data, NAMEDATALEN));
+ return (strncmp(n1->data, n2->data, NAMEDATALEN));
}
-int
+int
namestrcpy(Name name, char *str)
{
- if (!name || !str)
- return(-1);
- strNcpy(name->data, str, NAMEDATALEN-1);
- return(0);
+ if (!name || !str)
+ return (-1);
+ strNcpy(name->data, str, NAMEDATALEN - 1);
+ return (0);
}
#ifdef NOT_USED
-int namestrcat(Name name, char *str)
+int
+namestrcat(Name name, char *str)
{
- int i;
- char *p, *q;
-
- if (!name || !str)
- return(-1);
- for (i = 0, p = name->data; i < NAMEDATALEN && *p; ++i, ++p)
- ;
- for (q = str; i < NAMEDATALEN; ++i, ++p, ++q) {
- *p = *q;
- if (!*q)
- break;
- }
- return(0);
+ int i;
+ char *p,
+ *q;
+
+ if (!name || !str)
+ return (-1);
+ for (i = 0, p = name->data; i < NAMEDATALEN && *p; ++i, ++p)
+ ;
+ for (q = str; i < NAMEDATALEN; ++i, ++p, ++q)
+ {
+ *p = *q;
+ if (!*q)
+ break;
+ }
+ return (0);
}
+
#endif
-int
+int
namestrcmp(Name name, char *str)
{
- if (!name && !str)
- return(0);
- if (!name)
- return(-1); /* NULL < anything */
- if (!str)
- return(1); /* NULL < anything */
- return(strncmp(name->data, str, NAMEDATALEN));
+ if (!name && !str)
+ return (0);
+ if (!name)
+ return (-1); /* NULL < anything */
+ if (!str)
+ return (1); /* NULL < anything */
+ return (strncmp(name->data, str, NAMEDATALEN));
}
-/*****************************************************************************
- * PRIVATE ROUTINES *
+/*****************************************************************************
+ * PRIVATE ROUTINES *
*****************************************************************************/
#ifdef NOT_USED
-uint32
+uint32
NameComputeLength(Name name)
{
- char *charP;
- int length;
-
- for (length = 0, charP = name->data;
- length < NAMEDATALEN && *charP != '\0';
- length++, charP++) {
- ;
- }
- return (uint32)length;
+ char *charP;
+ int length;
+
+ for (length = 0, charP = name->data;
+ length < NAMEDATALEN && *charP != '\0';
+ length++, charP++)
+ {
+ ;
+ }
+ return (uint32) length;
}
+
#endif
diff --git a/src/backend/utils/adt/not_in.c b/src/backend/utils/adt/not_in.c
index a78e7dc31ce..0bc51eb6f19 100644
--- a/src/backend/utils/adt/not_in.c
+++ b/src/backend/utils/adt/not_in.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* not_in.c--
- * Executes the "not_in" operator for any data type
+ * Executes the "not_in" operator for any data type
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.3 1997/08/19 21:34:48 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.4 1997/09/07 04:50:29 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,81 +27,85 @@
#include "postgres.h"
#include "access/heapam.h"
#include "access/relscan.h"
-#include "utils/builtins.h" /* where function decls go */
+#include "utils/builtins.h" /* where function decls go */
-static int my_varattno(Relation rd, char *a);
+static int my_varattno(Relation rd, char *a);
/* ----------------------------------------------------------------
- *
+ *
* ----------------------------------------------------------------
*/
bool
int4notin(int16 not_in_arg, char *relation_and_attr)
{
- Relation relation_to_scan;
- int left_side_argument, integer_value;
- HeapTuple current_tuple;
- HeapScanDesc scan_descriptor;
- bool dummy, retval;
- int attrid;
- char *relation, *attribute;
- char my_copy[32];
- Datum value;
- NameData relNameData;
- ScanKeyData skeyData;
-
- strcpy(my_copy, relation_and_attr);
-
- relation = (char *) strtok(my_copy, ".");
- attribute = (char *) strtok(NULL, ".");
-
-
- /* fetch tuple OID */
-
- left_side_argument = not_in_arg;
-
- /* Open the relation and get a relation descriptor */
-
- namestrcpy(&relNameData,relation);
- relation_to_scan = heap_openr(relNameData.data);
- attrid = my_varattno(relation_to_scan, attribute);
-
- /* the last argument should be a ScanKey, not an integer! - jolly*/
- /* it looks like the arguments are out of order, too */
- /* but skeyData is never initialized! does this work?? - ay 2/95 */
- scan_descriptor = heap_beginscan(relation_to_scan, false, NULL, 0,
- &skeyData);
-
- retval = true;
-
- /* do a scan of the relation, and do the check */
- for (current_tuple = heap_getnext(scan_descriptor, 0, NULL);
- current_tuple != NULL && retval;
- current_tuple = heap_getnext(scan_descriptor, 0, NULL))
+ Relation relation_to_scan;
+ int left_side_argument,
+ integer_value;
+ HeapTuple current_tuple;
+ HeapScanDesc scan_descriptor;
+ bool dummy,
+ retval;
+ int attrid;
+ char *relation,
+ *attribute;
+ char my_copy[32];
+ Datum value;
+ NameData relNameData;
+ ScanKeyData skeyData;
+
+ strcpy(my_copy, relation_and_attr);
+
+ relation = (char *) strtok(my_copy, ".");
+ attribute = (char *) strtok(NULL, ".");
+
+
+ /* fetch tuple OID */
+
+ left_side_argument = not_in_arg;
+
+ /* Open the relation and get a relation descriptor */
+
+ namestrcpy(&relNameData, relation);
+ relation_to_scan = heap_openr(relNameData.data);
+ attrid = my_varattno(relation_to_scan, attribute);
+
+ /* the last argument should be a ScanKey, not an integer! - jolly */
+ /* it looks like the arguments are out of order, too */
+ /* but skeyData is never initialized! does this work?? - ay 2/95 */
+ scan_descriptor = heap_beginscan(relation_to_scan, false, NULL, 0,
+ &skeyData);
+
+ retval = true;
+
+ /* do a scan of the relation, and do the check */
+ for (current_tuple = heap_getnext(scan_descriptor, 0, NULL);
+ current_tuple != NULL && retval;
+ current_tuple = heap_getnext(scan_descriptor, 0, NULL))
{
- value = PointerGetDatum(heap_getattr(current_tuple,
- InvalidBuffer,
- (AttrNumber) attrid,
- RelationGetTupleDescriptor(relation_to_scan),
- &dummy));
-
- integer_value = DatumGetInt16(value);
- if (left_side_argument == integer_value)
+ value = PointerGetDatum(heap_getattr(current_tuple,
+ InvalidBuffer,
+ (AttrNumber) attrid,
+ RelationGetTupleDescriptor(relation_to_scan),
+ &dummy));
+
+ integer_value = DatumGetInt16(value);
+ if (left_side_argument == integer_value)
{
- retval = false;
+ retval = false;
}
}
-
- /* close the relation */
- heap_close(relation_to_scan);
- return(retval);
+
+ /* close the relation */
+ heap_close(relation_to_scan);
+ return (retval);
}
-bool oidnotin(Oid the_oid, char *compare)
+bool
+oidnotin(Oid the_oid, char *compare)
{
- if (the_oid == InvalidOid)
- return false;
- return(int4notin(the_oid, compare));
+ if (the_oid == InvalidOid)
+ return false;
+ return (int4notin(the_oid, compare));
}
/*
@@ -109,15 +113,17 @@ bool oidnotin(Oid the_oid, char *compare)
* If varattno (in parser/catalog_utils.h) ever is added to
* cinterface.a, this routine should go away
*/
-static int my_varattno(Relation rd, char *a)
+static int
+my_varattno(Relation rd, char *a)
{
- int i;
-
- for (i = 0; i < rd->rd_rel->relnatts; i++) {
- if (!namestrcmp(&rd->rd_att->attrs[i]->attname, a)) {
- return(i+1);
+ int i;
+
+ for (i = 0; i < rd->rd_rel->relnatts; i++)
+ {
+ if (!namestrcmp(&rd->rd_att->attrs[i]->attname, a))
+ {
+ return (i + 1);
+ }
}
- }
- return(-1);
+ return (-1);
}
-
diff --git a/src/backend/utils/adt/numutils.c b/src/backend/utils/adt/numutils.c
index 7f14317a700..3fd4ae382be 100644
--- a/src/backend/utils/adt/numutils.c
+++ b/src/backend/utils/adt/numutils.c
@@ -1,410 +1,449 @@
/*-------------------------------------------------------------------------
*
* numutils.c--
- * utility functions for I/O of built-in numeric types.
+ * utility functions for I/O of built-in numeric types.
*
- * integer: itoa, ltoa
- * floating point: ftoa, atof1
+ * integer: itoa, ltoa
+ * floating point: ftoa, atof1
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/numutils.c,v 1.13 1997/08/19 21:34:51 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/numutils.c,v 1.14 1997/09/07 04:50:33 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <errno.h>
#include <math.h>
#include "postgres.h"
#include "utils/builtins.h" /* where the declarations go */
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-#include <port-protos.h> /* ecvt(), fcvt() */
+#include <port-protos.h> /* ecvt(), fcvt() */
int32
pg_atoi(char *s, int size, int c)
{
- long l;
- char *badp = (char *) NULL;
-
- Assert(s);
-
- errno = 0;
- l = strtol(s, &badp, 10);
- if (errno) /* strtol must set ERANGE */
- elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
- if (badp && *badp && (*badp != c))
- elog(WARN, "pg_atoi: error in \"%s\": can\'t parse \"%s\"", s, badp);
-
- switch (size) {
- case sizeof(int32):
+ long l;
+ char *badp = (char *) NULL;
+
+ Assert(s);
+
+ errno = 0;
+ l = strtol(s, &badp, 10);
+ if (errno) /* strtol must set ERANGE */
+ elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
+ if (badp && *badp && (*badp != c))
+ elog(WARN, "pg_atoi: error in \"%s\": can\'t parse \"%s\"", s, badp);
+
+ switch (size)
+ {
+ case sizeof(int32):
#ifdef HAS_LONG_LONG
- /* won't get ERANGE on these with 64-bit longs... */
- if (l < -0x80000000L) {
- errno = ERANGE;
- elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
- }
- if (l > 0x7fffffffL) {
- errno = ERANGE;
- elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
- }
-#endif /* HAS_LONG_LONG */
- break;
- case sizeof(int16):
- if (l < -0x8000) {
- errno = ERANGE;
- elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
- }
- if (l > 0x7fff) {
- errno = ERANGE;
- elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
- }
- break;
- case sizeof(int8):
- if (l < -0x80) {
- errno = ERANGE;
- elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
- }
- if (l > 0x7f) {
- errno = ERANGE;
- elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
+ /* won't get ERANGE on these with 64-bit longs... */
+ if (l < -0x80000000L)
+ {
+ errno = ERANGE;
+ elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
+ }
+ if (l > 0x7fffffffL)
+ {
+ errno = ERANGE;
+ elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
+ }
+#endif /* HAS_LONG_LONG */
+ break;
+ case sizeof(int16):
+ if (l < -0x8000)
+ {
+ errno = ERANGE;
+ elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
+ }
+ if (l > 0x7fff)
+ {
+ errno = ERANGE;
+ elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
+ }
+ break;
+ case sizeof(int8):
+ if (l < -0x80)
+ {
+ errno = ERANGE;
+ elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
+ }
+ if (l > 0x7f)
+ {
+ errno = ERANGE;
+ elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
+ }
+ break;
+ default:
+ elog(WARN, "pg_atoi: invalid result size: %d", size);
}
- break;
- default:
- elog(WARN, "pg_atoi: invalid result size: %d", size);
- }
- return((int32) l);
+ return ((int32) l);
}
/*
- * itoa - converts a short int to its string represention
+ * itoa - converts a short int to its string represention
*
- * Note:
- * previously based on ~ingres/source/gutil/atoi.c
- * now uses vendor's sprintf conversion
+ * Note:
+ * previously based on ~ingres/source/gutil/atoi.c
+ * now uses vendor's sprintf conversion
*/
void
itoa(int i, char *a)
{
- sprintf(a, "%hd", (short)i);
+ sprintf(a, "%hd", (short) i);
}
/*
- * ltoa - converts a long int to its string represention
+ * ltoa - converts a long int to its string represention
*
- * Note:
- * previously based on ~ingres/source/gutil/atoi.c
- * now uses vendor's sprintf conversion
+ * Note:
+ * previously based on ~ingres/source/gutil/atoi.c
+ * now uses vendor's sprintf conversion
*/
void
ltoa(int32 l, char *a)
{
- sprintf(a, "%d", l);
+ sprintf(a, "%d", l);
}
/*
- ** ftoa - FLOATING POINT TO ASCII CONVERSION
+ ** ftoa - FLOATING POINT TO ASCII CONVERSION
**
- ** CODE derived from ingres, ~ingres/source/gutil/ftoa.c
+ ** CODE derived from ingres, ~ingres/source/gutil/ftoa.c
**
- ** 'Value' is converted to an ascii character string and stored
- ** into 'ascii'. Ascii should have room for at least 'width' + 1
- ** characters. 'Width' is the width of the output field (max).
- ** 'Prec' is the number of characters to put after the decimal
- ** point. The format of the output string is controlled by
- ** 'format'.
+ ** 'Value' is converted to an ascii character string and stored
+ ** into 'ascii'. Ascii should have room for at least 'width' + 1
+ ** characters. 'Width' is the width of the output field (max).
+ ** 'Prec' is the number of characters to put after the decimal
+ ** point. The format of the output string is controlled by
+ ** 'format'.
**
- ** 'Format' can be:
- ** e or E: "E" format output
- ** f or F: "F" format output
- ** g or G: "F" format output if it will fit, otherwise
- ** use "E" format.
- ** n or N: same as G, but decimal points will not always
- ** be aligned.
+ ** 'Format' can be:
+ ** e or E: "E" format output
+ ** f or F: "F" format output
+ ** g or G: "F" format output if it will fit, otherwise
+ ** use "E" format.
+ ** n or N: same as G, but decimal points will not always
+ ** be aligned.
**
- ** If 'format' is upper case, the "E" comes out in upper case;
- ** otherwise it comes out in lower case.
+ ** If 'format' is upper case, the "E" comes out in upper case;
+ ** otherwise it comes out in lower case.
**
- ** When the field width is not big enough, it fills the field with
- ** stars ("*****") and returns zero. Normal return is the width
- ** of the output field (sometimes shorter than 'width').
+ ** When the field width is not big enough, it fills the field with
+ ** stars ("*****") and returns zero. Normal return is the width
+ ** of the output field (sometimes shorter than 'width').
*/
#ifdef NOT_USED
int
ftoa(double value, char *ascii, int width, int prec1, char format)
{
#ifndef HAVE_FCVT
- char out[256];
- char fmt[256];
- int ret;
+ char out[256];
+ char fmt[256];
+ int ret;
sprintf(fmt, "%%%d.%d%c", width, prec1, format);
sprintf(out, fmt, value);
- if ((ret = strlen(out)) > width) {
+ if ((ret = strlen(out)) > width)
+ {
memset(ascii, '*', width - 2);
ascii[width] = 0;
- return(0);
+ return (0);
}
strcpy(ascii, out);
- return(ret);
+ return (ret);
#else
- auto int expon;
- auto int sign;
- register int avail = 0;
- register char *a = NULL;
- register char *p = NULL;
- char mode;
- int lowercase;
- int prec;
-/* extern char *ecvt(), *fcvt();*/
-
- prec = prec1;
- mode = format;
- lowercase = 'a' - 'A';
- if (mode >= 'a')
- mode -= 'a' - 'A';
- else
- lowercase = 0;
-
- if (mode != 'E') {
- /* try 'F' style output */
- p = fcvt(value, prec, &expon, &sign);
- avail = width;
- a = ascii;
-
- /* output sign */
- if (sign) {
- avail--;
- *a++ = '-';
+ auto int expon;
+ auto int sign;
+ register int avail = 0;
+ register char *a = NULL;
+ register char *p = NULL;
+ char mode;
+ int lowercase;
+ int prec;
+
+/* extern char *ecvt(), *fcvt();*/
+
+ prec = prec1;
+ mode = format;
+ lowercase = 'a' - 'A';
+ if (mode >= 'a')
+ mode -= 'a' - 'A';
+ else
+ lowercase = 0;
+
+ if (mode != 'E')
+ {
+ /* try 'F' style output */
+ p = fcvt(value, prec, &expon, &sign);
+ avail = width;
+ a = ascii;
+
+ /* output sign */
+ if (sign)
+ {
+ avail--;
+ *a++ = '-';
+ }
+
+ /* output '0' before the decimal point */
+ if (expon <= 0)
+ {
+ *a++ = '0';
+ avail--;
+ }
+
+ /* compute space length left after dec pt and fraction */
+ avail -= prec + 1;
+ if (mode == 'G')
+ avail -= 4;
+
+ if (avail >= expon)
+ {
+
+ /* it fits. output */
+ while (expon > 0)
+ {
+ /* output left of dp */
+ expon--;
+ if (*p)
+ {
+ *a++ = *p++;
+ }
+ else
+ *a++ = '0';
+ }
+
+ /* output fraction (right of dec pt) */
+ avail = expon;
+ goto frac_out;
+ }
+ /* won't fit; let's hope for G format */
}
-
- /* output '0' before the decimal point */
- if (expon <= 0) {
- *a++ = '0';
- avail--;
+
+ if (mode != 'F')
+ {
+ /* try to do E style output */
+ p = ecvt(value, prec + 1, &expon, &sign);
+ avail = width - 5;
+ a = ascii;
+
+ /* output the sign */
+ if (sign)
+ {
+ *a++ = '-';
+ avail--;
+ }
}
-
- /* compute space length left after dec pt and fraction */
- avail -= prec + 1;
- if (mode == 'G')
- avail -= 4;
-
- if (avail >= expon) {
-
- /* it fits. output */
- while (expon > 0) {
- /* output left of dp */
- expon--;
- if (*p) {
- *a++ = *p++;
- } else
- *a++ = '0';
- }
-
- /* output fraction (right of dec pt) */
- avail = expon;
- goto frac_out;
+
+ /* check for field too small */
+ if (mode == 'F' || avail < prec)
+ {
+ /* sorry joker, you lose */
+ a = ascii;
+ for (avail = width; avail > 0; avail--)
+ *a++ = '*';
+ *a = 0;
+ return (0);
}
- /* won't fit; let's hope for G format */
- }
-
- if (mode != 'F') {
- /* try to do E style output */
- p = ecvt(value, prec + 1, &expon, &sign);
- avail = width - 5;
- a = ascii;
-
- /* output the sign */
- if (sign) {
- *a++ = '-';
- avail--;
+
+ /* it fits; output the number */
+ mode = 'E';
+
+ /* output the LHS single digit */
+ *a++ = *p++;
+ expon--;
+
+ /* output the rhs */
+ avail = 1;
+
+frac_out:
+ *a++ = '.';
+ while (prec > 0)
+ {
+ prec--;
+ if (avail < 0)
+ {
+ avail++;
+ *a++ = '0';
+ }
+ else
+ {
+ if (*p)
+ *a++ = *p++;
+ else
+ *a++ = '0';
+ }
}
- }
-
- /* check for field too small */
- if (mode == 'F' || avail < prec) {
- /* sorry joker, you lose */
- a = ascii;
- for (avail = width; avail > 0; avail--)
- *a++ = '*';
- *a = 0;
- return (0);
- }
-
- /* it fits; output the number */
- mode = 'E';
-
- /* output the LHS single digit */
- *a++ = *p++;
- expon--;
-
- /* output the rhs */
- avail = 1;
-
- frac_out:
- *a++ = '.';
- while (prec > 0) {
- prec--;
- if (avail < 0) {
- avail++;
- *a++ = '0';
- } else {
- if (*p)
- *a++ = *p++;
- else
- *a++ = '0';
+
+ /* output the exponent */
+ if (mode == 'E')
+ {
+ *a++ = 'E' + lowercase;
+ if (expon < 0)
+ {
+ *a++ = '-';
+ expon = -expon;
+ }
+ else
+ *a++ = '+';
+ *a++ = (expon / 10) % 10 + '0';
+ *a++ = expon % 10 + '0';
}
- }
-
- /* output the exponent */
- if (mode == 'E') {
- *a++ = 'E' + lowercase;
- if (expon < 0) {
- *a++ = '-';
- expon = -expon;
- } else
- *a++ = '+';
- *a++ = (expon / 10) % 10 + '0';
- *a++ = expon % 10 + '0';
- }
-
- /* output spaces on the end in G format */
- if (mode == 'G') {
- *a++ = ' ';
- *a++ = ' ';
- *a++ = ' ';
- *a++ = ' ';
- }
-
- /* finally, we can return */
- *a = 0;
- avail = a - ascii;
- return (avail);
-#endif /* !BSD44_derived */
+
+ /* output spaces on the end in G format */
+ if (mode == 'G')
+ {
+ *a++ = ' ';
+ *a++ = ' ';
+ *a++ = ' ';
+ *a++ = ' ';
+ }
+
+ /* finally, we can return */
+ *a = 0;
+ avail = a - ascii;
+ return (avail);
+#endif /* !BSD44_derived */
}
+
#endif
/*
- ** atof1 - ASCII TO FLOATING CONVERSION
+ ** atof1 - ASCII TO FLOATING CONVERSION
**
- ** CODE derived from ~ingres/source/gutil/atof.c
+ ** CODE derived from ~ingres/source/gutil/atof.c
**
- ** Converts the string 'str' to floating point and stores the
- ** result into the cell pointed to by 'val'.
+ ** Converts the string 'str' to floating point and stores the
+ ** result into the cell pointed to by 'val'.
**
- ** The syntax which it accepts is pretty much what you would
- ** expect. Basically, it is:
- ** {<sp>} [+|-] {<sp>} {<digit>} [.{digit}] {<sp>} [<exp>]
- ** where <exp> is "e" or "E" followed by an integer, <sp> is a
- ** space character, <digit> is zero through nine, [] is zero or
- ** one, and {} is zero or more.
+ ** The syntax which it accepts is pretty much what you would
+ ** expect. Basically, it is:
+ ** {<sp>} [+|-] {<sp>} {<digit>} [.{digit}] {<sp>} [<exp>]
+ ** where <exp> is "e" or "E" followed by an integer, <sp> is a
+ ** space character, <digit> is zero through nine, [] is zero or
+ ** one, and {} is zero or more.
**
- ** Parameters:
- ** str -- string to convert.
- ** val -- pointer to place to put the result (which
- ** must be type double).
+ ** Parameters:
+ ** str -- string to convert.
+ ** val -- pointer to place to put the result (which
+ ** must be type double).
**
- ** Returns:
- ** zero -- ok.
- ** -1 -- syntax error.
- ** +1 -- overflow (not implemented).
+ ** Returns:
+ ** zero -- ok.
+ ** -1 -- syntax error.
+ ** +1 -- overflow (not implemented).
**
- ** Side Effects:
- ** clobbers *val.
+ ** Side Effects:
+ ** clobbers *val.
*/
#ifdef NOT_USED
int
atof1(char *str, double *val)
{
- register char *p;
- double v;
- double fact;
- int minus;
- register char c;
- int expon;
- register int gotmant;
-
- v = 0.0;
- p = str;
- minus = 0;
-
- /* skip leading blanks */
- while ((c = *p) != '\0') {
- if (c != ' ')
- break;
- p++;
- }
-
- /* handle possible sign */
- switch (c) {
- case '-':
- minus++;
-
- case '+':
- p++;
- }
-
- /* skip blanks after sign */
- while ((c = *p) != '\0') {
- if (c != ' ')
- break;
- p++;
- }
-
- /* start collecting the number to the decimal point */
- gotmant = 0;
- for (;;) {
- c = *p;
- if (c < '0' || c > '9')
- break;
- v = v * 10.0 + (c - '0');
- gotmant++;
- p++;
- }
-
- /* check for fractional part */
- if (c == '.') {
- fact = 1.0;
- for (;;) {
- c = *++p;
- if (c < '0' || c > '9')
- break;
- fact *= 0.1;
- v += (c - '0') * fact;
- gotmant++;
+ register char *p;
+ double v;
+ double fact;
+ int minus;
+ register char c;
+ int expon;
+ register int gotmant;
+
+ v = 0.0;
+ p = str;
+ minus = 0;
+
+ /* skip leading blanks */
+ while ((c = *p) != '\0')
+ {
+ if (c != ' ')
+ break;
+ p++;
+ }
+
+ /* handle possible sign */
+ switch (c)
+ {
+ case '-':
+ minus++;
+
+ case '+':
+ p++;
}
- }
-
- /* skip blanks before possible exponent */
- while ((c = *p) != '\0') {
- if (c != ' ')
- break;
- p++;
- }
-
- /* test for exponent */
- if (c == 'e' || c == 'E') {
- p++;
- expon = pg_atoi(p, sizeof(expon), '\0');
- if (!gotmant)
- v = 1.0;
- fact = expon;
- v *= pow(10.0, fact);
- } else {
- /* if no exponent, then nothing */
- if (c != 0)
- return (-1);
- }
-
- /* store the result and exit */
- if (minus)
- v = -v;
- *val = v;
- return (0);
+
+ /* skip blanks after sign */
+ while ((c = *p) != '\0')
+ {
+ if (c != ' ')
+ break;
+ p++;
+ }
+
+ /* start collecting the number to the decimal point */
+ gotmant = 0;
+ for (;;)
+ {
+ c = *p;
+ if (c < '0' || c > '9')
+ break;
+ v = v * 10.0 + (c - '0');
+ gotmant++;
+ p++;
+ }
+
+ /* check for fractional part */
+ if (c == '.')
+ {
+ fact = 1.0;
+ for (;;)
+ {
+ c = *++p;
+ if (c < '0' || c > '9')
+ break;
+ fact *= 0.1;
+ v += (c - '0') * fact;
+ gotmant++;
+ }
+ }
+
+ /* skip blanks before possible exponent */
+ while ((c = *p) != '\0')
+ {
+ if (c != ' ')
+ break;
+ p++;
+ }
+
+ /* test for exponent */
+ if (c == 'e' || c == 'E')
+ {
+ p++;
+ expon = pg_atoi(p, sizeof(expon), '\0');
+ if (!gotmant)
+ v = 1.0;
+ fact = expon;
+ v *= pow(10.0, fact);
+ }
+ else
+ {
+ /* if no exponent, then nothing */
+ if (c != 0)
+ return (-1);
+ }
+
+ /* store the result and exit */
+ if (minus)
+ v = -v;
+ *val = v;
+ return (0);
}
+
#endif
diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c
index 977fe87fbca..864c272c793 100644
--- a/src/backend/utils/adt/oid.c
+++ b/src/backend/utils/adt/oid.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* oid.c--
- * Functions for the built-in type Oid.
+ * Functions for the built-in type Oid.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/oid.c,v 1.8 1997/08/24 23:07:35 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/oid.c,v 1.9 1997/09/07 04:50:34 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,114 +16,125 @@
#include <string.h>
#include "postgres.h"
-#include "utils/builtins.h" /* where function declarations go */
+#include "utils/builtins.h" /* where function declarations go */
-/*****************************************************************************
- * USER I/O ROUTINES *
+/*****************************************************************************
+ * USER I/O ROUTINES *
*****************************************************************************/
/*
- * oid8in - converts "num num ..." to internal form
+ * oid8in - converts "num num ..." to internal form
*
- * Note:
- * Fills any nonexistent digits with NULL oids.
+ * Note:
+ * Fills any nonexistent digits with NULL oids.
*/
-Oid *oid8in(char *oidString)
+Oid *
+oid8in(char *oidString)
{
- register Oid (*result)[];
- int nums;
-
- if (oidString == NULL)
- return(NULL);
- result = (Oid (*)[]) palloc(sizeof(Oid [8]));
- if ((nums = sscanf(oidString, "%d%d%d%d%d%d%d%d",
- &(*result)[0],
- &(*result)[1],
- &(*result)[2],
- &(*result)[3],
- &(*result)[4],
- &(*result)[5],
- &(*result)[6],
- &(*result)[7])) != 8) {
- do
- (*result)[nums++] = 0;
- while (nums < 8);
- }
- return((Oid *) result);
+ register Oid(*result)[];
+ int nums;
+
+ if (oidString == NULL)
+ return (NULL);
+ result = (Oid(*)[]) palloc(sizeof(Oid[8]));
+ if ((nums = sscanf(oidString, "%d%d%d%d%d%d%d%d",
+ &(*result)[0],
+ &(*result)[1],
+ &(*result)[2],
+ &(*result)[3],
+ &(*result)[4],
+ &(*result)[5],
+ &(*result)[6],
+ &(*result)[7])) != 8)
+ {
+ do
+ (*result)[nums++] = 0;
+ while (nums < 8);
+ }
+ return ((Oid *) result);
}
/*
- * oid8out - converts internal form to "num num ..."
+ * oid8out - converts internal form to "num num ..."
*/
-char *oid8out(Oid (*oidArray)[])
+char *
+oid8out(Oid(*oidArray)[])
{
- register int num;
- register Oid *sp;
- register char *rp;
- char *result;
-
- if (oidArray == NULL) {
- result = (char *) palloc(2);
- result[0] = '-';
- result[1] = '\0';
- return(result);
- }
-
- /* assumes sign, 10 digits, ' ' */
- rp = result = (char *) palloc(8 * 12);
- sp = *oidArray;
- for (num = 8; num != 0; num--) {
- ltoa(*sp++, rp);
- while (*++rp != '\0')
- ;
- *rp++ = ' ';
- }
- *--rp = '\0';
- return(result);
+ register int num;
+ register Oid *sp;
+ register char *rp;
+ char *result;
+
+ if (oidArray == NULL)
+ {
+ result = (char *) palloc(2);
+ result[0] = '-';
+ result[1] = '\0';
+ return (result);
+ }
+
+ /* assumes sign, 10 digits, ' ' */
+ rp = result = (char *) palloc(8 * 12);
+ sp = *oidArray;
+ for (num = 8; num != 0; num--)
+ {
+ ltoa(*sp++, rp);
+ while (*++rp != '\0')
+ ;
+ *rp++ = ' ';
+ }
+ *--rp = '\0';
+ return (result);
}
-Oid oidin(char *s)
+Oid
+oidin(char *s)
{
- return(int4in(s));
+ return (int4in(s));
}
-char *oidout(Oid o)
+char *
+oidout(Oid o)
{
- return(int4out(o));
+ return (int4out(o));
}
-/*****************************************************************************
- * PUBLIC ROUTINES *
+/*****************************************************************************
+ * PUBLIC ROUTINES *
*****************************************************************************/
/*
* If you change this function, change heap_keytest()
* because we have hardcoded this in there as an optimization
*/
-bool oideq(Oid arg1, Oid arg2)
+bool
+oideq(Oid arg1, Oid arg2)
{
- return(arg1 == arg2);
+ return (arg1 == arg2);
}
-bool oidne(Oid arg1, Oid arg2)
+bool
+oidne(Oid arg1, Oid arg2)
{
- return(arg1 != arg2);
+ return (arg1 != arg2);
}
-bool oid8eq(Oid arg1[], Oid arg2[])
+bool
+oid8eq(Oid arg1[], Oid arg2[])
{
- return (bool)(memcmp(arg1, arg2, 8 * sizeof(Oid)) == 0);
+ return (bool) (memcmp(arg1, arg2, 8 * sizeof(Oid)) == 0);
}
-bool oideqint4(Oid arg1, int32 arg2)
+bool
+oideqint4(Oid arg1, int32 arg2)
{
/* oid is unsigned, but int4 is signed */
- return (arg2 >= 0 && arg1 == arg2);
+ return (arg2 >= 0 && arg1 == arg2);
}
-bool int4eqoid(int32 arg1, Oid arg2)
+bool
+int4eqoid(int32 arg1, Oid arg2)
{
/* oid is unsigned, but int4 is signed */
- return (arg1 >= 0 && arg1 == arg2);
+ return (arg1 >= 0 && arg1 == arg2);
}
-
diff --git a/src/backend/utils/adt/oidint2.c b/src/backend/utils/adt/oidint2.c
index 4d92821e8d8..009ab233f78 100644
--- a/src/backend/utils/adt/oidint2.c
+++ b/src/backend/utils/adt/oidint2.c
@@ -1,120 +1,120 @@
/*-------------------------------------------------------------------------
*
* oidint2.c--
- * Functions for the built-in type "oidint2".
+ * Functions for the built-in type "oidint2".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidint2.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidint2.c,v 1.2 1997/09/07 04:50:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include "postgres.h"
#include "utils/palloc.h"
-#include "utils/builtins.h" /* for pg_atoi() */
+#include "utils/builtins.h" /* for pg_atoi() */
#include "utils/oidcompos.h" /* where function declarations go */
OidInt2
oidint2in(char *o)
{
- OidInt2 oi;
- char *p;
-
- oi = (OidInt2) palloc(sizeof(OidInt2Data));
-
- for (p = o; *p != '\0' && *p != '/'; p++)
- continue;
-
- oi->oi_oid = (Oid) pg_atoi(o, sizeof(Oid), '/');
- if (*p == '\0') {
- oi->oi_int2 = 0;
- } else {
- oi->oi_int2 = (int16) pg_atoi(++p, sizeof(int2), '\0');
- }
-
- return (oi);
+ OidInt2 oi;
+ char *p;
+
+ oi = (OidInt2) palloc(sizeof(OidInt2Data));
+
+ for (p = o; *p != '\0' && *p != '/'; p++)
+ continue;
+
+ oi->oi_oid = (Oid) pg_atoi(o, sizeof(Oid), '/');
+ if (*p == '\0')
+ {
+ oi->oi_int2 = 0;
+ }
+ else
+ {
+ oi->oi_int2 = (int16) pg_atoi(++p, sizeof(int2), '\0');
+ }
+
+ return (oi);
}
-char *
+char *
oidint2out(OidInt2 o)
{
- char *r;
-
- /*
- * -2147483647/-32767
- * 0 1
- * 1234567890123456789
- */
- r = (char *) palloc(19);
- sprintf(r, "%d/%d", o->oi_oid, o->oi_int2);
-
- return (r);
+ char *r;
+
+ /*
+ * -2147483647/-32767 0 1 1234567890123456789
+ */
+ r = (char *) palloc(19);
+ sprintf(r, "%d/%d", o->oi_oid, o->oi_int2);
+
+ return (r);
}
bool
oidint2lt(OidInt2 o1, OidInt2 o2)
{
- return
- ((bool) (o1->oi_oid < o2->oi_oid ||
- (o1->oi_oid == o2->oi_oid && o1->oi_int2 < o2->oi_int2)));
+ return
+ ((bool) (o1->oi_oid < o2->oi_oid ||
+ (o1->oi_oid == o2->oi_oid && o1->oi_int2 < o2->oi_int2)));
}
bool
oidint2le(OidInt2 o1, OidInt2 o2)
{
- return ((bool) (o1->oi_oid < o2->oi_oid ||
- (o1->oi_oid == o2->oi_oid && o1->oi_int2 <= o2->oi_int2)));
+ return ((bool) (o1->oi_oid < o2->oi_oid ||
+ (o1->oi_oid == o2->oi_oid && o1->oi_int2 <= o2->oi_int2)));
}
bool
oidint2eq(OidInt2 o1, OidInt2 o2)
{
- return ((bool) (o1->oi_oid == o2->oi_oid && o1->oi_int2 == o2->oi_int2));
+ return ((bool) (o1->oi_oid == o2->oi_oid && o1->oi_int2 == o2->oi_int2));
}
bool
oidint2ge(OidInt2 o1, OidInt2 o2)
{
- return ((bool) (o1->oi_oid > o2->oi_oid ||
- (o1->oi_oid == o2->oi_oid && o1->oi_int2 >= o2->oi_int2)));
+ return ((bool) (o1->oi_oid > o2->oi_oid ||
+ (o1->oi_oid == o2->oi_oid && o1->oi_int2 >= o2->oi_int2)));
}
bool
oidint2gt(OidInt2 o1, OidInt2 o2)
{
- return ((bool) (o1->oi_oid > o2->oi_oid ||
- (o1->oi_oid == o2->oi_oid && o1->oi_int2 > o2->oi_int2)));
+ return ((bool) (o1->oi_oid > o2->oi_oid ||
+ (o1->oi_oid == o2->oi_oid && o1->oi_int2 > o2->oi_int2)));
}
bool
oidint2ne(OidInt2 o1, OidInt2 o2)
{
- return ((bool) (o1->oi_oid != o2->oi_oid || o1->oi_int2 != o2->oi_int2));
+ return ((bool) (o1->oi_oid != o2->oi_oid || o1->oi_int2 != o2->oi_int2));
}
int
oidint2cmp(OidInt2 o1, OidInt2 o2)
{
- if (oidint2lt(o1, o2))
- return (-1);
- else if (oidint2eq(o1, o2))
- return (0);
- else
- return (1);
+ if (oidint2lt(o1, o2))
+ return (-1);
+ else if (oidint2eq(o1, o2))
+ return (0);
+ else
+ return (1);
}
OidInt2
mkoidint2(Oid v_oid, uint16 v_int2)
{
- OidInt2 o;
-
- o = (OidInt2) palloc(sizeof(OidInt2Data));
- o->oi_oid = v_oid;
- o->oi_int2 = v_int2;
- return (o);
-}
+ OidInt2 o;
+ o = (OidInt2) palloc(sizeof(OidInt2Data));
+ o->oi_oid = v_oid;
+ o->oi_int2 = v_int2;
+ return (o);
+}
diff --git a/src/backend/utils/adt/oidint4.c b/src/backend/utils/adt/oidint4.c
index d0844411a73..c4da5141acf 100644
--- a/src/backend/utils/adt/oidint4.c
+++ b/src/backend/utils/adt/oidint4.c
@@ -1,111 +1,120 @@
/*-------------------------------------------------------------------------
*
* oidint4.c--
- * Functions for the built-in type "oidint4".
+ * Functions for the built-in type "oidint4".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidint4.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidint4.c,v 1.2 1997/09/07 04:50:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/builtins.h"
#include "utils/oidcompos.h" /* where function declarations go */
-OidInt4 oidint4in(char *o)
+OidInt4
+oidint4in(char *o)
{
- OidInt4 oi;
- char *p;
-
- oi = (OidInt4) palloc(sizeof(OidInt4Data));
-
- for (p = o; *p != '\0' && *p != '/'; p++)
- continue;
-
- oi->oi_oid = (Oid) pg_atoi(o, sizeof(Oid), '/');
- if (*p == '\0') {
- oi->oi_int4 = 0;
- } else {
- oi->oi_int4 = pg_atoi(++p, sizeof(int4), '\0');
- }
-
- return (oi);
+ OidInt4 oi;
+ char *p;
+
+ oi = (OidInt4) palloc(sizeof(OidInt4Data));
+
+ for (p = o; *p != '\0' && *p != '/'; p++)
+ continue;
+
+ oi->oi_oid = (Oid) pg_atoi(o, sizeof(Oid), '/');
+ if (*p == '\0')
+ {
+ oi->oi_int4 = 0;
+ }
+ else
+ {
+ oi->oi_int4 = pg_atoi(++p, sizeof(int4), '\0');
+ }
+
+ return (oi);
}
-char *oidint4out(OidInt4 o)
+char *
+oidint4out(OidInt4 o)
{
- char *r;
-
- /*
- * -2147483647/-2147483647
- * 0 1 2
- * 123456789012345678901234
- */
- r = (char *) palloc(24);
- sprintf(r, "%d/%d", o->oi_oid, o->oi_int4);
-
- return (r);
+ char *r;
+
+ /*
+ * -2147483647/-2147483647 0 1 2
+ * 123456789012345678901234
+ */
+ r = (char *) palloc(24);
+ sprintf(r, "%d/%d", o->oi_oid, o->oi_int4);
+
+ return (r);
}
-bool oidint4lt(OidInt4 o1, OidInt4 o2)
+bool
+oidint4lt(OidInt4 o1, OidInt4 o2)
{
- return
+ return
((bool) (o1->oi_oid < o2->oi_oid ||
- (o1->oi_oid == o2->oi_oid && o1->oi_int4 < o2->oi_int4)));
+ (o1->oi_oid == o2->oi_oid && o1->oi_int4 < o2->oi_int4)));
}
-bool oidint4le(OidInt4 o1, OidInt4 o2)
+bool
+oidint4le(OidInt4 o1, OidInt4 o2)
{
- return ((bool) (o1->oi_oid < o2->oi_oid ||
- (o1->oi_oid == o2->oi_oid && o1->oi_int4 <= o2->oi_int4)));
+ return ((bool) (o1->oi_oid < o2->oi_oid ||
+ (o1->oi_oid == o2->oi_oid && o1->oi_int4 <= o2->oi_int4)));
}
-bool oidint4eq(OidInt4 o1, OidInt4 o2)
+bool
+oidint4eq(OidInt4 o1, OidInt4 o2)
{
- return ((bool) (o1->oi_oid == o2->oi_oid && o1->oi_int4 == o2->oi_int4));
+ return ((bool) (o1->oi_oid == o2->oi_oid && o1->oi_int4 == o2->oi_int4));
}
-bool oidint4ge(OidInt4 o1, OidInt4 o2)
+bool
+oidint4ge(OidInt4 o1, OidInt4 o2)
{
- return ((bool) (o1->oi_oid > o2->oi_oid ||
- (o1->oi_oid == o2->oi_oid && o1->oi_int4 >= o2->oi_int4)));
+ return ((bool) (o1->oi_oid > o2->oi_oid ||
+ (o1->oi_oid == o2->oi_oid && o1->oi_int4 >= o2->oi_int4)));
}
-bool oidint4gt(OidInt4 o1, OidInt4 o2)
+bool
+oidint4gt(OidInt4 o1, OidInt4 o2)
{
- return ((bool) (o1->oi_oid > o2->oi_oid ||
- (o1->oi_oid == o2->oi_oid && o1->oi_int4 > o2->oi_int4)));
+ return ((bool) (o1->oi_oid > o2->oi_oid ||
+ (o1->oi_oid == o2->oi_oid && o1->oi_int4 > o2->oi_int4)));
}
-bool oidint4ne(OidInt4 o1, OidInt4 o2)
+bool
+oidint4ne(OidInt4 o1, OidInt4 o2)
{
- return ((bool) (o1->oi_oid != o2->oi_oid || o1->oi_int4 != o2->oi_int4));
+ return ((bool) (o1->oi_oid != o2->oi_oid || o1->oi_int4 != o2->oi_int4));
}
-int oidint4cmp(OidInt4 o1, OidInt4 o2)
+int
+oidint4cmp(OidInt4 o1, OidInt4 o2)
{
- if (oidint4lt(o1, o2))
- return (-1);
- else if (oidint4eq(o1, o2))
- return (0);
- else
- return (1);
+ if (oidint4lt(o1, o2))
+ return (-1);
+ else if (oidint4eq(o1, o2))
+ return (0);
+ else
+ return (1);
}
-OidInt4 mkoidint4(Oid v_oid, uint32 v_int4)
+OidInt4
+mkoidint4(Oid v_oid, uint32 v_int4)
{
- OidInt4 o;
-
- o = (OidInt4) palloc(sizeof(OidInt4Data));
- o->oi_oid = v_oid;
- o->oi_int4 = v_int4;
- return (o);
-}
-
-
+ OidInt4 o;
+ o = (OidInt4) palloc(sizeof(OidInt4Data));
+ o->oi_oid = v_oid;
+ o->oi_int4 = v_int4;
+ return (o);
+}
diff --git a/src/backend/utils/adt/oidname.c b/src/backend/utils/adt/oidname.c
index 425fa78f65c..30a081f2531 100644
--- a/src/backend/utils/adt/oidname.c
+++ b/src/backend/utils/adt/oidname.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* oidname.c--
- * adt for multiple key indices involving oid and name. Used for cache
- * index scans (could also be used in the general case with name).
+ * adt for multiple key indices involving oid and name. Used for cache
+ * index scans (could also be used in the general case with name).
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidname.c,v 1.4 1997/08/12 20:16:03 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidname.c,v 1.5 1997/09/07 04:50:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,106 +17,109 @@
#include "postgres.h"
#include "utils/oidcompos.h" /* where function declarations go */
-#include "utils/builtins.h" /* for pg_atoi() */
+#include "utils/builtins.h" /* for pg_atoi() */
#include "utils/palloc.h"
OidName
oidnamein(char *inStr)
{
- OidName oc;
- char *inptr;
-
- oc = (OidName) palloc(sizeof(OidNameData));
-
- memset(oc, 0, sizeof(OidNameData));
- for (inptr = inStr; *inptr && *inptr != ','; inptr++)
- ;
-
- if (*inptr) {
- oc->id = (Oid) pg_atoi(inStr, sizeof(Oid), ',');
- /* copy one less to ensure null-padding */
- ++inptr;
- strNcpy(oc->name.data,inptr,NAMEDATALEN-1);
- }else
- elog(WARN, "Bad input data for type oidname");
-
- return oc;
+ OidName oc;
+ char *inptr;
+
+ oc = (OidName) palloc(sizeof(OidNameData));
+
+ memset(oc, 0, sizeof(OidNameData));
+ for (inptr = inStr; *inptr && *inptr != ','; inptr++)
+ ;
+
+ if (*inptr)
+ {
+ oc->id = (Oid) pg_atoi(inStr, sizeof(Oid), ',');
+ /* copy one less to ensure null-padding */
+ ++inptr;
+ strNcpy(oc->name.data, inptr, NAMEDATALEN - 1);
+ }
+ else
+ elog(WARN, "Bad input data for type oidname");
+
+ return oc;
}
-char *
+char *
oidnameout(OidName oidname)
{
- char buf[30+NAMEDATALEN]; /* oidname length + oid length + some safety */
- char *res;
-
- sprintf(buf, "%d,%s", oidname->id, oidname->name.data);
- res = pstrdup(buf);
- return(res);
+ char buf[30 + NAMEDATALEN]; /* oidname length + oid
+ * length + some safety */
+ char *res;
+
+ sprintf(buf, "%d,%s", oidname->id, oidname->name.data);
+ res = pstrdup(buf);
+ return (res);
}
bool
oidnamelt(OidName o1, OidName o2)
{
- return (bool)
- (o1->id < o2->id ||
- (o1->id == o2->id && namecmp(&o1->name, &o2->name) < 0));
+ return (bool)
+ (o1->id < o2->id ||
+ (o1->id == o2->id && namecmp(&o1->name, &o2->name) < 0));
}
bool
oidnamele(OidName o1, OidName o2)
{
- return (bool)
- (o1->id < o2->id ||
- (o1->id == o2->id && namecmp(&o1->name,&o2->name) <= 0));
+ return (bool)
+ (o1->id < o2->id ||
+ (o1->id == o2->id && namecmp(&o1->name, &o2->name) <= 0));
}
bool
oidnameeq(OidName o1, OidName o2)
{
- return (bool)
- (o1->id == o2->id &&
- (namecmp(&o1->name, &o2->name) == 0));
+ return (bool)
+ (o1->id == o2->id &&
+ (namecmp(&o1->name, &o2->name) == 0));
}
bool
oidnamene(OidName o1, OidName o2)
{
- return (bool)
- (o1->id != o2->id ||
- (namecmp(&o1->name,&o2->name) != 0));
+ return (bool)
+ (o1->id != o2->id ||
+ (namecmp(&o1->name, &o2->name) != 0));
}
bool
oidnamege(OidName o1, OidName o2)
{
- return (bool) (o1->id > o2->id || (o1->id == o2->id &&
- namecmp(&o1->name, &o2->name) >= 0));
+ return (bool) (o1->id > o2->id || (o1->id == o2->id &&
+ namecmp(&o1->name, &o2->name) >= 0));
}
bool
oidnamegt(OidName o1, OidName o2)
{
- return (bool) (o1->id > o2->id || (o1->id == o2->id &&
- namecmp(&o1->name, &o2->name) > 0));
+ return (bool) (o1->id > o2->id || (o1->id == o2->id &&
+ namecmp(&o1->name, &o2->name) > 0));
}
int
oidnamecmp(OidName o1, OidName o2)
{
- if (o1->id == o2->id)
- return (namecmp(&o1->name,&o2->name));
-
- return (o1->id < o2->id) ? -1 : 1;
+ if (o1->id == o2->id)
+ return (namecmp(&o1->name, &o2->name));
+
+ return (o1->id < o2->id) ? -1 : 1;
}
OidName
mkoidname(Oid id, char *name)
{
- OidName oidname;
-
- oidname = (OidName) palloc(sizeof(Oid)+NAMEDATALEN);
-
- oidname->id = id;
- namestrcpy(&oidname->name,name);
- return oidname;
+ OidName oidname;
+
+ oidname = (OidName) palloc(sizeof(Oid) + NAMEDATALEN);
+
+ oidname->id = id;
+ namestrcpy(&oidname->name, name);
+ return oidname;
}
diff --git a/src/backend/utils/adt/oracle_compat.c b/src/backend/utils/adt/oracle_compat.c
index 6082311c54a..99acb57b58f 100644
--- a/src/backend/utils/adt/oracle_compat.c
+++ b/src/backend/utils/adt/oracle_compat.c
@@ -1,7 +1,7 @@
/*
- * Edmund Mergl <[email protected]>
+ * Edmund Mergl <[email protected]>
*
- * $Id: oracle_compat.c,v 1.7 1997/07/29 16:12:01 thomas Exp $
+ * $Id: oracle_compat.c,v 1.8 1997/09/07 04:50:38 momjian Exp $
*
*/
@@ -10,16 +10,16 @@
#include "postgres.h"
-text *lower(text *string);
-text *upper(text *string);
-text *initcap(text *string);
-text *lpad(text *string1, int4 len, text *string2);
-text *rpad(text *string1, int4 len, text *string2);
-text *btrim(text *string, text *set);
-text *ltrim(text *string, text *set);
-text *rtrim(text *string, text *set);
-text *substr(text *string, int4 m, int4 n);
-text *translate(text *string, char from, char to);
+text *lower(text * string);
+text *upper(text * string);
+text *initcap(text * string);
+text *lpad(text * string1, int4 len, text * string2);
+text *rpad(text * string1, int4 len, text * string2);
+text *btrim(text * string, text * set);
+text *ltrim(text * string, text * set);
+text *rtrim(text * string, text * set);
+text *substr(text * string, int4 m, int4 n);
+text *translate(text * string, char from, char to);
/********************************************************************
@@ -28,35 +28,37 @@ text *translate(text *string, char from, char to);
*
* Syntax:
*
- * text *lower(text *string)
+ * text *lower(text *string)
*
* Purpose:
*
- * Returns string, with all letters forced to lowercase.
+ * Returns string, with all letters forced to lowercase.
*
********************************************************************/
-text *
-lower(text *string)
+text *
+lower(text * string)
{
- text *ret;
- char *ptr, *ptr_ret;
- int m;
+ text *ret;
+ char *ptr,
+ *ptr_ret;
+ int m;
- if ((string == (text *)NULL) || ((m = VARSIZE(string) - VARHDRSZ) <= 0))
- return string;
+ if ((string == (text *) NULL) || ((m = VARSIZE(string) - VARHDRSZ) <= 0))
+ return string;
- ret = (text *)palloc(VARSIZE(string));
- VARSIZE(ret) = VARSIZE(string);
+ ret = (text *) palloc(VARSIZE(string));
+ VARSIZE(ret) = VARSIZE(string);
- ptr = VARDATA(string);
- ptr_ret = VARDATA(ret);
+ ptr = VARDATA(string);
+ ptr_ret = VARDATA(ret);
- while (m--) {
- *ptr_ret++ = tolower(*ptr++);
- }
+ while (m--)
+ {
+ *ptr_ret++ = tolower(*ptr++);
+ }
- return ret;
+ return ret;
}
@@ -66,35 +68,37 @@ lower(text *string)
*
* Syntax:
*
- * text *upper(text *string)
+ * text *upper(text *string)
*
* Purpose:
*
- * Returns string, with all letters forced to uppercase.
+ * Returns string, with all letters forced to uppercase.
*
********************************************************************/
-text *
-upper(text *string)
+text *
+upper(text * string)
{
- text *ret;
- char *ptr, *ptr_ret;
- int m;
+ text *ret;
+ char *ptr,
+ *ptr_ret;
+ int m;
- if ((string == (text *)NULL) || ((m = VARSIZE(string) - VARHDRSZ) <= 0))
- return string;
+ if ((string == (text *) NULL) || ((m = VARSIZE(string) - VARHDRSZ) <= 0))
+ return string;
- ret = (text *)palloc(VARSIZE(string));
- VARSIZE(ret) = VARSIZE(string);
+ ret = (text *) palloc(VARSIZE(string));
+ VARSIZE(ret) = VARSIZE(string);
- ptr = VARDATA(string);
- ptr_ret = VARDATA(ret);
+ ptr = VARDATA(string);
+ ptr_ret = VARDATA(ret);
- while (m--) {
- *ptr_ret++ = toupper(*ptr++);
- }
+ while (m--)
+ {
+ *ptr_ret++ = toupper(*ptr++);
+ }
- return ret;
+ return ret;
}
@@ -104,44 +108,49 @@ upper(text *string)
*
* Syntax:
*
- * text *initcap(text *string)
+ * text *initcap(text *string)
*
* Purpose:
*
- * Returns string, with first letter of each word in uppercase,
- * all other letters in lowercase. A word is delimited by white
- * space.
+ * Returns string, with first letter of each word in uppercase,
+ * all other letters in lowercase. A word is delimited by white
+ * space.
*
********************************************************************/
-text *
-initcap(text *string)
+text *
+initcap(text * string)
{
- text *ret;
- char *ptr, *ptr_ret;
- int m;
-
- if ((string == (text *)NULL) || ((m = VARSIZE(string) - VARHDRSZ) <= 0))
- return string;
-
- ret = (text *)palloc(VARSIZE(string));
- VARSIZE(ret) = VARSIZE(string);
-
- ptr = VARDATA(string);
- ptr_ret = VARDATA(ret);
-
- *ptr_ret++ = toupper(*ptr++);
- --m;
-
- while (m--) {
- if (*(ptr_ret - 1) == ' ' || *(ptr_ret - 1) == ' ') {
- *ptr_ret++ = toupper(*ptr++);
- } else {
- *ptr_ret++ = tolower(*ptr++);
- }
- }
-
- return ret;
+ text *ret;
+ char *ptr,
+ *ptr_ret;
+ int m;
+
+ if ((string == (text *) NULL) || ((m = VARSIZE(string) - VARHDRSZ) <= 0))
+ return string;
+
+ ret = (text *) palloc(VARSIZE(string));
+ VARSIZE(ret) = VARSIZE(string);
+
+ ptr = VARDATA(string);
+ ptr_ret = VARDATA(ret);
+
+ *ptr_ret++ = toupper(*ptr++);
+ --m;
+
+ while (m--)
+ {
+ if (*(ptr_ret - 1) == ' ' || *(ptr_ret - 1) == ' ')
+ {
+ *ptr_ret++ = toupper(*ptr++);
+ }
+ else
+ {
+ *ptr_ret++ = tolower(*ptr++);
+ }
+ }
+
+ return ret;
}
@@ -151,48 +160,53 @@ initcap(text *string)
*
* Syntax:
*
- * text *lpad(text *string1, int4 len, text *string2)
+ * text *lpad(text *string1, int4 len, text *string2)
*
* Purpose:
*
- * Returns string1, left-padded to length len with the sequence of
- * characters in string2.
+ * Returns string1, left-padded to length len with the sequence of
+ * characters in string2.
*
********************************************************************/
-text *
-lpad(text *string1, int4 len, text *string2)
+text *
+lpad(text * string1, int4 len, text * string2)
{
- text *ret;
- char *ptr1, *ptr2, *ptr_ret;
- int m, n;
-
- if ((string1 == (text *)NULL) ||
- (len <= (VARSIZE(string1) - VARHDRSZ)) ||
- ((m = len - VARSIZE(string1) + VARHDRSZ) <= 0) ||
- (string2 == (text *)NULL) ||
- ((VARSIZE(string2) - VARHDRSZ) <= 0))
- return string1;
-
- ret = (text *)palloc(VARHDRSZ + len);
- VARSIZE(ret) = VARHDRSZ + len;
-
- ptr2 = VARDATA(string2);
- ptr_ret = VARDATA(ret);
-
- while (m--) {
- *ptr_ret++ = *ptr2;
- ptr2 = ptr2 == VARDATA(string2) + VARSIZE(string2) - VARHDRSZ - 1 ? VARDATA(string2) : ++ptr2;
- }
-
- n = VARSIZE(string1) - VARHDRSZ;
- ptr1 = VARDATA(string1);
-
- while (n--) {
- *ptr_ret++ = *ptr1++;
- }
-
- return ret;
+ text *ret;
+ char *ptr1,
+ *ptr2,
+ *ptr_ret;
+ int m,
+ n;
+
+ if ((string1 == (text *) NULL) ||
+ (len <= (VARSIZE(string1) - VARHDRSZ)) ||
+ ((m = len - VARSIZE(string1) + VARHDRSZ) <= 0) ||
+ (string2 == (text *) NULL) ||
+ ((VARSIZE(string2) - VARHDRSZ) <= 0))
+ return string1;
+
+ ret = (text *) palloc(VARHDRSZ + len);
+ VARSIZE(ret) = VARHDRSZ + len;
+
+ ptr2 = VARDATA(string2);
+ ptr_ret = VARDATA(ret);
+
+ while (m--)
+ {
+ *ptr_ret++ = *ptr2;
+ ptr2 = ptr2 == VARDATA(string2) + VARSIZE(string2) - VARHDRSZ - 1 ? VARDATA(string2) : ++ptr2;
+ }
+
+ n = VARSIZE(string1) - VARHDRSZ;
+ ptr1 = VARDATA(string1);
+
+ while (n--)
+ {
+ *ptr_ret++ = *ptr1++;
+ }
+
+ return ret;
}
@@ -202,48 +216,53 @@ lpad(text *string1, int4 len, text *string2)
*
* Syntax:
*
- * text *rpad(text *string1, int4 len, text *string2)
+ * text *rpad(text *string1, int4 len, text *string2)
*
* Purpose:
*
- * Returns string1, right-padded to length len with the sequence of
- * characters in string2.
+ * Returns string1, right-padded to length len with the sequence of
+ * characters in string2.
*
********************************************************************/
-text *
-rpad(text *string1, int4 len, text *string2)
+text *
+rpad(text * string1, int4 len, text * string2)
{
- text *ret;
- char *ptr1, *ptr2, *ptr_ret;
- int m, n;
-
- if ((string1 == (text *)NULL) ||
- (len <= (VARSIZE(string1) - VARHDRSZ)) ||
- ((m = len - VARSIZE(string1) + VARHDRSZ) <= 0) ||
- (string2 == (text *)NULL) ||
- ((VARSIZE(string2) - VARHDRSZ) <= 0))
- return string1;
-
- ret = (text *)palloc(VARHDRSZ + len);
- VARSIZE(ret) = VARHDRSZ + len;
-
- n = VARSIZE(string1) - VARHDRSZ;
- ptr1 = VARDATA(string1);
- ptr_ret = VARDATA(ret);
-
- while (n--) {
- *ptr_ret++ = *ptr1++;
- }
-
- ptr2 = VARDATA(string2);
-
- while (m--) {
- *ptr_ret++ = *ptr2;
- ptr2 = ptr2 == VARDATA(string2) + VARSIZE(string2) - VARHDRSZ - 1 ? VARDATA(string2) : ++ptr2;
- }
-
- return ret;
+ text *ret;
+ char *ptr1,
+ *ptr2,
+ *ptr_ret;
+ int m,
+ n;
+
+ if ((string1 == (text *) NULL) ||
+ (len <= (VARSIZE(string1) - VARHDRSZ)) ||
+ ((m = len - VARSIZE(string1) + VARHDRSZ) <= 0) ||
+ (string2 == (text *) NULL) ||
+ ((VARSIZE(string2) - VARHDRSZ) <= 0))
+ return string1;
+
+ ret = (text *) palloc(VARHDRSZ + len);
+ VARSIZE(ret) = VARHDRSZ + len;
+
+ n = VARSIZE(string1) - VARHDRSZ;
+ ptr1 = VARDATA(string1);
+ ptr_ret = VARDATA(ret);
+
+ while (n--)
+ {
+ *ptr_ret++ = *ptr1++;
+ }
+
+ ptr2 = VARDATA(string2);
+
+ while (m--)
+ {
+ *ptr_ret++ = *ptr2;
+ ptr2 = ptr2 == VARDATA(string2) + VARSIZE(string2) - VARHDRSZ - 1 ? VARDATA(string2) : ++ptr2;
+ }
+
+ return ret;
}
@@ -253,73 +272,84 @@ rpad(text *string1, int4 len, text *string2)
*
* Syntax:
*
- * text *btrim(text *string, text *set)
+ * text *btrim(text *string, text *set)
*
* Purpose:
*
- * Returns string with characters removed from the front and back
- * up to the first character not in set.
+ * Returns string with characters removed from the front and back
+ * up to the first character not in set.
*
********************************************************************/
-text *
-btrim(text *string, text *set)
+text *
+btrim(text * string, text * set)
{
- text *ret;
- char *ptr, *end, *ptr2, *end2;
- int m;
-
- if ((string == (text *)NULL) ||
- ((m = VARSIZE(string) - VARHDRSZ) <= 0) ||
- (set == (text *)NULL) ||
- ((VARSIZE(set) - VARHDRSZ) <= 0))
- return string;
-
- ptr = VARDATA(string);
- ptr2 = VARDATA(set);
- end2 = VARDATA(set) + VARSIZE(set) - VARHDRSZ - 1;
-
- while (m--) {
- while (ptr2 <= end2) {
- if (*ptr == *ptr2) {
- break;
- }
- ++ptr2;
- }
- if (*ptr != *ptr2) {
- break;
- }
- ptr++;
- ptr2 = VARDATA(set);
- }
-
- ++m;
-
- end = VARDATA(string) + VARSIZE(string) - VARHDRSZ - 1;
- ptr2 = VARDATA(set);
-
- while (m--) {
- while (ptr2 <= end2) {
- if (*end == *ptr2) {
- break;
- }
- ++ptr2;
- }
- if (*end != *ptr2) {
- break;
- }
- --end;
- ptr2 = VARDATA(set);
- }
-
- ++m;
-
- ret = (text *)palloc(VARHDRSZ + m);
- VARSIZE(ret) = VARHDRSZ + m;
- memcpy(VARDATA(ret),ptr,m);
-
- return ret;
-} /* btrim() */
+ text *ret;
+ char *ptr,
+ *end,
+ *ptr2,
+ *end2;
+ int m;
+
+ if ((string == (text *) NULL) ||
+ ((m = VARSIZE(string) - VARHDRSZ) <= 0) ||
+ (set == (text *) NULL) ||
+ ((VARSIZE(set) - VARHDRSZ) <= 0))
+ return string;
+
+ ptr = VARDATA(string);
+ ptr2 = VARDATA(set);
+ end2 = VARDATA(set) + VARSIZE(set) - VARHDRSZ - 1;
+
+ while (m--)
+ {
+ while (ptr2 <= end2)
+ {
+ if (*ptr == *ptr2)
+ {
+ break;
+ }
+ ++ptr2;
+ }
+ if (*ptr != *ptr2)
+ {
+ break;
+ }
+ ptr++;
+ ptr2 = VARDATA(set);
+ }
+
+ ++m;
+
+ end = VARDATA(string) + VARSIZE(string) - VARHDRSZ - 1;
+ ptr2 = VARDATA(set);
+
+ while (m--)
+ {
+ while (ptr2 <= end2)
+ {
+ if (*end == *ptr2)
+ {
+ break;
+ }
+ ++ptr2;
+ }
+ if (*end != *ptr2)
+ {
+ break;
+ }
+ --end;
+ ptr2 = VARDATA(set);
+ }
+
+ ++m;
+
+ ret = (text *) palloc(VARHDRSZ + m);
+ VARSIZE(ret) = VARHDRSZ + m;
+ memcpy(VARDATA(ret), ptr, m);
+
+ return ret;
+} /* btrim() */
/********************************************************************
@@ -328,54 +358,60 @@ btrim(text *string, text *set)
*
* Syntax:
*
- * text *ltrim(text *string, text *set)
+ * text *ltrim(text *string, text *set)
*
* Purpose:
*
- * Returns string with initial characters removed up to the first
- * character not in set.
+ * Returns string with initial characters removed up to the first
+ * character not in set.
*
********************************************************************/
-text *
-ltrim(text *string, text *set)
+text *
+ltrim(text * string, text * set)
{
- text *ret;
- char *ptr, *ptr2, *end2;
- int m;
-
- if ((string == (text *)NULL) ||
- ((m = VARSIZE(string) - VARHDRSZ) <= 0) ||
- (set == (text *)NULL) ||
- ((VARSIZE(set) - VARHDRSZ) <= 0))
- return string;
-
- ptr = VARDATA(string);
- ptr2 = VARDATA(set);
- end2 = VARDATA(set) + VARSIZE(set) - VARHDRSZ - 1;
-
- while (m--) {
- while (ptr2 <= end2) {
- if (*ptr == *ptr2) {
- break;
- }
- ++ptr2;
- }
- if (*ptr != *ptr2) {
- break;
- }
- ptr++;
- ptr2 = VARDATA(set);
- }
-
- ++m;
-
- ret = (text *)palloc(VARHDRSZ + m);
- VARSIZE(ret) = VARHDRSZ + m;
-
- memcpy(VARDATA(ret),ptr,m);
-
- return ret;
+ text *ret;
+ char *ptr,
+ *ptr2,
+ *end2;
+ int m;
+
+ if ((string == (text *) NULL) ||
+ ((m = VARSIZE(string) - VARHDRSZ) <= 0) ||
+ (set == (text *) NULL) ||
+ ((VARSIZE(set) - VARHDRSZ) <= 0))
+ return string;
+
+ ptr = VARDATA(string);
+ ptr2 = VARDATA(set);
+ end2 = VARDATA(set) + VARSIZE(set) - VARHDRSZ - 1;
+
+ while (m--)
+ {
+ while (ptr2 <= end2)
+ {
+ if (*ptr == *ptr2)
+ {
+ break;
+ }
+ ++ptr2;
+ }
+ if (*ptr != *ptr2)
+ {
+ break;
+ }
+ ptr++;
+ ptr2 = VARDATA(set);
+ }
+
+ ++m;
+
+ ret = (text *) palloc(VARHDRSZ + m);
+ VARSIZE(ret) = VARHDRSZ + m;
+
+ memcpy(VARDATA(ret), ptr, m);
+
+ return ret;
}
@@ -385,61 +421,69 @@ ltrim(text *string, text *set)
*
* Syntax:
*
- * text *rtrim(text *string, text *set)
+ * text *rtrim(text *string, text *set)
*
* Purpose:
*
- * Returns string with final characters removed after the last
- * character not in set.
+ * Returns string with final characters removed after the last
+ * character not in set.
*
********************************************************************/
-text *
-rtrim(text *string, text *set)
+text *
+rtrim(text * string, text * set)
{
- text *ret;
- char *ptr, *ptr2, *end2, *ptr_ret;
- int m;
-
- if ((string == (text *)NULL) ||
- ((m = VARSIZE(string) - VARHDRSZ) <= 0) ||
- (set == (text *)NULL) ||
- ((VARSIZE(set) - VARHDRSZ) <= 0))
- return string;
-
- ptr = VARDATA(string) + VARSIZE(string) - VARHDRSZ - 1;
- ptr2 = VARDATA(set);
- end2 = VARDATA(set) + VARSIZE(set) - VARHDRSZ - 1;
-
- while (m--) {
- while (ptr2 <= end2) {
- if (*ptr == *ptr2) {
- break;
- }
- ++ptr2;
- }
- if (*ptr != *ptr2) {
- break;
- }
- --ptr;
- ptr2 = VARDATA(set);
- }
-
- ++m;
-
- ret = (text *)palloc(VARHDRSZ + m);
- VARSIZE(ret) = VARHDRSZ + m;
+ text *ret;
+ char *ptr,
+ *ptr2,
+ *end2,
+ *ptr_ret;
+ int m;
+
+ if ((string == (text *) NULL) ||
+ ((m = VARSIZE(string) - VARHDRSZ) <= 0) ||
+ (set == (text *) NULL) ||
+ ((VARSIZE(set) - VARHDRSZ) <= 0))
+ return string;
+
+ ptr = VARDATA(string) + VARSIZE(string) - VARHDRSZ - 1;
+ ptr2 = VARDATA(set);
+ end2 = VARDATA(set) + VARSIZE(set) - VARHDRSZ - 1;
+
+ while (m--)
+ {
+ while (ptr2 <= end2)
+ {
+ if (*ptr == *ptr2)
+ {
+ break;
+ }
+ ++ptr2;
+ }
+ if (*ptr != *ptr2)
+ {
+ break;
+ }
+ --ptr;
+ ptr2 = VARDATA(set);
+ }
+
+ ++m;
+
+ ret = (text *) palloc(VARHDRSZ + m);
+ VARSIZE(ret) = VARHDRSZ + m;
#if FALSE
- memcpy(VARDATA(ret),ptr-VARSIZE(ret)+m,m);
+ memcpy(VARDATA(ret), ptr - VARSIZE(ret) + m, m);
#endif
- ptr_ret = VARDATA(ret) + m - 1;
+ ptr_ret = VARDATA(ret) + m - 1;
- while (m--) {
- *ptr_ret-- = *ptr--;
- }
+ while (m--)
+ {
+ *ptr_ret-- = *ptr--;
+ }
- return ret;
+ return ret;
}
@@ -449,40 +493,42 @@ rtrim(text *string, text *set)
*
* Syntax:
*
- * text *substr(text *string, int4 m, int4 n)
+ * text *substr(text *string, int4 m, int4 n)
*
* Purpose:
*
- * Returns a portion of string, beginning at character m, n
- * characters long. The first position of string is 1.
+ * Returns a portion of string, beginning at character m, n
+ * characters long. The first position of string is 1.
*
********************************************************************/
-text *
-substr(text *string, int4 m, int4 n)
+text *
+substr(text * string, int4 m, int4 n)
{
- text *ret;
- char *ptr, *ptr_ret;
- int len;
+ text *ret;
+ char *ptr,
+ *ptr_ret;
+ int len;
- if ((string == (text *)NULL) ||
- (m <= 0) || (n <= 0) ||
- ((len = VARSIZE(string) - VARHDRSZ - m) <= 0))
- return string;
+ if ((string == (text *) NULL) ||
+ (m <= 0) || (n <= 0) ||
+ ((len = VARSIZE(string) - VARHDRSZ - m) <= 0))
+ return string;
- len = len + 1 < n ? len + 1 : n;
+ len = len + 1 < n ? len + 1 : n;
- ret = (text *)palloc(VARHDRSZ + len);
- VARSIZE(ret) = VARHDRSZ + len;
+ ret = (text *) palloc(VARHDRSZ + len);
+ VARSIZE(ret) = VARHDRSZ + len;
- ptr = VARDATA(string) + m - 1;
- ptr_ret = VARDATA(ret);
+ ptr = VARDATA(string) + m - 1;
+ ptr_ret = VARDATA(ret);
- while (len--) {
- *ptr_ret++ = *ptr++;
- }
+ while (len--)
+ {
+ *ptr_ret++ = *ptr++;
+ }
- return ret;
+ return ret;
}
@@ -492,39 +538,41 @@ substr(text *string, int4 m, int4 n)
*
* Syntax:
*
- * text *translate(text *string, char from, char to)
+ * text *translate(text *string, char from, char to)
*
* Purpose:
*
- * Returns string after replacing all occurences of from with
- * the corresponding character in to. TRANSLATE will not remove
- * characters.
+ * Returns string after replacing all occurences of from with
+ * the corresponding character in to. TRANSLATE will not remove
+ * characters.
*
********************************************************************/
-text *
-translate(text *string, char from, char to)
+text *
+translate(text * string, char from, char to)
{
- text *ret;
- char *ptr, *ptr_ret;
- int m;
+ text *ret;
+ char *ptr,
+ *ptr_ret;
+ int m;
- if ((string == (text *)NULL) ||
- ((m = VARSIZE(string) - VARHDRSZ) <= 0))
- return string;
+ if ((string == (text *) NULL) ||
+ ((m = VARSIZE(string) - VARHDRSZ) <= 0))
+ return string;
- ret = (text *)palloc(VARSIZE(string));
- VARSIZE(ret) = VARSIZE(string);
+ ret = (text *) palloc(VARSIZE(string));
+ VARSIZE(ret) = VARSIZE(string);
- ptr = VARDATA(string);
- ptr_ret = VARDATA(ret);
+ ptr = VARDATA(string);
+ ptr_ret = VARDATA(ret);
- while (m--) {
- *ptr_ret++ = *ptr == from ? to : *ptr;
- ptr++;
- }
+ while (m--)
+ {
+ *ptr_ret++ = *ptr == from ? to : *ptr;
+ ptr++;
+ }
- return ret;
+ return ret;
}
diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c
index a0d61b8304c..e7d982785ba 100644
--- a/src/backend/utils/adt/regexp.c
+++ b/src/backend/utils/adt/regexp.c
@@ -1,42 +1,42 @@
/*-------------------------------------------------------------------------
*
* regexp.c--
- * regular expression handling code.
+ * regular expression handling code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.7 1997/08/12 22:54:36 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.8 1997/09/07 04:50:39 momjian Exp $
*
- * Alistair Crooks added the code for the regex caching
- * agc - cached the regular expressions used - there's a good chance
- * that we'll get a hit, so this saves a compile step for every
- * attempted match. I haven't actually measured the speed improvement,
- * but it `looks' a lot quicker visually when watching regression
- * test output.
+ * Alistair Crooks added the code for the regex caching
+ * agc - cached the regular expressions used - there's a good chance
+ * that we'll get a hit, so this saves a compile step for every
+ * attempted match. I haven't actually measured the speed improvement,
+ * but it `looks' a lot quicker visually when watching regression
+ * test output.
*
- * agc - incorporated Keith Bostic's Berkeley regex code into
- * the tree for all ports. To distinguish this regex code from any that
- * is existent on a platform, I've prepended the string "pg95_" to
- * the functions regcomp, regerror, regexec and regfree.
- * Fixed a bug that was originally a typo by me, where `i' was used
- * instead of `oldest' when compiling regular expressions - benign
- * results mostly, although occasionally it bit you...
+ * agc - incorporated Keith Bostic's Berkeley regex code into
+ * the tree for all ports. To distinguish this regex code from any that
+ * is existent on a platform, I've prepended the string "pg95_" to
+ * the functions regcomp, regerror, regexec and regfree.
+ * Fixed a bug that was originally a typo by me, where `i' was used
+ * instead of `oldest' when compiling regular expressions - benign
+ * results mostly, although occasionally it bit you...
*
*
*-------------------------------------------------------------------------
*/
#include <string.h>
-#include "postgres.h" /* postgres system include file */
+#include "postgres.h" /* postgres system include file */
#include <regex/regex.h>
-#include "utils/builtins.h" /* where the function declarations go */
+#include "utils/builtins.h" /* where the function declarations go */
#if defined(DISABLE_XOPEN_NLS)
#undef _XOPEN_SOURCE
-#endif /* DISABLE_XOPEN_NLS */
+#endif /* DISABLE_XOPEN_NLS */
/* this is the number of cached regular expressions held. */
#ifndef MAX_CACHED_RES
@@ -44,297 +44,329 @@
#endif
/* this structure describes a cached regular expression */
-struct cached_re_str {
- struct varlena *cre_text; /* pattern as a text* */
- char *cre_s; /* pattern as null-terminated string */
- int cre_type; /* compiled-type: extended,icase etc */
- regex_t cre_re; /* the compiled regular expression */
+struct cached_re_str
+{
+ struct varlena *cre_text; /* pattern as a text* */
+ char *cre_s; /* pattern as null-terminated string */
+ int cre_type; /* compiled-type: extended,icase etc */
+ regex_t cre_re; /* the compiled regular expression */
unsigned long cre_lru; /* lru tag */
};
-static int rec = 0; /* # of cached re's */
-static struct cached_re_str rev[MAX_CACHED_RES]; /* cached re's */
-static unsigned long lru; /* system lru tag */
+static int rec = 0; /* # of cached re's */
+static struct cached_re_str rev[MAX_CACHED_RES]; /* cached re's */
+static unsigned long lru; /* system lru tag */
/* attempt to compile `re' as an re, then match it against text */
/* cflags - flag to regcomp indicates case sensitivity */
static int
-RE_compile_and_execute(struct varlena *text_re, char *text, int cflags)
+RE_compile_and_execute(struct varlena * text_re, char *text, int cflags)
{
- int oldest;
- int n;
- int i;
- char *re;
- int regcomp_result;
-
- re = textout(text_re);
- /* find a previously compiled regular expression */
- for (i = 0 ; i < rec ; i++) {
- if (rev[i].cre_s) {
- if (strcmp(rev[i].cre_s, re) == 0) {
- if (rev[i].cre_type == cflags) {
- rev[i].cre_lru = ++lru;
- pfree(re);
- return(pg95_regexec(&rev[i].cre_re,
- text, 0,
- (regmatch_t *) NULL, 0) == 0);
- }
+ int oldest;
+ int n;
+ int i;
+ char *re;
+ int regcomp_result;
+
+ re = textout(text_re);
+ /* find a previously compiled regular expression */
+ for (i = 0; i < rec; i++)
+ {
+ if (rev[i].cre_s)
+ {
+ if (strcmp(rev[i].cre_s, re) == 0)
+ {
+ if (rev[i].cre_type == cflags)
+ {
+ rev[i].cre_lru = ++lru;
+ pfree(re);
+ return (pg95_regexec(&rev[i].cre_re,
+ text, 0,
+ (regmatch_t *) NULL, 0) == 0);
+ }
+ }
}
- }
- }
-
+ }
+
/* we didn't find it - make room in the cache for it */
- if (rec == MAX_CACHED_RES) {
+ if (rec == MAX_CACHED_RES)
+ {
/* cache is full - find the oldest entry */
- for (oldest = 0, i = 1 ; i < rec ; i++) {
- if (rev[i].cre_lru < rev[oldest].cre_lru) {
+ for (oldest = 0, i = 1; i < rec; i++)
+ {
+ if (rev[i].cre_lru < rev[oldest].cre_lru)
+ {
oldest = i;
}
}
- } else {
+ }
+ else
+ {
oldest = rec++;
}
/* if there was an old re, then de-allocate the space it used */
- if (rev[oldest].cre_s != (char *) NULL) {
- for (lru = i = 0 ; i < rec ; i++) {
+ if (rev[oldest].cre_s != (char *) NULL)
+ {
+ for (lru = i = 0; i < rec; i++)
+ {
rev[i].cre_lru =
(rev[i].cre_lru - rev[oldest].cre_lru) / 2;
- if (rev[i].cre_lru > lru) {
+ if (rev[i].cre_lru > lru)
+ {
lru = rev[i].cre_lru;
}
- }
+ }
pg95_regfree(&rev[oldest].cre_re);
- /* use malloc/free for the cre_s field because the storage
- has to persist across transactions */
- free(rev[oldest].cre_s);
+
+ /*
+ * use malloc/free for the cre_s field because the storage has to
+ * persist across transactions
+ */
+ free(rev[oldest].cre_s);
}
/* compile the re */
regcomp_result = pg95_regcomp(&rev[oldest].cre_re, re, cflags);
- if ( regcomp_result == 0) {
+ if (regcomp_result == 0)
+ {
n = strlen(re);
- /* use malloc/free for the cre_s field because the storage
- has to persist across transactions */
+
+ /*
+ * use malloc/free for the cre_s field because the storage has to
+ * persist across transactions
+ */
rev[oldest].cre_s = (char *) malloc(n + 1);
memmove(rev[oldest].cre_s, re, n);
rev[oldest].cre_s[n] = 0;
- rev[oldest].cre_text = text_re;
+ rev[oldest].cre_text = text_re;
rev[oldest].cre_lru = ++lru;
- rev[oldest].cre_type = cflags;
+ rev[oldest].cre_type = cflags;
pfree(re);
- /* agc - fixed an old typo here */
- return(pg95_regexec(&rev[oldest].cre_re, text, 0,
- (regmatch_t *) NULL, 0) == 0);
- } else {
- char errMsg[1000];
- /* re didn't compile */
- rev[oldest].cre_s = (char *) NULL;
- pg95_regerror(regcomp_result, &rev[oldest].cre_re, errMsg,
- sizeof(errMsg));
- elog(WARN,"regcomp failed with error %s",errMsg);
+ /* agc - fixed an old typo here */
+ return (pg95_regexec(&rev[oldest].cre_re, text, 0,
+ (regmatch_t *) NULL, 0) == 0);
+ }
+ else
+ {
+ char errMsg[1000];
+
+ /* re didn't compile */
+ rev[oldest].cre_s = (char *) NULL;
+ pg95_regerror(regcomp_result, &rev[oldest].cre_re, errMsg,
+ sizeof(errMsg));
+ elog(WARN, "regcomp failed with error %s", errMsg);
}
/* not reached */
- return(0);
+ return (0);
}
/*
- * interface routines called by the function manager
+ * interface routines called by the function manager
*/
/*
fixedlen_regexeq:
a generic fixed length regexp routine
- s - the string to match against (not necessarily null-terminated)
- p - the pattern
- charlen - the length of the string
+ s - the string to match against (not necessarily null-terminated)
+ p - the pattern
+ charlen - the length of the string
*/
-static bool
-fixedlen_regexeq(char *s, struct varlena* p, int charlen, int cflags)
+static bool
+fixedlen_regexeq(char *s, struct varlena * p, int charlen, int cflags)
{
- char *sterm;
- int result;
-
- if (!s || !p)
- return FALSE;
-
- /* be sure sterm is null-terminated */
- sterm = (char *) palloc(charlen + 1);
- strNcpy(sterm, s, charlen);
-
- result = RE_compile_and_execute(p, sterm, cflags);
-
- pfree(sterm);
-
- return ((bool) result);
+ char *sterm;
+ int result;
+
+ if (!s || !p)
+ return FALSE;
+
+ /* be sure sterm is null-terminated */
+ sterm = (char *) palloc(charlen + 1);
+ strNcpy(sterm, s, charlen);
+
+ result = RE_compile_and_execute(p, sterm, cflags);
+
+ pfree(sterm);
+
+ return ((bool) result);
}
/*
- * routines that use the regexp stuff
+ * routines that use the regexp stuff
*/
-bool
-char2regexeq(uint16 arg1, struct varlena *p)
+bool
+char2regexeq(uint16 arg1, struct varlena * p)
{
- char *s = (char *) &arg1;
- return (fixedlen_regexeq(s, p, 2, REG_EXTENDED));
+ char *s = (char *) &arg1;
+
+ return (fixedlen_regexeq(s, p, 2, REG_EXTENDED));
}
-bool
-char2regexne(uint16 arg1, struct varlena *p)
+bool
+char2regexne(uint16 arg1, struct varlena * p)
{
- return (!char2regexeq(arg1, p));
+ return (!char2regexeq(arg1, p));
}
-bool
-char4regexeq(uint32 arg1, struct varlena *p)
+bool
+char4regexeq(uint32 arg1, struct varlena * p)
{
- char *s = (char *) &arg1;
- return (fixedlen_regexeq(s, p, 4, REG_EXTENDED));
+ char *s = (char *) &arg1;
+
+ return (fixedlen_regexeq(s, p, 4, REG_EXTENDED));
}
-bool
-char4regexne(uint32 arg1, struct varlena *p)
+bool
+char4regexne(uint32 arg1, struct varlena * p)
{
- return (!char4regexeq(arg1, p));
+ return (!char4regexeq(arg1, p));
}
-bool
-char8regexeq(char *s, struct varlena *p)
+bool
+char8regexeq(char *s, struct varlena * p)
{
- return (fixedlen_regexeq(s, p, 8, REG_EXTENDED));
+ return (fixedlen_regexeq(s, p, 8, REG_EXTENDED));
}
-bool
-char8regexne(char *s, struct varlena *p)
+bool
+char8regexne(char *s, struct varlena * p)
{
- return (!char8regexeq(s, p));
+ return (!char8regexeq(s, p));
}
-bool
-char16regexeq(char *s, struct varlena *p)
+bool
+char16regexeq(char *s, struct varlena * p)
{
- return (fixedlen_regexeq(s, p, 16, REG_EXTENDED));
+ return (fixedlen_regexeq(s, p, 16, REG_EXTENDED));
}
-bool
-char16regexne(char *s, struct varlena *p)
+bool
+char16regexne(char *s, struct varlena * p)
{
- return (!char16regexeq(s, p));
+ return (!char16regexeq(s, p));
}
-bool
-nameregexeq(NameData *n, struct varlena *p)
+bool
+nameregexeq(NameData * n, struct varlena * p)
{
- if (!n) return FALSE;
- return (fixedlen_regexeq(n->data, p, NAMEDATALEN, REG_EXTENDED));
+ if (!n)
+ return FALSE;
+ return (fixedlen_regexeq(n->data, p, NAMEDATALEN, REG_EXTENDED));
}
-bool
-nameregexne(NameData *s, struct varlena *p)
+
+bool
+nameregexne(NameData * s, struct varlena * p)
{
- return (!nameregexeq(s, p));
+ return (!nameregexeq(s, p));
}
-bool
-textregexeq(struct varlena *s, struct varlena *p)
+bool
+textregexeq(struct varlena * s, struct varlena * p)
{
- if (!s) return (FALSE);
- return (fixedlen_regexeq(VARDATA(s), p, VARSIZE(s) - VARHDRSZ, REG_EXTENDED));
+ if (!s)
+ return (FALSE);
+ return (fixedlen_regexeq(VARDATA(s), p, VARSIZE(s) - VARHDRSZ, REG_EXTENDED));
}
-bool
-textregexne(struct varlena *s, struct varlena *p)
+bool
+textregexne(struct varlena * s, struct varlena * p)
{
- return (!textregexeq(s, p));
+ return (!textregexeq(s, p));
}
/*
* routines that use the regexp stuff, but ignore the case.
- * for this, we use the REG_ICASE flag to pg95_regcomp
+ * for this, we use the REG_ICASE flag to pg95_regcomp
*/
-bool
-char2icregexeq(uint16 arg1, struct varlena *p)
+bool
+char2icregexeq(uint16 arg1, struct varlena * p)
{
- char *s = (char *) &arg1;
- return (fixedlen_regexeq(s, p, 2, REG_ICASE | REG_EXTENDED));
+ char *s = (char *) &arg1;
+
+ return (fixedlen_regexeq(s, p, 2, REG_ICASE | REG_EXTENDED));
}
-
-bool
-char2icregexne(uint16 arg1, struct varlena *p)
+
+bool
+char2icregexne(uint16 arg1, struct varlena * p)
{
- return (!char2icregexeq(arg1, p));
+ return (!char2icregexeq(arg1, p));
}
-bool
-char4icregexeq(uint32 arg1, struct varlena *p)
+bool
+char4icregexeq(uint32 arg1, struct varlena * p)
{
- char *s = (char *) &arg1;
- return (fixedlen_regexeq(s, p, 4, REG_ICASE | REG_EXTENDED ));
+ char *s = (char *) &arg1;
+
+ return (fixedlen_regexeq(s, p, 4, REG_ICASE | REG_EXTENDED));
}
-bool
-char4icregexne(uint32 arg1, struct varlena *p)
+bool
+char4icregexne(uint32 arg1, struct varlena * p)
{
- return (!char4icregexeq(arg1, p));
+ return (!char4icregexeq(arg1, p));
}
-
-bool
-char8icregexeq(char *s, struct varlena *p)
+
+bool
+char8icregexeq(char *s, struct varlena * p)
{
- return (fixedlen_regexeq(s, p, 8, REG_ICASE | REG_EXTENDED));
+ return (fixedlen_regexeq(s, p, 8, REG_ICASE | REG_EXTENDED));
}
-bool
-char8icregexne(char *s, struct varlena *p)
+bool
+char8icregexne(char *s, struct varlena * p)
{
- return (!char8icregexeq(s, p));
+ return (!char8icregexeq(s, p));
}
-bool
-char16icregexeq(char *s, struct varlena *p)
+bool
+char16icregexeq(char *s, struct varlena * p)
{
- return (fixedlen_regexeq(s, p, 16, REG_ICASE | REG_EXTENDED));
+ return (fixedlen_regexeq(s, p, 16, REG_ICASE | REG_EXTENDED));
}
-bool
-char16icregexne(char *s, struct varlena *p)
+bool
+char16icregexne(char *s, struct varlena * p)
{
- return (!char16icregexeq(s, p));
+ return (!char16icregexeq(s, p));
}
-bool
-texticregexeq(struct varlena *s, struct varlena *p)
+bool
+texticregexeq(struct varlena * s, struct varlena * p)
{
- if (!s) return FALSE;
- return (fixedlen_regexeq(VARDATA(s), p, VARSIZE(s) - VARHDRSZ,
- REG_ICASE | REG_EXTENDED));
+ if (!s)
+ return FALSE;
+ return (fixedlen_regexeq(VARDATA(s), p, VARSIZE(s) - VARHDRSZ,
+ REG_ICASE | REG_EXTENDED));
}
-bool
-texticregexne(struct varlena *s, struct varlena *p)
+bool
+texticregexne(struct varlena * s, struct varlena * p)
{
- return (!texticregexeq(s, p));
+ return (!texticregexeq(s, p));
}
-bool
-nameicregexeq(NameData *n, struct varlena *p)
+bool
+nameicregexeq(NameData * n, struct varlena * p)
{
- if (!n) return FALSE;
- return (fixedlen_regexeq(n->data, p, NAMEDATALEN,
- REG_ICASE | REG_EXTENDED));
+ if (!n)
+ return FALSE;
+ return (fixedlen_regexeq(n->data, p, NAMEDATALEN,
+ REG_ICASE | REG_EXTENDED));
}
-bool
-nameicregexne(NameData *s, struct varlena *p)
+
+bool
+nameicregexne(NameData * s, struct varlena * p)
{
- return (!nameicregexeq(s, p));
+ return (!nameicregexeq(s, p));
}
-
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index 04442cb42df..6a4e8b01e50 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* regproc.c--
- * Functions for the built-in type "RegProcedure".
+ * Functions for the built-in type "RegProcedure".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.5 1997/08/12 20:16:05 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.6 1997/09/07 04:50:41 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,129 +19,140 @@
#include "utils/palloc.h"
#include "catalog/catname.h"
-#include "utils/builtins.h" /* where function declarations go */
+#include "utils/builtins.h" /* where function declarations go */
-/*****************************************************************************
- * USER I/O ROUTINES *
+/*****************************************************************************
+ * USER I/O ROUTINES *
*****************************************************************************/
/*
- * regprocin - converts "proname" to proid
+ * regprocin - converts "proname" to proid
*
- * proid of NULL signifies unknown
+ * proid of NULL signifies unknown
*/
-int32 regprocin(char *proname)
+int32
+regprocin(char *proname)
{
- Relation proc;
- HeapScanDesc procscan;
- HeapTuple proctup;
- ScanKeyData key;
- RegProcedure result = (Oid)0;
- bool isnull;
-
- if (proname == NULL)
- return(0);
- proc = heap_openr(ProcedureRelationName);
- if (!RelationIsValid(proc)) {
- elog(WARN, "regprocin: could not open %s",
- ProcedureRelationName);
- return(0);
- }
- ScanKeyEntryInitialize(&key,
- (bits16)0,
- (AttrNumber)1,
- (RegProcedure)F_CHAR16EQ,
- (Datum)proname);
-
- procscan = heap_beginscan(proc, 0, NowTimeQual, 1, &key);
- if (!HeapScanIsValid(procscan)) {
- heap_close(proc);
- elog(WARN, "regprocin: could not being scan of %s",
- ProcedureRelationName);
- return(0);
- }
- proctup = heap_getnext(procscan, 0, (Buffer *) NULL);
- switch (HeapTupleIsValid(proctup)) {
- case 1:
- result = (RegProcedure) heap_getattr(proctup,
- InvalidBuffer,
- ObjectIdAttributeNumber,
- RelationGetTupleDescriptor(proc),
- &isnull);
- if (isnull) {
- elog(FATAL, "regprocin: null procedure %s", proname);
+ Relation proc;
+ HeapScanDesc procscan;
+ HeapTuple proctup;
+ ScanKeyData key;
+ RegProcedure result = (Oid) 0;
+ bool isnull;
+
+ if (proname == NULL)
+ return (0);
+ proc = heap_openr(ProcedureRelationName);
+ if (!RelationIsValid(proc))
+ {
+ elog(WARN, "regprocin: could not open %s",
+ ProcedureRelationName);
+ return (0);
+ }
+ ScanKeyEntryInitialize(&key,
+ (bits16) 0,
+ (AttrNumber) 1,
+ (RegProcedure) F_CHAR16EQ,
+ (Datum) proname);
+
+ procscan = heap_beginscan(proc, 0, NowTimeQual, 1, &key);
+ if (!HeapScanIsValid(procscan))
+ {
+ heap_close(proc);
+ elog(WARN, "regprocin: could not being scan of %s",
+ ProcedureRelationName);
+ return (0);
}
- break;
- case 0:
- result = (RegProcedure) 0;
+ proctup = heap_getnext(procscan, 0, (Buffer *) NULL);
+ switch (HeapTupleIsValid(proctup))
+ {
+ case 1:
+ result = (RegProcedure) heap_getattr(proctup,
+ InvalidBuffer,
+ ObjectIdAttributeNumber,
+ RelationGetTupleDescriptor(proc),
+ &isnull);
+ if (isnull)
+ {
+ elog(FATAL, "regprocin: null procedure %s", proname);
+ }
+ break;
+ case 0:
+ result = (RegProcedure) 0;
#ifdef EBUG
- elog(DEBUG, "regprocin: no such procedure %s", proname);
-#endif /* defined(EBUG) */
- }
- heap_endscan(procscan);
- heap_close(proc);
- return((int32) result);
+ elog(DEBUG, "regprocin: no such procedure %s", proname);
+#endif /* defined(EBUG) */
+ }
+ heap_endscan(procscan);
+ heap_close(proc);
+ return ((int32) result);
}
/*
- * regprocout - converts proid to "proname"
+ * regprocout - converts proid to "proname"
*/
-char *regprocout(RegProcedure proid)
+char *
+regprocout(RegProcedure proid)
{
- Relation proc;
- HeapScanDesc procscan;
- HeapTuple proctup;
- char *result;
- ScanKeyData key;
-
- result = (char *)palloc(NAMEDATALEN);
- proc = heap_openr(ProcedureRelationName);
- if (!RelationIsValid(proc)) {
- elog(WARN, "regprocout: could not open %s",
- ProcedureRelationName);
- return(0);
- }
- ScanKeyEntryInitialize(&key,
- (bits16)0,
- (AttrNumber)ObjectIdAttributeNumber,
- (RegProcedure)F_INT4EQ,
- (Datum)proid);
-
- procscan = heap_beginscan(proc, 0, NowTimeQual, 1, &key);
- if (!HeapScanIsValid(procscan)) {
- heap_close(proc);
- elog(WARN, "regprocin: could not being scan of %s",
- ProcedureRelationName);
- return(0);
- }
- proctup = heap_getnext(procscan, 0, (Buffer *)NULL);
- switch (HeapTupleIsValid(proctup)) {
- char *s;
- bool isnull;
- case 1:
- s = (char *) heap_getattr(proctup, InvalidBuffer, 1,
- RelationGetTupleDescriptor(proc), &isnull);
- if (!isnull) {
- strNcpy(result, s, 16);
- break;
+ Relation proc;
+ HeapScanDesc procscan;
+ HeapTuple proctup;
+ char *result;
+ ScanKeyData key;
+
+ result = (char *) palloc(NAMEDATALEN);
+ proc = heap_openr(ProcedureRelationName);
+ if (!RelationIsValid(proc))
+ {
+ elog(WARN, "regprocout: could not open %s",
+ ProcedureRelationName);
+ return (0);
+ }
+ ScanKeyEntryInitialize(&key,
+ (bits16) 0,
+ (AttrNumber) ObjectIdAttributeNumber,
+ (RegProcedure) F_INT4EQ,
+ (Datum) proid);
+
+ procscan = heap_beginscan(proc, 0, NowTimeQual, 1, &key);
+ if (!HeapScanIsValid(procscan))
+ {
+ heap_close(proc);
+ elog(WARN, "regprocin: could not being scan of %s",
+ ProcedureRelationName);
+ return (0);
}
- elog(FATAL, "regprocout: null procedure %d", proid);
- /*FALLTHROUGH*/
- case 0:
- result[0] = '-';
- result[1] = '\0';
+ proctup = heap_getnext(procscan, 0, (Buffer *) NULL);
+ switch (HeapTupleIsValid(proctup))
+ {
+ char *s;
+ bool isnull;
+
+ case 1:
+ s = (char *) heap_getattr(proctup, InvalidBuffer, 1,
+ RelationGetTupleDescriptor(proc), &isnull);
+ if (!isnull)
+ {
+ strNcpy(result, s, 16);
+ break;
+ }
+ elog(FATAL, "regprocout: null procedure %d", proid);
+ /* FALLTHROUGH */
+ case 0:
+ result[0] = '-';
+ result[1] = '\0';
#ifdef EBUG
- elog(DEBUG, "regprocout: no such procedure %d", proid);
-#endif /* defined(EBUG) */
- }
- heap_endscan(procscan);
- heap_close(proc);
- return(result);
+ elog(DEBUG, "regprocout: no such procedure %d", proid);
+#endif /* defined(EBUG) */
+ }
+ heap_endscan(procscan);
+ heap_close(proc);
+ return (result);
}
-/*****************************************************************************
- * PUBLIC ROUTINES *
+/*****************************************************************************
+ * PUBLIC ROUTINES *
*****************************************************************************/
/* regproctooid()
@@ -149,13 +160,13 @@ char *regprocout(RegProcedure proid)
* Define RegprocToOid() as a macro in builtins.h.
* Referenced in pg_proc.h. - tgl 97/04/26
*/
-Oid regproctooid(RegProcedure rp)
+Oid
+regproctooid(RegProcedure rp)
{
- return (Oid)rp;
+ return (Oid) rp;
}
/* (see int.c for comparison/operation routines) */
/* ========== PRIVATE ROUTINES ========== */
-
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index fe90feda72d..3f8c225ca9e 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* selfuncs.c--
- * Selectivity functions for system catalogs and builtin types
+ * Selectivity functions for system catalogs and builtin types
*
- * These routines are registered in the operator catalog in the
- * "oprrest" and "oprjoin" attributes.
+ * These routines are registered in the operator catalog in the
+ * "oprrest" and "oprjoin" attributes.
*
- * XXX check all the functions--I suspect them to be 1-based.
+ * XXX check all the functions--I suspect them to be 1-based.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.8 1997/08/21 03:02:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.9 1997/09/07 04:50:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -22,10 +22,10 @@
#include "postgres.h"
#include "access/heapam.h"
-#include "utils/tqual.h" /* for NowTimeQual */
+#include "utils/tqual.h" /* for NowTimeQual */
#include "fmgr.h"
-#include "utils/builtins.h" /* for textout() prototype
- and where the declarations go */
+#include "utils/builtins.h" /* for textout() prototype and where the
+ * declarations go */
#include "utils/palloc.h"
#include "catalog/catname.h"
@@ -34,580 +34,624 @@
#include "catalog/pg_statistic.h"
/* N is not a valid var/constant or relation id */
-#define NONVALUE(N) ((N) == -1)
+#define NONVALUE(N) ((N) == -1)
-/*
+/*
* generalize the test for functional index selectivity request
*/
#define FunctionalSelectivity(nIndKeys,attNum) (attNum==InvalidAttrNumber)
static float32data getattdisbursion(Oid relid, AttrNumber attnum);
-static void gethilokey(Oid relid, AttrNumber attnum, Oid opid,
- char **high, char **low);
+static void
+gethilokey(Oid relid, AttrNumber attnum, Oid opid,
+ char **high, char **low);
/*
- * eqsel - Selectivity of "=" for any data type.
+ * eqsel - Selectivity of "=" for any data type.
*/
float64
eqsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- char *value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ char *value,
+ int32 flag)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- if (NONVALUE(attno) || NONVALUE(relid))
- *result = 0.1;
- else
- *result = (float64data)getattdisbursion(relid, (int) attno);
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ if (NONVALUE(attno) || NONVALUE(relid))
+ *result = 0.1;
+ else
+ *result = (float64data) getattdisbursion(relid, (int) attno);
+ return (result);
}
/*
- * neqsel - Selectivity of "!=" for any data type.
+ * neqsel - Selectivity of "!=" for any data type.
*/
float64
neqsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- char *value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ char *value,
+ int32 flag)
{
- float64 result;
-
- result = eqsel(opid, relid, attno, value, flag);
- *result = 1.0 - *result;
- return(result);
+ float64 result;
+
+ result = eqsel(opid, relid, attno, value, flag);
+ *result = 1.0 - *result;
+ return (result);
}
/*
- * intltsel - Selectivity of "<" for integers.
- * Should work for both longs and shorts.
+ * intltsel - Selectivity of "<" for integers.
+ * Should work for both longs and shorts.
*/
float64
intltsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- int32 value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ int32 value,
+ int32 flag)
{
- float64 result;
- char *highchar, *lowchar;
- long val, high, low, top, bottom;
-
- result = (float64) palloc(sizeof(float64data));
- if (NONVALUE(attno) || NONVALUE(relid))
- *result = 1.0 / 3;
- else {
- /* XXX val = atol(value);*/
- val = value;
- gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
- if (*highchar == 'n' || *lowchar == 'n') {
- *result = 1.0/3.0;
- return (result);
- }
- high = atol(highchar);
- low = atol(lowchar);
- if ((flag & SEL_RIGHT && val < low) ||
- (!(flag & SEL_RIGHT) && val > high)) {
- float32data nvals;
- nvals = getattdisbursion(relid, (int) attno);
- if (nvals == 0)
- *result = 1.0 / 3.0;
- else {
- *result = 3.0 * (float64data)nvals;
- if (*result > 1.0)
- *result = 1;
- }
- }else {
- bottom = high - low;
- if (bottom == 0)
- ++bottom;
- if (flag & SEL_RIGHT)
- top = val - low;
- else
- top = high - val;
- if (top > bottom)
- *result = 1.0;
- else {
- if (top == 0)
- ++top;
- *result = ((1.0 * top) / bottom);
- }
+ float64 result;
+ char *highchar,
+ *lowchar;
+ long val,
+ high,
+ low,
+ top,
+ bottom;
+
+ result = (float64) palloc(sizeof(float64data));
+ if (NONVALUE(attno) || NONVALUE(relid))
+ *result = 1.0 / 3;
+ else
+ {
+ /* XXX val = atol(value); */
+ val = value;
+ gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
+ if (*highchar == 'n' || *lowchar == 'n')
+ {
+ *result = 1.0 / 3.0;
+ return (result);
+ }
+ high = atol(highchar);
+ low = atol(lowchar);
+ if ((flag & SEL_RIGHT && val < low) ||
+ (!(flag & SEL_RIGHT) && val > high))
+ {
+ float32data nvals;
+
+ nvals = getattdisbursion(relid, (int) attno);
+ if (nvals == 0)
+ *result = 1.0 / 3.0;
+ else
+ {
+ *result = 3.0 * (float64data) nvals;
+ if (*result > 1.0)
+ *result = 1;
+ }
+ }
+ else
+ {
+ bottom = high - low;
+ if (bottom == 0)
+ ++bottom;
+ if (flag & SEL_RIGHT)
+ top = val - low;
+ else
+ top = high - val;
+ if (top > bottom)
+ *result = 1.0;
+ else
+ {
+ if (top == 0)
+ ++top;
+ *result = ((1.0 * top) / bottom);
+ }
+ }
}
- }
- return(result);
+ return (result);
}
/*
- * intgtsel - Selectivity of ">" for integers.
- * Should work for both longs and shorts.
+ * intgtsel - Selectivity of ">" for integers.
+ * Should work for both longs and shorts.
*/
float64
intgtsel(Oid opid,
- Oid relid,
- AttrNumber attno,
- int32 value,
- int32 flag)
+ Oid relid,
+ AttrNumber attno,
+ int32 value,
+ int32 flag)
{
- float64 result;
- int notflag;
-
- if (flag & 0)
- notflag = flag & ~SEL_RIGHT;
- else
- notflag = flag | SEL_RIGHT;
- result = intltsel(opid, relid, attno, value, (int32) notflag);
- return(result);
+ float64 result;
+ int notflag;
+
+ if (flag & 0)
+ notflag = flag & ~SEL_RIGHT;
+ else
+ notflag = flag | SEL_RIGHT;
+ result = intltsel(opid, relid, attno, value, (int32) notflag);
+ return (result);
}
/*
- * eqjoinsel - Join selectivity of "="
+ * eqjoinsel - Join selectivity of "="
*/
float64
eqjoinsel(Oid opid,
- Oid relid1,
- AttrNumber attno1,
- Oid relid2,
- AttrNumber attno2)
+ Oid relid1,
+ AttrNumber attno1,
+ Oid relid2,
+ AttrNumber attno2)
{
- float64 result;
- float32data num1, num2, max;
-
- result = (float64) palloc(sizeof(float64data));
- if (NONVALUE(attno1) || NONVALUE(relid1) ||
- NONVALUE(attno2) || NONVALUE(relid2))
- *result = 0.1;
- else {
- num1 = getattdisbursion(relid1, (int) attno1);
- num2 = getattdisbursion(relid2, (int) attno2);
- max = (num1 > num2) ? num1 : num2;
- if (max == 0)
- *result = 1.0;
+ float64 result;
+ float32data num1,
+ num2,
+ max;
+
+ result = (float64) palloc(sizeof(float64data));
+ if (NONVALUE(attno1) || NONVALUE(relid1) ||
+ NONVALUE(attno2) || NONVALUE(relid2))
+ *result = 0.1;
else
- *result = (float64data)max;
- }
- return(result);
+ {
+ num1 = getattdisbursion(relid1, (int) attno1);
+ num2 = getattdisbursion(relid2, (int) attno2);
+ max = (num1 > num2) ? num1 : num2;
+ if (max == 0)
+ *result = 1.0;
+ else
+ *result = (float64data) max;
+ }
+ return (result);
}
/*
- * neqjoinsel - Join selectivity of "!="
+ * neqjoinsel - Join selectivity of "!="
*/
float64
neqjoinsel(Oid opid,
- Oid relid1,
- AttrNumber attno1,
- Oid relid2,
- AttrNumber attno2)
+ Oid relid1,
+ AttrNumber attno1,
+ Oid relid2,
+ AttrNumber attno2)
{
- float64 result;
-
- result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
- *result = 1.0 - *result;
- return(result);
+ float64 result;
+
+ result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
+ *result = 1.0 - *result;
+ return (result);
}
/*
- * intltjoinsel - Join selectivity of "<"
+ * intltjoinsel - Join selectivity of "<"
*/
float64
intltjoinsel(Oid opid,
- Oid relid1,
- AttrNumber attno1,
- Oid relid2,
- AttrNumber attno2)
+ Oid relid1,
+ AttrNumber attno1,
+ Oid relid2,
+ AttrNumber attno2)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 3.0;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ *result = 1.0 / 3.0;
+ return (result);
}
/*
- * intgtjoinsel - Join selectivity of ">"
+ * intgtjoinsel - Join selectivity of ">"
*/
float64
intgtjoinsel(Oid opid,
- Oid relid1,
- AttrNumber attno1,
- Oid relid2,
- AttrNumber attno2)
+ Oid relid1,
+ AttrNumber attno1,
+ Oid relid2,
+ AttrNumber attno2)
{
- float64 result;
-
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 3.0;
- return(result);
+ float64 result;
+
+ result = (float64) palloc(sizeof(float64data));
+ *result = 1.0 / 3.0;
+ return (result);
}
/*
- * getattdisbursion - Retrieves the number of values within an attribute.
+ * getattdisbursion - Retrieves the number of values within an attribute.
*
- * Note:
- * getattdisbursion and gethilokey both currently use keyed
- * relation scans and amgetattr. Alternatively,
- * the relation scan could be non-keyed and the tuple
- * returned could be cast (struct X *) tuple + tuple->t_hoff.
- * The first method is good for testing the implementation,
- * but the second may ultimately be faster?!? In any case,
- * using the cast instead of amgetattr would be
- * more efficient. However, the cast will not work
- * for gethilokey which accesses stahikey in struct statistic.
+ * Note:
+ * getattdisbursion and gethilokey both currently use keyed
+ * relation scans and amgetattr. Alternatively,
+ * the relation scan could be non-keyed and the tuple
+ * returned could be cast (struct X *) tuple + tuple->t_hoff.
+ * The first method is good for testing the implementation,
+ * but the second may ultimately be faster?!? In any case,
+ * using the cast instead of amgetattr would be
+ * more efficient. However, the cast will not work
+ * for gethilokey which accesses stahikey in struct statistic.
*/
-static float32data
+static float32data
getattdisbursion(Oid relid, AttrNumber attnum)
{
- HeapTuple atp;
- float32data nvals;
- int32 ntuples;
-
- atp = SearchSysCacheTuple(ATTNUM,
- ObjectIdGetDatum(relid),
- Int16GetDatum(attnum),
- 0,0);
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "getattdisbursion: no attribute tuple %d %d",
- relid, attnum);
- return(0);
- }
- nvals = ((AttributeTupleForm ) GETSTRUCT(atp))->attdisbursion;
- if (nvals > 0) return(nvals);
-
- atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(relid),
- 0,0,0);
- /* XXX -- use number of tuples as number of distinctive values
- just for now, in case number of distinctive values is
- not cached */
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "getattdisbursion: no relation tuple %d", relid);
- return(0);
- }
- ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
- /* Look above how nvals is used. - vadim 04/09/97 */
- if ( ntuples > 0 )
- nvals = 1.0 / ntuples;
-
- return(nvals);
+ HeapTuple atp;
+ float32data nvals;
+ int32 ntuples;
+
+ atp = SearchSysCacheTuple(ATTNUM,
+ ObjectIdGetDatum(relid),
+ Int16GetDatum(attnum),
+ 0, 0);
+ if (!HeapTupleIsValid(atp))
+ {
+ elog(WARN, "getattdisbursion: no attribute tuple %d %d",
+ relid, attnum);
+ return (0);
+ }
+ nvals = ((AttributeTupleForm) GETSTRUCT(atp))->attdisbursion;
+ if (nvals > 0)
+ return (nvals);
+
+ atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(relid),
+ 0, 0, 0);
+
+ /*
+ * XXX -- use number of tuples as number of distinctive values just
+ * for now, in case number of distinctive values is not cached
+ */
+ if (!HeapTupleIsValid(atp))
+ {
+ elog(WARN, "getattdisbursion: no relation tuple %d", relid);
+ return (0);
+ }
+ ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
+ /* Look above how nvals is used. - vadim 04/09/97 */
+ if (ntuples > 0)
+ nvals = 1.0 / ntuples;
+
+ return (nvals);
}
/*
- * gethilokey - Returns a pointer to strings containing
- * the high and low keys within an attribute.
+ * gethilokey - Returns a pointer to strings containing
+ * the high and low keys within an attribute.
*
- * Currently returns "0", and "0" in high and low if the statistic
- * catalog does not contain the proper tuple. Eventually, the
- * statistic demon should have the tuple maintained, and it should
- * elog() if the tuple is missing.
+ * Currently returns "0", and "0" in high and low if the statistic
+ * catalog does not contain the proper tuple. Eventually, the
+ * statistic demon should have the tuple maintained, and it should
+ * elog() if the tuple is missing.
*
- * XXX Question: is this worth sticking in the catalog caches,
- * or will this get invalidated too often?
+ * XXX Question: is this worth sticking in the catalog caches,
+ * or will this get invalidated too often?
*/
static void
gethilokey(Oid relid,
- AttrNumber attnum,
- Oid opid,
- char **high,
- char **low)
+ AttrNumber attnum,
+ Oid opid,
+ char **high,
+ char **low)
{
- register Relation rdesc;
- register HeapScanDesc sdesc;
- static ScanKeyData key[3] = {
- { 0, Anum_pg_statistic_starelid, F_OIDEQ },
- { 0, Anum_pg_statistic_staattnum, F_INT2EQ },
- { 0, Anum_pg_statistic_staop, F_OIDEQ }
- };
- bool isnull;
- HeapTuple tuple;
-
- rdesc = heap_openr(StatisticRelationName);
-
- key[0].sk_argument = ObjectIdGetDatum(relid);
- key[1].sk_argument = Int16GetDatum((int16) attnum);
- key[2].sk_argument = ObjectIdGetDatum(opid);
- sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 3, key);
- tuple = heap_getnext(sdesc, 0, (Buffer *) NULL);
- if (!HeapTupleIsValid(tuple)) {
- *high = "n";
- *low = "n";
- /* XXX elog(WARN, "gethilokey: statistic tuple not found");*/
- return;
- }
- *high = textout((struct varlena *)
- heap_getattr(tuple,
- InvalidBuffer,
- Anum_pg_statistic_stahikey,
- RelationGetTupleDescriptor(rdesc),
- &isnull));
- if (isnull)
- elog(DEBUG, "gethilokey: high key is null");
- *low = textout((struct varlena *)
- heap_getattr(tuple,
- InvalidBuffer,
- Anum_pg_statistic_stalokey,
- RelationGetTupleDescriptor(rdesc),
- &isnull));
- if (isnull)
- elog(DEBUG, "gethilokey: low key is null");
- heap_endscan(sdesc);
- heap_close(rdesc);
+ register Relation rdesc;
+ register HeapScanDesc sdesc;
+ static ScanKeyData key[3] = {
+ {0, Anum_pg_statistic_starelid, F_OIDEQ},
+ {0, Anum_pg_statistic_staattnum, F_INT2EQ},
+ {0, Anum_pg_statistic_staop, F_OIDEQ}
+ };
+ bool isnull;
+ HeapTuple tuple;
+
+ rdesc = heap_openr(StatisticRelationName);
+
+ key[0].sk_argument = ObjectIdGetDatum(relid);
+ key[1].sk_argument = Int16GetDatum((int16) attnum);
+ key[2].sk_argument = ObjectIdGetDatum(opid);
+ sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 3, key);
+ tuple = heap_getnext(sdesc, 0, (Buffer *) NULL);
+ if (!HeapTupleIsValid(tuple))
+ {
+ *high = "n";
+ *low = "n";
+
+ /*
+ * XXX elog(WARN, "gethilokey: statistic tuple not
+ * found");
+ */
+ return;
+ }
+ *high = textout((struct varlena *)
+ heap_getattr(tuple,
+ InvalidBuffer,
+ Anum_pg_statistic_stahikey,
+ RelationGetTupleDescriptor(rdesc),
+ &isnull));
+ if (isnull)
+ elog(DEBUG, "gethilokey: high key is null");
+ *low = textout((struct varlena *)
+ heap_getattr(tuple,
+ InvalidBuffer,
+ Anum_pg_statistic_stalokey,
+ RelationGetTupleDescriptor(rdesc),
+ &isnull));
+ if (isnull)
+ elog(DEBUG, "gethilokey: low key is null");
+ heap_endscan(sdesc);
+ heap_close(rdesc);
}
float64
btreesel(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+ Oid indrelid,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag,
+ int32 nIndexKeys,
+ Oid indexrelid)
{
- float64 result;
- float64data resultData;
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
- /*
- * Need to call the functions selectivity
- * function here. For now simply assume it's
- * 1/3 since functions don't currently
- * have selectivity functions
- */
- resultData = 1.0 / 3.0;
- result = &resultData;
- }
- else {
- result = (float64)fmgr(get_oprrest (operatorObjectId),
- (char*)operatorObjectId,
- (char*)indrelid,
- (char*)(int)attributeNumber,
- (char*)constValue,
- (char*)constFlag,
- NULL);
- }
-
- if (!PointerIsValid(result))
- elog(WARN, "Btree Selectivity: bad pointer");
- if (*result < 0.0 || *result > 1.0)
- elog(WARN, "Btree Selectivity: bad value %lf", *result);
-
- return(result);
+ float64 result;
+ float64data resultData;
+
+ if (FunctionalSelectivity(nIndexKeys, attributeNumber))
+ {
+
+ /*
+ * Need to call the functions selectivity function here. For now
+ * simply assume it's 1/3 since functions don't currently have
+ * selectivity functions
+ */
+ resultData = 1.0 / 3.0;
+ result = &resultData;
+ }
+ else
+ {
+ result = (float64) fmgr(get_oprrest(operatorObjectId),
+ (char *) operatorObjectId,
+ (char *) indrelid,
+ (char *) (int) attributeNumber,
+ (char *) constValue,
+ (char *) constFlag,
+ NULL);
+ }
+
+ if (!PointerIsValid(result))
+ elog(WARN, "Btree Selectivity: bad pointer");
+ if (*result < 0.0 || *result > 1.0)
+ elog(WARN, "Btree Selectivity: bad value %lf", *result);
+
+ return (result);
}
float64
btreenpage(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+ Oid indrelid,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag,
+ int32 nIndexKeys,
+ Oid indexrelid)
{
- float64 temp, result;
- float64data tempData;
- HeapTuple atp;
- int npage;
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
- /*
- * Need to call the functions selectivity
- * function here. For now simply assume it's
- * 1/3 since functions don't currently
- * have selectivity functions
- */
- tempData = 1.0 / 3.0;
- temp = &tempData;
- }
- else {
- temp = (float64)fmgr(get_oprrest (operatorObjectId),
- (char*)operatorObjectId,
- (char*)indrelid,
- (char*)(int)attributeNumber,
- (char*)constValue,
- (char*)constFlag,
- NULL);
- }
- atp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(indexrelid),
- 0,0,0);
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "btreenpage: no index tuple %d", indexrelid);
- return(0);
- }
-
- npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
- result = (float64)palloc(sizeof(float64data));
- *result = *temp * npage;
- return(result);
+ float64 temp,
+ result;
+ float64data tempData;
+ HeapTuple atp;
+ int npage;
+
+ if (FunctionalSelectivity(nIndexKeys, attributeNumber))
+ {
+
+ /*
+ * Need to call the functions selectivity function here. For now
+ * simply assume it's 1/3 since functions don't currently have
+ * selectivity functions
+ */
+ tempData = 1.0 / 3.0;
+ temp = &tempData;
+ }
+ else
+ {
+ temp = (float64) fmgr(get_oprrest(operatorObjectId),
+ (char *) operatorObjectId,
+ (char *) indrelid,
+ (char *) (int) attributeNumber,
+ (char *) constValue,
+ (char *) constFlag,
+ NULL);
+ }
+ atp = SearchSysCacheTuple(RELOID,
+ ObjectIdGetDatum(indexrelid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(atp))
+ {
+ elog(WARN, "btreenpage: no index tuple %d", indexrelid);
+ return (0);
+ }
+
+ npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
+ result = (float64) palloc(sizeof(float64data));
+ *result = *temp * npage;
+ return (result);
}
float64
hashsel(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+ Oid indrelid,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag,
+ int32 nIndexKeys,
+ Oid indexrelid)
{
-
- float64 result;
- float64data resultData;
- HeapTuple atp;
- int ntuples;
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
- /*
- * Need to call the functions selectivity
- * function here. For now simply use 1/Number of Tuples
- * since functions don't currently
- * have selectivity functions
- */
-
- atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
- 0,0,0);
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "hashsel: no index tuple %d", indexrelid);
- return(0);
- }
- ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
- if (ntuples > 0) {
- resultData = 1.0 / (float64data) ntuples;
+
+ float64 result;
+ float64data resultData;
+ HeapTuple atp;
+ int ntuples;
+
+ if (FunctionalSelectivity(nIndexKeys, attributeNumber))
+ {
+
+ /*
+ * Need to call the functions selectivity function here. For now
+ * simply use 1/Number of Tuples since functions don't currently
+ * have selectivity functions
+ */
+
+ atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(atp))
+ {
+ elog(WARN, "hashsel: no index tuple %d", indexrelid);
+ return (0);
+ }
+ ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
+ if (ntuples > 0)
+ {
+ resultData = 1.0 / (float64data) ntuples;
+ }
+ else
+ {
+ resultData = (float64data) (1.0 / 100.0);
+ }
+ result = &resultData;
+
}
- else {
- resultData = (float64data) (1.0 / 100.0);
+ else
+ {
+ result = (float64) fmgr(get_oprrest(operatorObjectId),
+ (char *) operatorObjectId,
+ (char *) indrelid,
+ (char *) (int) attributeNumber,
+ (char *) constValue,
+ (char *) constFlag,
+ NULL);
}
- result = &resultData;
-
- }
- else {
- result = (float64)fmgr(get_oprrest (operatorObjectId),
- (char*)operatorObjectId,
- (char*)indrelid,
- (char*)(int)attributeNumber,
- (char*)constValue,
- (char*)constFlag,
- NULL);
- }
-
- if (!PointerIsValid(result))
- elog(WARN, "Hash Table Selectivity: bad pointer");
- if (*result < 0.0 || *result > 1.0)
- elog(WARN, "Hash Table Selectivity: bad value %lf", *result);
-
- return(result);
-
-
+
+ if (!PointerIsValid(result))
+ elog(WARN, "Hash Table Selectivity: bad pointer");
+ if (*result < 0.0 || *result > 1.0)
+ elog(WARN, "Hash Table Selectivity: bad value %lf", *result);
+
+ return (result);
+
+
}
float64
hashnpage(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+ Oid indrelid,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag,
+ int32 nIndexKeys,
+ Oid indexrelid)
{
- float64 temp, result;
- float64data tempData;
- HeapTuple atp;
- int npage;
- int ntuples;
-
- atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
- 0,0,0);
- if (!HeapTupleIsValid(atp)) {
- elog(WARN, "hashsel: no index tuple %d", indexrelid);
- return(0);
- }
-
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
- /*
- * Need to call the functions selectivity
- * function here. For now, use 1/Number of Tuples
- * since functions don't currently
- * have selectivity functions
- */
-
- ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
- if (ntuples > 0) {
- tempData = 1.0 / (float64data) ntuples;
+ float64 temp,
+ result;
+ float64data tempData;
+ HeapTuple atp;
+ int npage;
+ int ntuples;
+
+ atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(atp))
+ {
+ elog(WARN, "hashsel: no index tuple %d", indexrelid);
+ return (0);
+ }
+
+
+ if (FunctionalSelectivity(nIndexKeys, attributeNumber))
+ {
+
+ /*
+ * Need to call the functions selectivity function here. For now,
+ * use 1/Number of Tuples since functions don't currently have
+ * selectivity functions
+ */
+
+ ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
+ if (ntuples > 0)
+ {
+ tempData = 1.0 / (float64data) ntuples;
+ }
+ else
+ {
+ tempData = (float64data) (1.0 / 100.0);
+ }
+ temp = &tempData;
+
}
- else {
- tempData = (float64data) (1.0 / 100.0);
+ else
+ {
+ temp = (float64) fmgr(get_oprrest(operatorObjectId),
+ (char *) operatorObjectId,
+ (char *) indrelid,
+ (char *) (int) attributeNumber,
+ (char *) constValue,
+ (char *) constFlag,
+ NULL);
}
- temp = &tempData;
-
- }
- else {
- temp = (float64)fmgr(get_oprrest (operatorObjectId),
- (char*)operatorObjectId,
- (char*)indrelid,
- (char*)(int)attributeNumber,
- (char*)constValue,
- (char*)constFlag,
- NULL);
- }
-
- npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
- result = (float64)palloc(sizeof(float64data));
- *result = *temp * npage;
- return(result);
+
+ npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
+ result = (float64) palloc(sizeof(float64data));
+ *result = *temp * npage;
+ return (result);
}
float64
rtsel(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+ Oid indrelid,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag,
+ int32 nIndexKeys,
+ Oid indexrelid)
{
- return (btreesel(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
+ return (btreesel(operatorObjectId, indrelid, attributeNumber,
+ constValue, constFlag, nIndexKeys, indexrelid));
}
float64
rtnpage(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+ Oid indrelid,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag,
+ int32 nIndexKeys,
+ Oid indexrelid)
{
- return (btreenpage(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
+ return (btreenpage(operatorObjectId, indrelid, attributeNumber,
+ constValue, constFlag, nIndexKeys, indexrelid));
}
float64
gistsel(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+ Oid indrelid,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag,
+ int32 nIndexKeys,
+ Oid indexrelid)
{
- return (btreesel(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
+ return (btreesel(operatorObjectId, indrelid, attributeNumber,
+ constValue, constFlag, nIndexKeys, indexrelid));
}
float64
gistnpage(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+ Oid indrelid,
+ AttrNumber attributeNumber,
+ char *constValue,
+ int32 constFlag,
+ int32 nIndexKeys,
+ Oid indexrelid)
{
- return (btreenpage(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
+ return (btreenpage(operatorObjectId, indrelid, attributeNumber,
+ constValue, constFlag, nIndexKeys, indexrelid));
}
diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c
index 55ca1f4b643..72f0a615a66 100644
--- a/src/backend/utils/adt/sets.c
+++ b/src/backend/utils/adt/sets.c
@@ -1,163 +1,173 @@
/*-------------------------------------------------------------------------
*
* sets.c--
- * Functions for sets, which are defined by queries.
- * Example: a set is defined as being the result of the query
- * retrieve (X.all)
+ * Functions for sets, which are defined by queries.
+ * Example: a set is defined as being the result of the query
+ * retrieve (X.all)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.5 1997/08/12 22:54:38 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.6 1997/09/07 04:50:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
#include "access/heapam.h"
#include "access/relscan.h"
#include "access/xact.h"
-#include "catalog/pg_proc.h" /* for Form_pg_proc */
-#include "utils/syscache.h" /* for PROOID */
-#include "catalog/catname.h" /* for ProcedureRelationName */
-#include "catalog/indexing.h" /* for Num_pg_proc_indices */
+#include "catalog/pg_proc.h" /* for Form_pg_proc */
+#include "utils/syscache.h" /* for PROOID */
+#include "catalog/catname.h" /* for ProcedureRelationName */
+#include "catalog/indexing.h" /* for Num_pg_proc_indices */
#include "storage/lmgr.h"
-#include "utils/sets.h" /* for GENERICSETNAME */
+#include "utils/sets.h" /* for GENERICSETNAME */
#include "tcop/dest.h"
#include "fmgr.h"
-extern CommandDest whereToSendOutput; /* defined in tcop/postgres.c */
+extern CommandDest whereToSendOutput; /* defined in tcop/postgres.c */
/*
- * SetDefine - converts query string defining set to an oid
+ * SetDefine - converts query string defining set to an oid
*
- * The query string is used to store the set as a function in
- * pg_proc. The name of the function is then changed to use the
- * OID of its tuple in pg_proc.
+ * The query string is used to store the set as a function in
+ * pg_proc. The name of the function is then changed to use the
+ * OID of its tuple in pg_proc.
*/
Oid
SetDefine(char *querystr, char *typename)
{
- Oid setoid;
- char *procname = GENERICSETNAME;
- char *fileName = "-";
- char realprocname[16];
- HeapTuple tup, newtup = NULL;
- Form_pg_proc proc;
- Relation procrel;
- int i;
- Datum replValue[Natts_pg_proc];
- char replNull[Natts_pg_proc];
- char repl[Natts_pg_proc];
- HeapScanDesc pg_proc_scan;
- Buffer buffer;
- ItemPointerData ipdata;
-
- static ScanKeyData oidKey[1] = {
- { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure }};
-
-
- setoid = ProcedureCreate(procname, /* changed below, after oid known */
- true, /* returnsSet */
- typename, /* returnTypeName */
- "sql", /* languageName */
- querystr, /* sourceCode */
- fileName, /* fileName */
- false, /* canCache */
- true, /* trusted */
- 100, /* byte_pct */
- 0, /* perbyte_cpu */
- 0, /* percall_cpu */
- 100, /* outin_ratio */
- NIL, /* argList */
- whereToSendOutput);
- /* Since we're still inside this command of the transaction, we can't
- * see the results of the procedure definition unless we pretend
- * we've started the next command. (Postgres's solution to the
- * Halloween problem is to not allow you to see the results of your
- * command until you start the next command.)
- */
- CommandCounterIncrement();
- tup = SearchSysCacheTuple(PROOID,
- ObjectIdGetDatum(setoid),
- 0,0,0);
- if (!HeapTupleIsValid(tup))
- elog(WARN, "setin: unable to define set %s", querystr);
-
- /* We can tell whether the set was already defined by checking
- * the name. If it's GENERICSETNAME, the set is new. If it's
- * "set<some oid>" it's already defined.
- */
- proc = (Form_pg_proc)GETSTRUCT(tup);
- if (!strcmp((char*)procname, (char*)&(proc->proname))) {
- /* make the real proc name */
- sprintf(realprocname, "set%u", setoid);
-
- /* set up the attributes to be modified or kept the same */
- repl[0] = 'r';
- for (i = 1; i < Natts_pg_proc; i++) repl[i] = ' ';
- replValue[0] = (Datum)realprocname;
- for (i = 1; i < Natts_pg_proc; i++) replValue[i] = (Datum)0;
- for (i = 0; i < Natts_pg_proc; i++) replNull[i] = ' ';
-
- /* change the pg_proc tuple */
- procrel = heap_openr(ProcedureRelationName);
- RelationSetLockForWrite(procrel);
- fmgr_info(ObjectIdEqualRegProcedure,
- &oidKey[0].sk_func,
- &oidKey[0].sk_nargs);
- oidKey[0].sk_argument = ObjectIdGetDatum(setoid);
- pg_proc_scan = heap_beginscan(procrel,
- 0,
- SelfTimeQual,
- 1,
- oidKey);
- tup = heap_getnext(pg_proc_scan, 0, &buffer);
- if (HeapTupleIsValid(tup)) {
- newtup = heap_modifytuple(tup,
- buffer,
- procrel,
- replValue,
- replNull,
- repl);
-
- /* XXX may not be necessary */
- ItemPointerCopy(&tup->t_ctid, &ipdata);
-
- setheapoverride(true);
- heap_replace(procrel, &ipdata, newtup);
- setheapoverride(false);
-
- setoid = newtup->t_oid;
- } else
- elog(WARN, "setin: could not find new set oid tuple");
- heap_endscan(pg_proc_scan);
-
- if (RelationGetRelationTupleForm(procrel)->relhasindex)
- {
- Relation idescs[Num_pg_proc_indices];
-
- CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup);
- CatalogCloseIndices(Num_pg_proc_indices, idescs);
- }
- RelationUnsetLockForWrite(procrel);
- heap_close(procrel);
- }
- return setoid;
+ Oid setoid;
+ char *procname = GENERICSETNAME;
+ char *fileName = "-";
+ char realprocname[16];
+ HeapTuple tup,
+ newtup = NULL;
+ Form_pg_proc proc;
+ Relation procrel;
+ int i;
+ Datum replValue[Natts_pg_proc];
+ char replNull[Natts_pg_proc];
+ char repl[Natts_pg_proc];
+ HeapScanDesc pg_proc_scan;
+ Buffer buffer;
+ ItemPointerData ipdata;
+
+ static ScanKeyData oidKey[1] = {
+ {0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure}};
+
+
+ setoid = ProcedureCreate(procname, /* changed below, after oid known */
+ true, /* returnsSet */
+ typename, /* returnTypeName */
+ "sql", /* languageName */
+ querystr, /* sourceCode */
+ fileName, /* fileName */
+ false, /* canCache */
+ true, /* trusted */
+ 100, /* byte_pct */
+ 0, /* perbyte_cpu */
+ 0, /* percall_cpu */
+ 100, /* outin_ratio */
+ NIL, /* argList */
+ whereToSendOutput);
+
+ /*
+ * Since we're still inside this command of the transaction, we can't
+ * see the results of the procedure definition unless we pretend we've
+ * started the next command. (Postgres's solution to the Halloween
+ * problem is to not allow you to see the results of your command
+ * until you start the next command.)
+ */
+ CommandCounterIncrement();
+ tup = SearchSysCacheTuple(PROOID,
+ ObjectIdGetDatum(setoid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(WARN, "setin: unable to define set %s", querystr);
+
+ /*
+ * We can tell whether the set was already defined by checking the
+ * name. If it's GENERICSETNAME, the set is new. If it's "set<some
+ * oid>" it's already defined.
+ */
+ proc = (Form_pg_proc) GETSTRUCT(tup);
+ if (!strcmp((char *) procname, (char *) &(proc->proname)))
+ {
+ /* make the real proc name */
+ sprintf(realprocname, "set%u", setoid);
+
+ /* set up the attributes to be modified or kept the same */
+ repl[0] = 'r';
+ for (i = 1; i < Natts_pg_proc; i++)
+ repl[i] = ' ';
+ replValue[0] = (Datum) realprocname;
+ for (i = 1; i < Natts_pg_proc; i++)
+ replValue[i] = (Datum) 0;
+ for (i = 0; i < Natts_pg_proc; i++)
+ replNull[i] = ' ';
+
+ /* change the pg_proc tuple */
+ procrel = heap_openr(ProcedureRelationName);
+ RelationSetLockForWrite(procrel);
+ fmgr_info(ObjectIdEqualRegProcedure,
+ &oidKey[0].sk_func,
+ &oidKey[0].sk_nargs);
+ oidKey[0].sk_argument = ObjectIdGetDatum(setoid);
+ pg_proc_scan = heap_beginscan(procrel,
+ 0,
+ SelfTimeQual,
+ 1,
+ oidKey);
+ tup = heap_getnext(pg_proc_scan, 0, &buffer);
+ if (HeapTupleIsValid(tup))
+ {
+ newtup = heap_modifytuple(tup,
+ buffer,
+ procrel,
+ replValue,
+ replNull,
+ repl);
+
+ /* XXX may not be necessary */
+ ItemPointerCopy(&tup->t_ctid, &ipdata);
+
+ setheapoverride(true);
+ heap_replace(procrel, &ipdata, newtup);
+ setheapoverride(false);
+
+ setoid = newtup->t_oid;
+ }
+ else
+ elog(WARN, "setin: could not find new set oid tuple");
+ heap_endscan(pg_proc_scan);
+
+ if (RelationGetRelationTupleForm(procrel)->relhasindex)
+ {
+ Relation idescs[Num_pg_proc_indices];
+
+ CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup);
+ CatalogCloseIndices(Num_pg_proc_indices, idescs);
+ }
+ RelationUnsetLockForWrite(procrel);
+ heap_close(procrel);
+ }
+ return setoid;
}
-/* This function is a placeholder. The parser uses the OID of this
+/* This function is a placeholder. The parser uses the OID of this
* function to fill in the :funcid field of a set. This routine is
- * never executed. At runtime, the OID of the actual set is substituted
+ * never executed. At runtime, the OID of the actual set is substituted
* into the :funcid.
*/
int
seteval(Oid funcoid)
{
- return 17;
+ return 17;
}
diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c
index 6fb4e589ad8..fe10f2b58e3 100644
--- a/src/backend/utils/adt/tid.c
+++ b/src/backend/utils/adt/tid.c
@@ -1,89 +1,90 @@
/*-------------------------------------------------------------------------
*
* tid.c--
- * Functions for the built-in type tuple id
+ * Functions for the built-in type tuple id
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.2 1996/11/06 06:50:05 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.3 1997/09/07 04:50:46 momjian Exp $
*
* NOTES
- * input routine largely stolen from boxin().
+ * input routine largely stolen from boxin().
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
#include "storage/bufpage.h"
#include "utils/palloc.h"
-#include "utils/builtins.h" /* where function declarations go */
+#include "utils/builtins.h" /* where function declarations go */
-#define LDELIM '('
-#define RDELIM ')'
-#define DELIM ','
-#define NTIDARGS 2
+#define LDELIM '('
+#define RDELIM ')'
+#define DELIM ','
+#define NTIDARGS 2
/* ----------------------------------------------------------------
- * tidin
+ * tidin
* ----------------------------------------------------------------
*/
ItemPointer
tidin(char *str)
{
- char *p, *coord[NTIDARGS];
- int i;
- ItemPointer result;
-
- BlockNumber blockNumber;
- OffsetNumber offsetNumber;
-
- if (str == NULL)
- return NULL;
-
- for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
- if (*p == DELIM || (*p == LDELIM && !i))
- coord[i++] = p + 1;
-
- if (i < NTIDARGS - 1)
- return NULL;
-
- blockNumber = (BlockNumber) atoi(coord[0]);
- offsetNumber = (OffsetNumber) atoi(coord[1]);
-
- result = (ItemPointer) palloc(sizeof(ItemPointerData));
-
- ItemPointerSet(result, blockNumber, offsetNumber);
-
- return result;
+ char *p,
+ *coord[NTIDARGS];
+ int i;
+ ItemPointer result;
+
+ BlockNumber blockNumber;
+ OffsetNumber offsetNumber;
+
+ if (str == NULL)
+ return NULL;
+
+ for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
+ if (*p == DELIM || (*p == LDELIM && !i))
+ coord[i++] = p + 1;
+
+ if (i < NTIDARGS - 1)
+ return NULL;
+
+ blockNumber = (BlockNumber) atoi(coord[0]);
+ offsetNumber = (OffsetNumber) atoi(coord[1]);
+
+ result = (ItemPointer) palloc(sizeof(ItemPointerData));
+
+ ItemPointerSet(result, blockNumber, offsetNumber);
+
+ return result;
}
/* ----------------------------------------------------------------
- * tidout
+ * tidout
* ----------------------------------------------------------------
*/
-char *
+char *
tidout(ItemPointer itemPtr)
{
- BlockNumber blockNumber;
- OffsetNumber offsetNumber;
- BlockId blockId;
- char buf[32];
- char *str;
-
- blockId = &(itemPtr->ip_blkid);
-
- blockNumber = BlockIdGetBlockNumber(blockId);
- offsetNumber = itemPtr->ip_posid;
-
- sprintf(buf, "(%d,%d)", blockNumber, offsetNumber);
-
- str = (char *) palloc(strlen(buf)+1);
- strcpy(str, buf);
-
- return str;
+ BlockNumber blockNumber;
+ OffsetNumber offsetNumber;
+ BlockId blockId;
+ char buf[32];
+ char *str;
+
+ blockId = &(itemPtr->ip_blkid);
+
+ blockNumber = BlockIdGetBlockNumber(blockId);
+ offsetNumber = itemPtr->ip_posid;
+
+ sprintf(buf, "(%d,%d)", blockNumber, offsetNumber);
+
+ str = (char *) palloc(strlen(buf) + 1);
+ strcpy(str, buf);
+
+ return str;
}
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 4d3a8f9af21..d9ed6d299c5 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -16,7 +16,7 @@
static const char *
cpstr(const char *s, char *buf)
{
- char in = 0;
+ char in = 0;
while (isspace(*s))
s++;
@@ -26,7 +26,7 @@ cpstr(const char *s, char *buf)
if (strchr("-,:/", *s))
{
buf[in] = 0;
- return(s + 1);
+ return (s + 1);
}
if (in < 16)
@@ -36,72 +36,76 @@ cpstr(const char *s, char *buf)
buf[in] = 0;
return s;
}
+
#endif
/* assumes dd/mm/yyyy unless first item is month in word form */
time_t
timestamp_in(const char *timestamp_str)
{
- int4 result;
+ int4 result;
#if FALSE
- struct tm input_time;
- char buf[18];
- const char *p;
+ struct tm input_time;
+ char buf[18];
+ const char *p;
static const char *mstr[] = {
"january", "february", "march", "april", "may", "june",
"july", "august", "september", "october", "november", "december"
};
- memset(&input_time, 0, sizeof(input_time));
+ memset(&input_time, 0, sizeof(input_time));
p = cpstr(timestamp_str, buf);
- if (isdigit(buf[0])) /* must be dd/mm/yyyy */
+ if (isdigit(buf[0])) /* must be dd/mm/yyyy */
{
input_time.tm_mday = atoi(buf);
p = cpstr(p, buf);
if (!buf[0])
elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date",
- timestamp_str);
+ timestamp_str);
if (isdigit(buf[0]))
{
input_time.tm_mon = atoi(buf) - 1;
if (input_time.tm_mon < 0 || input_time.tm_mon > 11)
elog(WARN, "timestamp_in: timestamp \"%s\" invalid month",
- timestamp_str);
+ timestamp_str);
}
else
{
- int i;
+ int i;
+
for (i = 0; i < 12; i++)
if (strncmp(mstr[i], buf, strlen(buf)) == 0)
break;
if (1 > 11)
elog(WARN, "timestamp_in: timestamp \"%s\" invalid month",
- timestamp_str);
+ timestamp_str);
input_time.tm_mon = i;
}
}
- else /* must be month/dd/yyyy */
+ else
+/* must be month/dd/yyyy */
{
- int i;
+ int i;
+
for (i = 0; i < 12; i++)
if (strncmp(mstr[i], buf, strlen(buf)) == 0)
break;
if (1 > 11)
elog(WARN, "timestamp_in: timestamp \"%s\" invalid month",
- timestamp_str);
+ timestamp_str);
input_time.tm_mon = i;
p = cpstr(p, buf);
input_time.tm_mday = atoi(buf);
if (!input_time.tm_mday || input_time.tm_mday > 31)
elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date",
- timestamp_str);
- }
+ timestamp_str);
+ }
p = cpstr(p, buf);
if (!buf[0] || !isdigit(buf[0]))
elog(WARN, "timestamp_in: timestamp \"%s\" not a proper date",
- timestamp_str);
+ timestamp_str);
if ((input_time.tm_year = atoi(buf)) < 1900)
input_time.tm_year += 1900;
@@ -113,102 +117,104 @@ timestamp_in(const char *timestamp_str)
p = cpstr(p, buf);
input_time.tm_sec = atoi(buf);
- /* use mktime(), but make this GMT, not local time */
- result = mktime(&input_time);
+ /* use mktime(), but make this GMT, not local time */
+ result = mktime(&input_time);
#endif
- result = nabstimein( (char *) timestamp_str);
+ result = nabstimein((char *) timestamp_str);
- return result;
+ return result;
}
-char *
+char *
timestamp_out(time_t timestamp)
{
- char *result;
- int tz;
- double fsec = 0;
- struct tm tt, *tm = &tt;
- char buf[MAXDATELEN+1];
- char zone[MAXDATELEN+1], *tzn = zone;
+ char *result;
+ int tz;
+ double fsec = 0;
+ struct tm tt,
+ *tm = &tt;
+ char buf[MAXDATELEN + 1];
+ char zone[MAXDATELEN + 1],
+ *tzn = zone;
#if FALSE
- time = localtime(&timestamp);
+ time = localtime(&timestamp);
- sprintf(result, "%04d-%02d-%02d %02d:%02d:%02d",
- time->tm_year+1900, time->tm_mon+1, time->tm_mday,
- time->tm_hour, time->tm_min, time->tm_sec);
+ sprintf(result, "%04d-%02d-%02d %02d:%02d:%02d",
+ time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
+ time->tm_hour, time->tm_min, time->tm_sec);
#endif
- abstime2tm( timestamp, &tz, tm, tzn);
- EncodeDateTime( tm, fsec, &tz, &tzn, USE_ISO_DATES, buf);
+ abstime2tm(timestamp, &tz, tm, tzn);
+ EncodeDateTime(tm, fsec, &tz, &tzn, USE_ISO_DATES, buf);
- result = palloc(strlen(buf)+1);
- strcpy( result, buf);
- return result;
+ result = palloc(strlen(buf) + 1);
+ strcpy(result, buf);
+ return result;
}
time_t
now(void)
{
- time_t sec;
+ time_t sec;
- time(&sec);
- return(sec);
+ time(&sec);
+ return (sec);
}
bool
timestampeq(time_t t1, time_t t2)
{
- return difftime(t1, t2) == 0;
+ return difftime(t1, t2) == 0;
}
bool
timestampne(time_t t1, time_t t2)
{
- return difftime(t1, t2) != 0;
+ return difftime(t1, t2) != 0;
}
bool
timestamplt(time_t t1, time_t t2)
{
- return difftime(t1, t2) > 0;
+ return difftime(t1, t2) > 0;
}
bool
timestampgt(time_t t1, time_t t2)
{
- return difftime(t1, t2) < 0;
+ return difftime(t1, t2) < 0;
}
bool
timestample(time_t t1, time_t t2)
{
- return difftime(t1, t2) >= 0;
+ return difftime(t1, t2) >= 0;
}
bool
timestampge(time_t t1, time_t t2)
{
- return difftime(t1, t2) <= 0;
+ return difftime(t1, t2) <= 0;
}
-DateTime *
+DateTime *
timestamp_datetime(time_t timestamp)
{
- DateTime *result;
+ DateTime *result;
- double fsec = 0;
- struct tm *tm;
+ double fsec = 0;
+ struct tm *tm;
- if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
- elog(WARN,"Memory allocation failed, can't convert timestamp to datetime",NULL);
+ if (!PointerIsValid(result = PALLOCTYPE(DateTime)))
+ elog(WARN, "Memory allocation failed, can't convert timestamp to datetime", NULL);
- tm = localtime((time_t *) &timestamp);
- tm->tm_year += 1900;
- tm->tm_mon += 1;
+ tm = localtime((time_t *) & timestamp);
+ tm->tm_year += 1900;
+ tm->tm_mon += 1;
- if (tm2datetime(tm, fsec, NULL, result) != 0)
- elog(WARN,"Unable to convert timestamp to datetime",timestamp_out(timestamp));
+ if (tm2datetime(tm, fsec, NULL, result) != 0)
+ elog(WARN, "Unable to convert timestamp to datetime", timestamp_out(timestamp));
- return(result);
-} /* timestamp_datetime() */
+ return (result);
+} /* timestamp_datetime() */
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 538063c6225..106ff5dad26 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* varchar.c--
- * Functions for the built-in type char() and varchar().
+ * Functions for the built-in type char() and varchar().
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.8 1997/08/12 20:16:07 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.9 1997/09/07 04:52:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
#include "utils/builtins.h"
@@ -35,488 +35,524 @@
* the length for the comparison functions. (The difference between "text"
* is that we truncate and possibly blank-pad the string at insertion time.)
*
- * - ay 6/95
+ * - ay 6/95
*/
-/*****************************************************************************
- * bpchar - char() *
+/*****************************************************************************
+ * bpchar - char() *
*****************************************************************************/
/*
* bpcharin -
- * converts a string of char() type to the internal representation.
- * len is the length specified in () plus 4 bytes. (XXX dummy is here
- * because we pass typelem as the second argument for array_in.)
+ * converts a string of char() type to the internal representation.
+ * len is the length specified in () plus 4 bytes. (XXX dummy is here
+ * because we pass typelem as the second argument for array_in.)
*/
-char *
+char *
bpcharin(char *s, int dummy, int typlen)
{
- char *result, *r;
- int len = typlen - 4;
- int i;
-
- if (s == NULL)
- return((char *) NULL);
-
- if (typlen == -1) {
- /*
- * this is here because some functions can't supply the typlen
- */
- len = strlen(s);
- typlen = len + 4;
- }
-
- if (len > 4096)
- elog(WARN, "bpcharin: length of char() must be less than 4096");
-
- result = (char *) palloc(typlen);
- *(int32*)result = typlen;
- r = result + 4;
- for(i=0; i < len; i++, r++, s++) {
- *r = *s;
- if (*r == '\0')
- break;
- }
- /* blank pad the string if necessary */
- for(; i < len; i++) {
- *r++ = ' ';
- }
- return(result);
+ char *result,
+ *r;
+ int len = typlen - 4;
+ int i;
+
+ if (s == NULL)
+ return ((char *) NULL);
+
+ if (typlen == -1)
+ {
+
+ /*
+ * this is here because some functions can't supply the typlen
+ */
+ len = strlen(s);
+ typlen = len + 4;
+ }
+
+ if (len > 4096)
+ elog(WARN, "bpcharin: length of char() must be less than 4096");
+
+ result = (char *) palloc(typlen);
+ *(int32 *) result = typlen;
+ r = result + 4;
+ for (i = 0; i < len; i++, r++, s++)
+ {
+ *r = *s;
+ if (*r == '\0')
+ break;
+ }
+ /* blank pad the string if necessary */
+ for (; i < len; i++)
+ {
+ *r++ = ' ';
+ }
+ return (result);
}
-char *
+char *
bpcharout(char *s)
{
- char *result;
- int len;
-
- if (s == NULL) {
- result = (char *) palloc(2);
- result[0] = '-';
- result[1] = '\0';
- } else {
- len = *(int32*)s - 4;
- result = (char *) palloc(len+1);
- strNcpy(result, s+4, len); /* these are blank-padded */
- }
- return(result);
+ char *result;
+ int len;
+
+ if (s == NULL)
+ {
+ result = (char *) palloc(2);
+ result[0] = '-';
+ result[1] = '\0';
+ }
+ else
+ {
+ len = *(int32 *) s - 4;
+ result = (char *) palloc(len + 1);
+ strNcpy(result, s + 4, len); /* these are blank-padded */
+ }
+ return (result);
}
-/*****************************************************************************
- * varchar - varchar() *
+/*****************************************************************************
+ * varchar - varchar() *
*****************************************************************************/
/*
* vcharin -
- * converts a string of varchar() type to the internal representation.
- * len is the length specified in () plus 4 bytes. (XXX dummy is here
- * because we pass typelem as the second argument for array_in.)
+ * converts a string of varchar() type to the internal representation.
+ * len is the length specified in () plus 4 bytes. (XXX dummy is here
+ * because we pass typelem as the second argument for array_in.)
*/
-char *
+char *
varcharin(char *s, int dummy, int typlen)
{
- char *result;
- int len = typlen - 4;
-
- if (s == NULL)
- return((char *) NULL);
-
- if (typlen == -1) {
- /*
- * this is here because some functions can't supply the typlen
- */
- len = strlen(s);
- typlen = len + 4;
- }
-
- if (len > 4096)
- elog(WARN, "varcharin: length of char() must be less than 4096");
-
- result = (char *) palloc(typlen);
- *(int32*)result = typlen;
- strncpy(result+4, s, len);
-
- return(result);
+ char *result;
+ int len = typlen - 4;
+
+ if (s == NULL)
+ return ((char *) NULL);
+
+ if (typlen == -1)
+ {
+
+ /*
+ * this is here because some functions can't supply the typlen
+ */
+ len = strlen(s);
+ typlen = len + 4;
+ }
+
+ if (len > 4096)
+ elog(WARN, "varcharin: length of char() must be less than 4096");
+
+ result = (char *) palloc(typlen);
+ *(int32 *) result = typlen;
+ strncpy(result + 4, s, len);
+
+ return (result);
}
-char *
+char *
varcharout(char *s)
{
- char *result;
- int len;
-
- if (s == NULL) {
- result = (char *) palloc(2);
- result[0] = '-';
- result[1] = '\0';
- } else {
- len = *(int32*)s - 4;
- result = (char *) palloc(len+1);
- strNcpy(result, s+4, len);
- }
- return(result);
+ char *result;
+ int len;
+
+ if (s == NULL)
+ {
+ result = (char *) palloc(2);
+ result[0] = '-';
+ result[1] = '\0';
+ }
+ else
+ {
+ len = *(int32 *) s - 4;
+ result = (char *) palloc(len + 1);
+ strNcpy(result, s + 4, len);
+ }
+ return (result);
}
/*****************************************************************************
- * Comparison Functions used for bpchar
+ * Comparison Functions used for bpchar
*****************************************************************************/
static int
bcTruelen(char *arg)
{
- char *s = arg + 4;
- int i;
- int len;
-
- len = *(int32*)arg - 4;
- for(i=len-1; i >= 0; i--) {
- if (s[i] != ' ')
- break;
- }
- return (i+1);
+ char *s = arg + 4;
+ int i;
+ int len;
+
+ len = *(int32 *) arg - 4;
+ for (i = len - 1; i >= 0; i--)
+ {
+ if (s[i] != ' ')
+ break;
+ }
+ return (i + 1);
}
bool
bpchareq(char *arg1, char *arg2)
{
- int len1, len2;
+ int len1,
+ len2;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = bcTruelen(arg1);
+ len2 = bcTruelen(arg2);
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = bcTruelen(arg1);
- len2 = bcTruelen(arg2);
+ if (len1 != len2)
+ return 0;
- if (len1!=len2)
- return 0;
-
- return(strncmp(arg1+4, arg2+4, len1) == 0);
+ return (strncmp(arg1 + 4, arg2 + 4, len1) == 0);
}
bool
bpcharne(char *arg1, char *arg2)
{
- int len1, len2;
+ int len1,
+ len2;
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = bcTruelen(arg1);
- len2 = bcTruelen(arg2);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = bcTruelen(arg1);
+ len2 = bcTruelen(arg2);
- if (len1!=len2)
- return 1;
+ if (len1 != len2)
+ return 1;
- return(strncmp(arg1+4, arg2+4, len1) != 0);
+ return (strncmp(arg1 + 4, arg2 + 4, len1) != 0);
}
bool
bpcharlt(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = bcTruelen(arg1);
- len2 = bcTruelen(arg2);
-
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if (cmp == 0)
- return (len1<len2);
- else
- return (cmp < 0);
+ int len1,
+ len2;
+ int cmp;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = bcTruelen(arg1);
+ len2 = bcTruelen(arg2);
+
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if (cmp == 0)
+ return (len1 < len2);
+ else
+ return (cmp < 0);
}
bool
bpcharle(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = bcTruelen(arg1);
- len2 = bcTruelen(arg2);
-
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if (0 == cmp)
- return (bool)(len1 <= len2 ? 1 : 0);
- else
- return (bool)(cmp <= 0);
+ int len1,
+ len2;
+ int cmp;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = bcTruelen(arg1);
+ len2 = bcTruelen(arg2);
+
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if (0 == cmp)
+ return (bool) (len1 <= len2 ? 1 : 0);
+ else
+ return (bool) (cmp <= 0);
}
bool
bpchargt(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = bcTruelen(arg1);
- len2 = bcTruelen(arg2);
-
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if (cmp == 0)
- return (len1 > len2);
- else
- return (cmp > 0);
+ int len1,
+ len2;
+ int cmp;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = bcTruelen(arg1);
+ len2 = bcTruelen(arg2);
+
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if (cmp == 0)
+ return (len1 > len2);
+ else
+ return (cmp > 0);
}
bool
bpcharge(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = bcTruelen(arg1);
- len2 = bcTruelen(arg2);
-
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if (0 == cmp)
- return (bool)(len1 >= len2 ? 1 : 0);
- else
- return (bool)(cmp >= 0);
+ int len1,
+ len2;
+ int cmp;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = bcTruelen(arg1);
+ len2 = bcTruelen(arg2);
+
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if (0 == cmp)
+ return (bool) (len1 >= len2 ? 1 : 0);
+ else
+ return (bool) (cmp >= 0);
}
int32
bpcharcmp(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- len1 = bcTruelen(arg1);
- len2 = bcTruelen(arg2);
-
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if ((0 == cmp) && (len1 != len2))
- return (int32)(len1 < len2 ? -1 : 1);
- else
- return cmp;
+ int len1,
+ len2;
+ int cmp;
+
+ len1 = bcTruelen(arg1);
+ len2 = bcTruelen(arg2);
+
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if ((0 == cmp) && (len1 != len2))
+ return (int32) (len1 < len2 ? -1 : 1);
+ else
+ return cmp;
}
/*****************************************************************************
- * Comparison Functions used for varchar
+ * Comparison Functions used for varchar
*****************************************************************************/
static int
vcTruelen(char *arg)
{
- char *s = arg + 4;
- int i;
- int len;
-
- len = *(int32*)arg - 4;
- for(i=0; i < len; i++) {
- if (*s++ == '\0')
- break;
- }
- return i;
+ char *s = arg + 4;
+ int i;
+ int len;
+
+ len = *(int32 *) arg - 4;
+ for (i = 0; i < len; i++)
+ {
+ if (*s++ == '\0')
+ break;
+ }
+ return i;
}
bool
varchareq(char *arg1, char *arg2)
{
- int len1, len2;
+ int len1,
+ len2;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = vcTruelen(arg1);
+ len2 = vcTruelen(arg2);
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = vcTruelen(arg1);
- len2 = vcTruelen(arg2);
+ if (len1 != len2)
+ return 0;
- if (len1!=len2)
- return 0;
-
- return(strncmp(arg1+4, arg2+4, len1) == 0);
+ return (strncmp(arg1 + 4, arg2 + 4, len1) == 0);
}
bool
varcharne(char *arg1, char *arg2)
{
- int len1, len2;
+ int len1,
+ len2;
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = vcTruelen(arg1);
- len2 = vcTruelen(arg2);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = vcTruelen(arg1);
+ len2 = vcTruelen(arg2);
- if (len1!=len2)
- return 1;
+ if (len1 != len2)
+ return 1;
- return(strncmp(arg1+4, arg2+4, len1) != 0);
+ return (strncmp(arg1 + 4, arg2 + 4, len1) != 0);
}
bool
varcharlt(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = vcTruelen(arg1);
- len2 = vcTruelen(arg2);
-
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if (cmp == 0)
- return (len1<len2);
- else
- return (cmp < 0);
+ int len1,
+ len2;
+ int cmp;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = vcTruelen(arg1);
+ len2 = vcTruelen(arg2);
+
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if (cmp == 0)
+ return (len1 < len2);
+ else
+ return (cmp < 0);
}
bool
varcharle(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = vcTruelen(arg1);
- len2 = vcTruelen(arg2);
-
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if (0 == cmp)
- return (bool)( len1 <= len2 ? 1 : 0);
- else
- return (bool)(cmp <= 0);
+ int len1,
+ len2;
+ int cmp;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = vcTruelen(arg1);
+ len2 = vcTruelen(arg2);
+
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if (0 == cmp)
+ return (bool) (len1 <= len2 ? 1 : 0);
+ else
+ return (bool) (cmp <= 0);
}
bool
varchargt(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = vcTruelen(arg1);
- len2 = vcTruelen(arg2);
-
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if (cmp == 0)
- return (len1 > len2);
- else
- return (cmp > 0);
+ int len1,
+ len2;
+ int cmp;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = vcTruelen(arg1);
+ len2 = vcTruelen(arg2);
+
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if (cmp == 0)
+ return (len1 > len2);
+ else
+ return (cmp > 0);
}
bool
varcharge(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
+ int len1,
+ len2;
+ int cmp;
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
- len1 = vcTruelen(arg1);
- len2 = vcTruelen(arg2);
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+ len1 = vcTruelen(arg1);
+ len2 = vcTruelen(arg2);
- cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
- if (0 == cmp)
- return (bool)(len1 >= len2 ? 1 : 0);
- else
- return (bool)(cmp >= 0);
+ cmp = strncmp(arg1 + 4, arg2 + 4, Min(len1, len2));
+ if (0 == cmp)
+ return (bool) (len1 >= len2 ? 1 : 0);
+ else
+ return (bool) (cmp >= 0);
}
int32
varcharcmp(char *arg1, char *arg2)
{
- int len1, len2;
- int cmp;
-
- len1 = vcTruelen(arg1);
- len2 = vcTruelen(arg2);
- cmp = (strncmp(arg1+4, arg2+4, Min(len1,len2)));
- if ((0 == cmp) && (len1 != len2))
- return (int32)(len1 < len2 ? -1 : 1);
- else
- return (int32)(cmp);
+ int len1,
+ len2;
+ int cmp;
+
+ len1 = vcTruelen(arg1);
+ len2 = vcTruelen(arg2);
+ cmp = (strncmp(arg1 + 4, arg2 + 4, Min(len1, len2)));
+ if ((0 == cmp) && (len1 != len2))
+ return (int32) (len1 < len2 ? -1 : 1);
+ else
+ return (int32) (cmp);
}
/*****************************************************************************
* Hash functions (modified from hashtext in access/hash/hashfunc.c)
*****************************************************************************/
-uint32 hashbpchar(struct varlena *key)
+uint32
+hashbpchar(struct varlena * key)
{
- int keylen;
- char *keydata;
- uint32 n;
- int loop;
-
- keydata = VARDATA(key);
- keylen = bcTruelen((char*)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 = bcTruelen((char *) 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);
+}
-uint32 hashvarchar(struct varlena *key)
+uint32
+hashvarchar(struct varlena * key)
{
- int keylen;
- char *keydata;
- uint32 n;
- int loop;
-
- keydata = VARDATA(key);
- keylen = vcTruelen((char*)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 = vcTruelen((char *) 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/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 7c25cfd67b8..273fae92e9e 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* varlena.c--
- * Functions for the variable-length built-in types.
+ * Functions for the variable-length built-in types.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.18 1997/08/19 21:34:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.19 1997/09/07 04:52:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,64 +16,65 @@
#include "postgres.h"
#include "utils/palloc.h"
-#include "utils/builtins.h" /* where function declarations go */
+#include "utils/builtins.h" /* where function declarations go */
-/*****************************************************************************
- * USER I/O ROUTINES *
+/*****************************************************************************
+ * USER I/O ROUTINES *
*****************************************************************************/
-#define VAL(CH) ((CH) - '0')
-#define DIG(VAL) ((VAL) + '0')
+#define VAL(CH) ((CH) - '0')
+#define DIG(VAL) ((VAL) + '0')
/*
- * byteain - converts from printable representation of byte array
+ * byteain - converts from printable representation of byte array
*
- * Non-printable characters must be passed as '\nnn' (octal) and are
- * converted to internal form. '\' must be passed as '\\'.
- * elog(WARN, ...) if bad form.
+ * Non-printable characters must be passed as '\nnn' (octal) and are
+ * converted to internal form. '\' must be passed as '\\'.
+ * elog(WARN, ...) if bad form.
*
- * BUGS:
- * The input is scaned twice.
- * The error checking of input is minimal.
+ * BUGS:
+ * The input is scaned twice.
+ * The error checking of input is minimal.
*/
struct varlena *
byteain(char *inputText)
{
- register char *tp;
- register char *rp;
- register int byte;
- struct varlena *result;
-
- if (inputText == NULL)
- elog(WARN, "Bad input string for type bytea");
-
- for (byte = 0, tp = inputText; *tp != '\0'; byte++)
- if (*tp++ == '\\')
- {
- if (*tp == '\\')
- tp++;
- else if (!isdigit(*tp++) ||
- !isdigit(*tp++) ||
- !isdigit(*tp++))
- elog(WARN, "Bad input string for type bytea");
- }
- tp = inputText;
- byte += sizeof(int32); /* varlena? */
- result = (struct varlena *) palloc(byte);
- result->vl_len = byte; /* varlena? */
- rp = result->vl_dat;
- while (*tp != '\0')
- if (*tp != '\\' || *++tp == '\\')
- *rp++ = *tp++;
- else {
- byte = VAL(*tp++);
- byte <<= 3;
- byte += VAL(*tp++);
- byte <<= 3;
- *rp++ = byte + VAL(*tp++);
- }
- return(result);
+ register char *tp;
+ register char *rp;
+ register int byte;
+ struct varlena *result;
+
+ if (inputText == NULL)
+ elog(WARN, "Bad input string for type bytea");
+
+ for (byte = 0, tp = inputText; *tp != '\0'; byte++)
+ if (*tp++ == '\\')
+ {
+ if (*tp == '\\')
+ tp++;
+ else if (!isdigit(*tp++) ||
+ !isdigit(*tp++) ||
+ !isdigit(*tp++))
+ elog(WARN, "Bad input string for type bytea");
+ }
+ tp = inputText;
+ byte += sizeof(int32); /* varlena? */
+ result = (struct varlena *) palloc(byte);
+ result->vl_len = byte; /* varlena? */
+ rp = result->vl_dat;
+ while (*tp != '\0')
+ if (*tp != '\\' || *++tp == '\\')
+ *rp++ = *tp++;
+ else
+ {
+ byte = VAL(*tp++);
+ byte <<= 3;
+ byte += VAL(*tp++);
+ byte <<= 3;
+ *rp++ = byte + VAL(*tp++);
+ }
+ return (result);
}
/*
@@ -85,114 +86,120 @@ byteain(char *inputText)
struct varlena *
shove_bytes(unsigned char *stuff, int len)
{
- struct varlena *result;
-
- result = (struct varlena *) palloc(len + sizeof(int32));
- result->vl_len = len;
- memmove(result->vl_dat,
- stuff + sizeof(int32),
- len - sizeof(int32));
- return(result);
+ struct varlena *result;
+
+ result = (struct varlena *) palloc(len + sizeof(int32));
+ result->vl_len = len;
+ memmove(result->vl_dat,
+ stuff + sizeof(int32),
+ len - sizeof(int32));
+ return (result);
}
+
#endif
/*
- * byteaout - converts to printable representation of byte array
+ * byteaout - converts to printable representation of byte array
*
- * Non-printable characters are inserted as '\nnn' (octal) and '\' as
- * '\\'.
+ * Non-printable characters are inserted as '\nnn' (octal) and '\' as
+ * '\\'.
*
- * NULL vlena should be an error--returning string with NULL for now.
+ * NULL vlena should be an error--returning string with NULL for now.
*/
-char *
-byteaout(struct varlena *vlena)
+char *
+byteaout(struct varlena * vlena)
{
- register char *vp;
- register char *rp;
- register int val; /* holds unprintable chars */
- int i;
- int len;
- static char *result;
-
- if (vlena == NULL) {
- result = (char *) palloc(2);
- result[0] = '-';
- result[1] = '\0';
- return(result);
- }
- vp = vlena->vl_dat;
- len = 1; /* empty string has 1 char */
- for (i = vlena->vl_len - sizeof(int32); i != 0; i--, vp++) /* varlena? */
- if (*vp == '\\')
- len += 2;
- else if (isascii(*vp) && isprint(*vp))
- len++;
- else
- len += 4;
- rp = result = (char *) palloc(len);
- vp = vlena->vl_dat;
- for (i = vlena->vl_len - sizeof(int32); i != 0; i--) /* varlena? */
- if (*vp == '\\') {
- vp++;
- *rp++ = '\\';
- *rp++ = '\\';
- } else if (isascii(*vp) && isprint(*vp))
- *rp++ = *vp++;
- else {
- val = *vp++;
- *rp = '\\';
- rp += 3;
- *rp-- = DIG(val & 07);
- val >>= 3;
- *rp-- = DIG(val & 07);
- val >>= 3;
- *rp = DIG(val & 03);
- rp += 3;
+ register char *vp;
+ register char *rp;
+ register int val; /* holds unprintable chars */
+ int i;
+ int len;
+ static char *result;
+
+ if (vlena == NULL)
+ {
+ result = (char *) palloc(2);
+ result[0] = '-';
+ result[1] = '\0';
+ return (result);
}
- *rp = '\0';
- return(result);
+ vp = vlena->vl_dat;
+ len = 1; /* empty string has 1 char */
+ for (i = vlena->vl_len - sizeof(int32); i != 0; i--, vp++) /* varlena? */
+ if (*vp == '\\')
+ len += 2;
+ else if (isascii(*vp) && isprint(*vp))
+ len++;
+ else
+ len += 4;
+ rp = result = (char *) palloc(len);
+ vp = vlena->vl_dat;
+ for (i = vlena->vl_len - sizeof(int32); i != 0; i--) /* varlena? */
+ if (*vp == '\\')
+ {
+ vp++;
+ *rp++ = '\\';
+ *rp++ = '\\';
+ }
+ else if (isascii(*vp) && isprint(*vp))
+ *rp++ = *vp++;
+ else
+ {
+ val = *vp++;
+ *rp = '\\';
+ rp += 3;
+ *rp-- = DIG(val & 07);
+ val >>= 3;
+ *rp-- = DIG(val & 07);
+ val >>= 3;
+ *rp = DIG(val & 03);
+ rp += 3;
+ }
+ *rp = '\0';
+ return (result);
}
/*
- * textin - converts "..." to internal representation
+ * textin - converts "..." to internal representation
*/
struct varlena *
textin(char *inputText)
{
- struct varlena *result;
- int len;
-
- if (inputText == NULL)
- return(NULL);
- len = strlen(inputText) + VARHDRSZ;
- result = (struct varlena *) palloc(len);
- VARSIZE(result) = len;
- memmove(VARDATA(result), inputText, len - VARHDRSZ);
- return(result);
+ struct varlena *result;
+ int len;
+
+ if (inputText == NULL)
+ return (NULL);
+ len = strlen(inputText) + VARHDRSZ;
+ result = (struct varlena *) palloc(len);
+ VARSIZE(result) = len;
+ memmove(VARDATA(result), inputText, len - VARHDRSZ);
+ return (result);
}
/*
- * textout - converts internal representation to "..."
+ * textout - converts internal representation to "..."
*/
-char *
-textout(struct varlena *vlena)
+char *
+textout(struct varlena * vlena)
{
- int len;
- char *result;
-
- if (vlena == NULL) {
- result = (char *) palloc(2);
- result[0] = '-';
- result[1] = '\0';
- return(result);
- }
- len = VARSIZE(vlena) - VARHDRSZ;
- result = (char *) palloc(len + 1);
- memmove(result, VARDATA(vlena), len);
- result[len] = '\0';
- return(result);
+ int len;
+ char *result;
+
+ if (vlena == NULL)
+ {
+ result = (char *) palloc(2);
+ result[0] = '-';
+ result[1] = '\0';
+ return (result);
+ }
+ len = VARSIZE(vlena) - VARHDRSZ;
+ result = (char *) palloc(len + 1);
+ memmove(result, VARDATA(vlena), len);
+ result[len] = '\0';
+ return (result);
}
@@ -200,25 +207,28 @@ textout(struct varlena *vlena)
/*
* textlen -
- * returns the actual length of a text* (which may be less than
- * the VARSIZE of the text*)
+ * returns the actual length of a text* (which may be less than
+ * the VARSIZE of the text*)
*/
#ifdef NOT_USED
-int textlen (text* t)
+int
+textlen(text * t)
{
- int i = 0;
- int max = VARSIZE(t) - VARHDRSZ;
- char *ptr = VARDATA(t);
- while (i < max && *ptr++)
- i++;
- return i;
+ int i = 0;
+ int max = VARSIZE(t) - VARHDRSZ;
+ char *ptr = VARDATA(t);
+
+ while (i < max && *ptr++)
+ i++;
+ return i;
}
+
#endif
/*
* textcat -
- * takes two text* and returns a text* that is the concatentation of
- * the two.
+ * takes two text* and returns a text* that is the concatentation of
+ * the two.
*
* Rewritten by Sapa, [email protected]. 8-Jul-96.
* Updated by Thomas, [email protected] 1997-07-10.
@@ -228,222 +238,241 @@ int textlen (text* t)
* Is this OK?
*/
-text*
-textcat(text* t1, text* t2)
+text *
+textcat(text * t1, text * t2)
{
- int len1, len2, len;
- char *ptr;
- text* result;
+ int len1,
+ len2,
+ len;
+ char *ptr;
+ text *result;
- if (!PointerIsValid(t1) && !PointerIsValid(t2))
- return(NULL);
+ if (!PointerIsValid(t1) && !PointerIsValid(t2))
+ return (NULL);
- len1 = (PointerIsValid(t1)? (VARSIZE(t1) - VARHDRSZ): 0);
- if (len1 < 0) len1 = 0;
- len2 = (PointerIsValid(t2)? (VARSIZE(t2) - VARHDRSZ): 0);
- if (len2 < 0) len2 = 0;
+ len1 = (PointerIsValid(t1) ? (VARSIZE(t1) - VARHDRSZ) : 0);
+ if (len1 < 0)
+ len1 = 0;
+ len2 = (PointerIsValid(t2) ? (VARSIZE(t2) - VARHDRSZ) : 0);
+ if (len2 < 0)
+ len2 = 0;
- result = PALLOC(len = len1 + len2 + VARHDRSZ);
+ result = PALLOC(len = len1 + len2 + VARHDRSZ);
- /* Fill data field of result string... */
- ptr = VARDATA(result);
- if (PointerIsValid(t1)) memcpy(ptr, VARDATA(t1), len1);
- if (PointerIsValid(t2)) memcpy(ptr + len1, VARDATA(t2), len2);
+ /* Fill data field of result string... */
+ ptr = VARDATA(result);
+ if (PointerIsValid(t1))
+ memcpy(ptr, VARDATA(t1), len1);
+ if (PointerIsValid(t2))
+ memcpy(ptr + len1, VARDATA(t2), len2);
- /* Set size of result string... */
- VARSIZE(result) = len;
+ /* Set size of result string... */
+ VARSIZE(result) = len;
- return(result);
-} /* textcat() */
+ return (result);
+} /* textcat() */
/*
* textpos -
- * Return the position of the specified substring.
- * Implements the SQL92 POSITION() function.
- * Ref: A Guide To The SQL Standard, Date & Darwen, 1997
+ * Return the position of the specified substring.
+ * Implements the SQL92 POSITION() function.
+ * Ref: A Guide To The SQL Standard, Date & Darwen, 1997
* - thomas 1997-07-27
*/
int32
-textpos(text* t1, text* t2)
+textpos(text * t1, text * t2)
{
- int pos;
- int px, p;
- int len1, len2;
- char *p1, *p2;
-
- if (!PointerIsValid(t1) || !PointerIsValid(t2))
- return(0);
-
- if (VARSIZE(t2) <= 0)
- return(1);
-
- len1 = (VARSIZE(t1) - VARHDRSZ);
- len2 = (VARSIZE(t2) - VARHDRSZ);
- p1 = VARDATA(t1);
- p2 = VARDATA(t2);
- pos = 0;
- px = (len1 - len2);
- for (p = 0; p <= px; p++) {
- if ((*p2 == *p1) && (strncmp(p1, p2, len2) == 0)) {
- pos = p + 1;
- break;
+ int pos;
+ int px,
+ p;
+ int len1,
+ len2;
+ char *p1,
+ *p2;
+
+ if (!PointerIsValid(t1) || !PointerIsValid(t2))
+ return (0);
+
+ if (VARSIZE(t2) <= 0)
+ return (1);
+
+ len1 = (VARSIZE(t1) - VARHDRSZ);
+ len2 = (VARSIZE(t2) - VARHDRSZ);
+ p1 = VARDATA(t1);
+ p2 = VARDATA(t2);
+ pos = 0;
+ px = (len1 - len2);
+ for (p = 0; p <= px; p++)
+ {
+ if ((*p2 == *p1) && (strncmp(p1, p2, len2) == 0))
+ {
+ pos = p + 1;
+ break;
+ };
+ p1++;
};
- p1++;
- };
- return(pos);
-} /* textpos() */
+ return (pos);
+} /* textpos() */
/*
- * texteq - returns 1 iff arguments are equal
- * textne - returns 1 iff arguments are not equal
+ * texteq - returns 1 iff arguments are equal
+ * textne - returns 1 iff arguments are not equal
*/
bool
-texteq(struct varlena *arg1, struct varlena *arg2)
+texteq(struct varlena * arg1, struct varlena * arg2)
{
- register int len;
- register char *a1p, *a2p;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) NULL);
- if ((len = arg1->vl_len) != arg2->vl_len)
- return((bool) 0);
- a1p = arg1->vl_dat;
- a2p = arg2->vl_dat;
- /*
- * Varlenas are stored as the total size (data + size variable)
- * followed by the data.
- * Use VARHDRSZ instead of explicit sizeof() - thomas 1997-07-10
- */
- len -= VARHDRSZ;
- while (len-- != 0)
- if (*a1p++ != *a2p++)
- return((bool) 0);
- return((bool) 1);
-} /* texteq() */
+ register int len;
+ register char *a1p,
+ *a2p;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) NULL);
+ if ((len = arg1->vl_len) != arg2->vl_len)
+ return ((bool) 0);
+ a1p = arg1->vl_dat;
+ a2p = arg2->vl_dat;
+
+ /*
+ * Varlenas are stored as the total size (data + size variable)
+ * followed by the data. Use VARHDRSZ instead of explicit sizeof() -
+ * thomas 1997-07-10
+ */
+ len -= VARHDRSZ;
+ while (len-- != 0)
+ if (*a1p++ != *a2p++)
+ return ((bool) 0);
+ return ((bool) 1);
+} /* texteq() */
bool
-textne(struct varlena *arg1, struct varlena *arg2)
+textne(struct varlena * arg1, struct varlena * arg2)
{
- return((bool) !texteq(arg1, arg2));
+ return ((bool) ! texteq(arg1, arg2));
}
/* text_lt()
* Comparison function for text strings.
* Includes locale support, but must copy strings to temporary memory
- * to allow null-termination for inputs to strcoll().
+ * to allow null-termination for inputs to strcoll().
* XXX HACK code for textlen() indicates that there can be embedded nulls
- * but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
+ * but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
*/
bool
-text_lt(struct varlena *arg1, struct varlena *arg2)
+text_lt(struct varlena * arg1, struct varlena * arg2)
{
- bool result;
+ bool result;
#ifdef USE_LOCALE
- int cval;
+ int cval;
+
#endif
- int len;
- unsigned char *a1p, *a2p;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) FALSE);
-
- len = (((VARSIZE(arg1) <= VARSIZE(arg2))? VARSIZE(arg1): VARSIZE(arg2))-VARHDRSZ);
-
+ int len;
+ unsigned char *a1p,
+ *a2p;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) FALSE);
+
+ len = (((VARSIZE(arg1) <= VARSIZE(arg2)) ? VARSIZE(arg1) : VARSIZE(arg2)) - VARHDRSZ);
+
#ifdef USE_LOCALE
- a1p = (unsigned char *) palloc (len+1);
- a2p = (unsigned char *) palloc (len+1);
+ a1p = (unsigned char *) palloc(len + 1);
+ a2p = (unsigned char *) palloc(len + 1);
- memcpy(a1p, VARDATA(arg1), len);
- *(a1p+len) = '\0';
- memcpy(a2p, VARDATA(arg2), len);
- *(a2p+len) = '\0';
+ memcpy(a1p, VARDATA(arg1), len);
+ *(a1p + len) = '\0';
+ memcpy(a2p, VARDATA(arg2), len);
+ *(a2p + len) = '\0';
- cval = strcoll(a1p,a2p);
- result = ((cval < 0) || ((cval == 0) && (VARSIZE(arg1) < VARSIZE(arg2))));
+ cval = strcoll(a1p, a2p);
+ result = ((cval < 0) || ((cval == 0) && (VARSIZE(arg1) < VARSIZE(arg2))));
- pfree (a1p);
- pfree (a2p);
+ pfree(a1p);
+ pfree(a2p);
#else
- a1p = (unsigned char *)VARDATA(arg1);
- a2p = (unsigned char *)VARDATA(arg2);
-
- while (len != 0 && *a1p == *a2p) {
- a1p++;
- a2p++;
- len--;
- };
-
- result = (len? (*a1p < *a2p): (VARSIZE(arg1) < VARSIZE(arg2)));
+ a1p = (unsigned char *) VARDATA(arg1);
+ a2p = (unsigned char *) VARDATA(arg2);
+
+ while (len != 0 && *a1p == *a2p)
+ {
+ a1p++;
+ a2p++;
+ len--;
+ };
+
+ result = (len ? (*a1p < *a2p) : (VARSIZE(arg1) < VARSIZE(arg2)));
#endif
- return(result);
-} /* text_lt() */
+ return (result);
+} /* text_lt() */
/* text_le()
* Comparison function for text strings.
* Includes locale support, but must copy strings to temporary memory
- * to allow null-termination for inputs to strcoll().
+ * to allow null-termination for inputs to strcoll().
* XXX HACK code for textlen() indicates that there can be embedded nulls
- * but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
+ * but it appears that most routines (incl. this one) assume not! - tgl 97/04/07
*/
bool
-text_le(struct varlena *arg1, struct varlena *arg2)
+text_le(struct varlena * arg1, struct varlena * arg2)
{
- bool result;
+ bool result;
#ifdef USE_LOCALE
- int cval;
+ int cval;
+
#endif
- int len;
- unsigned char *a1p, *a2p;
-
- if (arg1 == NULL || arg2 == NULL)
- return((bool) 0);
-
- len = (((VARSIZE(arg1) <= VARSIZE(arg2))? VARSIZE(arg1): VARSIZE(arg2))-VARHDRSZ);
-
+ int len;
+ unsigned char *a1p,
+ *a2p;
+
+ if (arg1 == NULL || arg2 == NULL)
+ return ((bool) 0);
+
+ len = (((VARSIZE(arg1) <= VARSIZE(arg2)) ? VARSIZE(arg1) : VARSIZE(arg2)) - VARHDRSZ);
+
#ifdef USE_LOCALE
- a1p = (unsigned char *) palloc (len+1);
- a2p = (unsigned char *) palloc (len+1);
+ a1p = (unsigned char *) palloc(len + 1);
+ a2p = (unsigned char *) palloc(len + 1);
- memcpy(a1p, VARDATA(arg1), len);
- *(a1p+len) = '\0';
- memcpy(a2p, VARDATA(arg2), len);
- *(a2p+len) = '\0';
+ memcpy(a1p, VARDATA(arg1), len);
+ *(a1p + len) = '\0';
+ memcpy(a2p, VARDATA(arg2), len);
+ *(a2p + len) = '\0';
- cval = strcoll(a1p,a2p);
- result = ((cval < 0) || ((cval == 0) && (VARSIZE(arg1) <= VARSIZE(arg2))));
+ cval = strcoll(a1p, a2p);
+ result = ((cval < 0) || ((cval == 0) && (VARSIZE(arg1) <= VARSIZE(arg2))));
- pfree (a1p);
- pfree (a2p);
+ pfree(a1p);
+ pfree(a2p);
#else
- a1p = (unsigned char *)VARDATA(arg1);
- a2p = (unsigned char *)VARDATA(arg2);
-
- while (len != 0 && *a1p == *a2p) {
- a1p++;
- a2p++;
- len--;
- };
-
- result = (len? (*a1p <= *a2p): (VARSIZE(arg1) <= VARSIZE(arg2)));
+ a1p = (unsigned char *) VARDATA(arg1);
+ a2p = (unsigned char *) VARDATA(arg2);
+
+ while (len != 0 && *a1p == *a2p)
+ {
+ a1p++;
+ a2p++;
+ len--;
+ };
+
+ result = (len ? (*a1p <= *a2p) : (VARSIZE(arg1) <= VARSIZE(arg2)));
#endif
- return(result);
-} /* text_le() */
+ return (result);
+} /* text_le() */
bool
-text_gt(struct varlena *arg1, struct varlena *arg2)
+text_gt(struct varlena * arg1, struct varlena * arg2)
{
- return ((bool) !text_le(arg1, arg2));
+ return ((bool) ! text_le(arg1, arg2));
}
bool
-text_ge(struct varlena *arg1, struct varlena *arg2)
+text_ge(struct varlena * arg1, struct varlena * arg2)
{
- return ((bool) !text_lt(arg1, arg2));
+ return ((bool) ! text_lt(arg1, arg2));
}
/*-------------------------------------------------------------
@@ -453,13 +482,13 @@ text_ge(struct varlena *arg1, struct varlena *arg2)
*-------------------------------------------------------------
*/
int32
-byteaGetSize(struct varlena *v)
+byteaGetSize(struct varlena * v)
{
- register int len;
-
- len = v->vl_len - sizeof(v->vl_len);
-
- return(len);
+ register int len;
+
+ len = v->vl_len - sizeof(v->vl_len);
+
+ return (len);
}
/*-------------------------------------------------------------
@@ -471,21 +500,22 @@ byteaGetSize(struct varlena *v)
*-------------------------------------------------------------
*/
int32
-byteaGetByte(struct varlena *v, int32 n)
+byteaGetByte(struct varlena * v, int32 n)
{
- int len;
- int byte;
-
- len = byteaGetSize(v);
-
- if (n>=len) {
- elog(WARN, "byteaGetByte: index (=%d) out of range [0..%d]",
- n,len-1);
- }
-
- byte = (unsigned char) (v->vl_dat[n]);
-
- return((int32) byte);
+ int len;
+ int byte;
+
+ len = byteaGetSize(v);
+
+ if (n >= len)
+ {
+ elog(WARN, "byteaGetByte: index (=%d) out of range [0..%d]",
+ n, len - 1);
+ }
+
+ byte = (unsigned char) (v->vl_dat[n]);
+
+ return ((int32) byte);
}
/*-------------------------------------------------------------
@@ -498,22 +528,27 @@ byteaGetByte(struct varlena *v, int32 n)
*-------------------------------------------------------------
*/
int32
-byteaGetBit(struct varlena *v, int32 n)
+byteaGetBit(struct varlena * v, int32 n)
{
- int byteNo, bitNo;
- int byte;
-
- byteNo = n/8;
- bitNo = n%8;
-
- byte = byteaGetByte(v, byteNo);
-
- if (byte & (1<<bitNo)) {
- return((int32)1);
- } else {
- return((int32)0);
- }
+ int byteNo,
+ bitNo;
+ int byte;
+
+ byteNo = n / 8;
+ bitNo = n % 8;
+
+ byte = byteaGetByte(v, byteNo);
+
+ if (byte & (1 << bitNo))
+ {
+ return ((int32) 1);
+ }
+ else
+ {
+ return ((int32) 0);
+ }
}
+
/*-------------------------------------------------------------
* byteaSetByte
*
@@ -523,35 +558,37 @@ byteaGetBit(struct varlena *v, int32 n)
*-------------------------------------------------------------
*/
struct varlena *
-byteaSetByte(struct varlena *v, int32 n, int32 newByte)
+byteaSetByte(struct varlena * v, int32 n, int32 newByte)
{
- int len;
- struct varlena *res;
-
- len = byteaGetSize(v);
-
- if (n>=len) {
- elog(WARN,
- "byteaSetByte: index (=%d) out of range [0..%d]",
- n, len-1);
- }
-
- /*
- * Make a copy of the original varlena.
- */
- res = (struct varlena *) palloc(VARSIZE(v));
- if (res==NULL) {
- elog(WARN, "byteaSetByte: Out of memory (%d bytes requested)",
- VARSIZE(v));
- }
- memmove((char *)res, (char *)v, VARSIZE(v));
-
- /*
- * Now set the byte.
- */
- res->vl_dat[n] = newByte;
-
- return(res);
+ int len;
+ struct varlena *res;
+
+ len = byteaGetSize(v);
+
+ if (n >= len)
+ {
+ elog(WARN,
+ "byteaSetByte: index (=%d) out of range [0..%d]",
+ n, len - 1);
+ }
+
+ /*
+ * Make a copy of the original varlena.
+ */
+ res = (struct varlena *) palloc(VARSIZE(v));
+ if (res == NULL)
+ {
+ elog(WARN, "byteaSetByte: Out of memory (%d bytes requested)",
+ VARSIZE(v));
+ }
+ memmove((char *) res, (char *) v, VARSIZE(v));
+
+ /*
+ * Now set the byte.
+ */
+ res->vl_dat[n] = newByte;
+
+ return (res);
}
/*-------------------------------------------------------------
@@ -563,39 +600,45 @@ byteaSetByte(struct varlena *v, int32 n, int32 newByte)
*-------------------------------------------------------------
*/
struct varlena *
-byteaSetBit(struct varlena *v, int32 n, int32 newBit)
+byteaSetBit(struct varlena * v, int32 n, int32 newBit)
{
- struct varlena *res;
- int oldByte, newByte;
- int byteNo, bitNo;
-
- /*
- * sanity check!
- */
- if (newBit != 0 && newBit != 1) {
- elog(WARN, "byteaSetByte: new bit must be 0 or 1");
- }
-
- /*
- * get the byte where the bit we want is stored.
- */
- byteNo = n / 8;
- bitNo = n % 8;
- oldByte = byteaGetByte(v, byteNo);
-
- /*
- * calculate the new value for that byte
- */
- if (newBit == 0) {
- newByte = oldByte & (~(1<<bitNo));
- } else {
- newByte = oldByte | (1<<bitNo);
- }
-
- /*
- * NOTE: 'byteaSetByte' creates a copy of 'v' & sets the byte.
- */
- res = byteaSetByte(v, byteNo, newByte);
-
- return(res);
+ struct varlena *res;
+ int oldByte,
+ newByte;
+ int byteNo,
+ bitNo;
+
+ /*
+ * sanity check!
+ */
+ if (newBit != 0 && newBit != 1)
+ {
+ elog(WARN, "byteaSetByte: new bit must be 0 or 1");
+ }
+
+ /*
+ * get the byte where the bit we want is stored.
+ */
+ byteNo = n / 8;
+ bitNo = n % 8;
+ oldByte = byteaGetByte(v, byteNo);
+
+ /*
+ * calculate the new value for that byte
+ */
+ if (newBit == 0)
+ {
+ newByte = oldByte & (~(1 << bitNo));
+ }
+ else
+ {
+ newByte = oldByte | (1 << bitNo);
+ }
+
+ /*
+ * NOTE: 'byteaSetByte' creates a copy of 'v' & sets the byte.
+ */
+ res = byteaSetByte(v, byteNo, newByte);
+
+ return (res);
}
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index aee835943e3..3edddd3c1aa 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* catcache.c--
- * System catalog cache for tuples matching a key.
+ * System catalog cache for tuples matching a key.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.10 1997/08/26 19:24:36 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/catcache.c,v 1.11 1997/09/07 04:52:56 momjian Exp $
*
* Notes:
- * XXX This needs to use exception.h to handle recovery when
- * an abort occurs during DisableCache.
- *
+ * XXX This needs to use exception.h to handle recovery when
+ * an abort occurs during DisableCache.
+ *
*-------------------------------------------------------------------------
*/
#include <string.h>
@@ -26,7 +26,7 @@
#include "miscadmin.h"
#include "utils/portal.h"
#include "utils/catcache.h"
-#include "fmgr.h" /* for F_BOOLEQ, etc. DANGER */
+#include "fmgr.h" /* for F_BOOLEQ, etc. DANGER */
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
@@ -34,29 +34,31 @@
#include "catalog/pg_type.h" /* for OID of int28 type */
#include "lib/dllist.h"
-static void CatCacheRemoveCTup(CatCache *cache, Dlelem *e);
-static Index CatalogCacheComputeHashIndex(struct catcache *cacheInP);
-static Index CatalogCacheComputeTupleHashIndex(struct catcache *cacheInOutP,
- Relation relation, HeapTuple tuple);
-static void CatalogCacheInitializeCache(struct catcache *cache,
- Relation relation);
-static long comphash(long l, char *v);
+static void CatCacheRemoveCTup(CatCache * cache, Dlelem * e);
+static Index CatalogCacheComputeHashIndex(struct catcache * cacheInP);
+static Index
+CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
+ Relation relation, HeapTuple tuple);
+static void
+CatalogCacheInitializeCache(struct catcache * cache,
+ Relation relation);
+static long comphash(long l, char *v);
/* ----------------
- * variables, macros and other stuff
+ * variables, macros and other stuff
*
- * note CCSIZE allocates 51 buckets .. one was already allocated in
- * the catcache structure.
+ * note CCSIZE allocates 51 buckets .. one was already allocated in
+ * the catcache structure.
* ----------------
*/
#ifdef CACHEDEBUG
-#define CACHE1_elog(a,b) elog(a,b)
-#define CACHE2_elog(a,b,c) elog(a,b,c)
-#define CACHE3_elog(a,b,c,d) elog(a,b,c,d)
-#define CACHE4_elog(a,b,c,d,e) elog(a,b,c,d,e)
-#define CACHE5_elog(a,b,c,d,e,f) elog(a,b,c,d,e,f)
-#define CACHE6_elog(a,b,c,d,e,f,g) elog(a,b,c,d,e,f,g)
+#define CACHE1_elog(a,b) elog(a,b)
+#define CACHE2_elog(a,b,c) elog(a,b,c)
+#define CACHE3_elog(a,b,c,d) elog(a,b,c,d)
+#define CACHE4_elog(a,b,c,d,e) elog(a,b,c,d,e)
+#define CACHE5_elog(a,b,c,d,e,f) elog(a,b,c,d,e,f)
+#define CACHE6_elog(a,b,c,d,e,f,g) elog(a,b,c,d,e,f,g)
#else
#define CACHE1_elog(a,b)
#define CACHE2_elog(a,b,c)
@@ -66,209 +68,217 @@ static long comphash(long l, char *v);
#define CACHE6_elog(a,b,c,d,e,f,g)
#endif
-CatCache *Caches = NULL;
+CatCache *Caches = NULL;
GlobalMemory CacheCxt;
-static int DisableCache;
+static int DisableCache;
/* ----------------
- * EQPROC is used in CatalogCacheInitializeCache
- * XXX this should be replaced by catalog lookups soon
+ * EQPROC is used in CatalogCacheInitializeCache
+ * XXX this should be replaced by catalog lookups soon
* ----------------
*/
-static long eqproc[] = {
- F_BOOLEQ, 0l, F_CHAREQ, F_CHAR16EQ, 0l,
- F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, 0l, F_TEXTEQ,
- F_OIDEQ, 0l, 0l, 0l, F_OID8EQ
+static long eqproc[] = {
+ F_BOOLEQ, 0l, F_CHAREQ, F_CHAR16EQ, 0l,
+ F_INT2EQ, F_KEYFIRSTEQ, F_INT4EQ, 0l, F_TEXTEQ,
+ F_OIDEQ, 0l, 0l, 0l, F_OID8EQ
};
-#define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-16]
+#define EQPROC(SYSTEMTYPEOID) eqproc[(SYSTEMTYPEOID)-16]
/* ----------------------------------------------------------------
- * internal support functions
+ * internal support functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * CatalogCacheInitializeCache
+ * CatalogCacheInitializeCache
* --------------------------------
*/
#ifdef CACHEDEBUG
#define CatalogCacheInitializeCache_DEBUG1 \
- elog(DEBUG, "CatalogCacheInitializeCache: cache @%08lx", cache); \
- if (relation) \
- elog(DEBUG, "CatalogCacheInitializeCache: called w/relation(inval)"); \
- else \
- elog(DEBUG, "CatalogCacheInitializeCache: called w/relname %s", \
- cache->cc_relname)
+ elog(DEBUG, "CatalogCacheInitializeCache: cache @%08lx", cache); \
+ if (relation) \
+ elog(DEBUG, "CatalogCacheInitializeCache: called w/relation(inval)"); \
+ else \
+ elog(DEBUG, "CatalogCacheInitializeCache: called w/relname %s", \
+ cache->cc_relname)
#define CatalogCacheInitializeCache_DEBUG2 \
- if (cache->cc_key[i] > 0) { \
- elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d, %d", \
- i+1, cache->cc_nkeys, cache->cc_key[i], \
- relation->rd_att->attrs[cache->cc_key[i] - 1]->attlen); \
- } else { \
- elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d", \
- i+1, cache->cc_nkeys, cache->cc_key[i]); \
- }
+ if (cache->cc_key[i] > 0) { \
+ elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d, %d", \
+ i+1, cache->cc_nkeys, cache->cc_key[i], \
+ relation->rd_att->attrs[cache->cc_key[i] - 1]->attlen); \
+ } else { \
+ elog(DEBUG, "CatalogCacheInitializeCache: load %d/%d w/%d", \
+ i+1, cache->cc_nkeys, cache->cc_key[i]); \
+ }
#else
#define CatalogCacheInitializeCache_DEBUG1
#define CatalogCacheInitializeCache_DEBUG2
#endif
static void
-CatalogCacheInitializeCache(struct catcache *cache,
- Relation relation)
+CatalogCacheInitializeCache(struct catcache * cache,
+ Relation relation)
{
- MemoryContext oldcxt;
- short didopen = 0;
- short i;
- TupleDesc tupdesc;
-
- CatalogCacheInitializeCache_DEBUG1;
-
- /* ----------------
- * first switch to the cache context so our allocations
- * do not vanish at the end of a transaction
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * If no relation was passed we must open it to get access to
- * its fields. If one of the other caches has already opened
- * it we use heap_open() instead of heap_openr()
- * ----------------
- */
- if (! RelationIsValid(relation)) {
- struct catcache *cp;
+ MemoryContext oldcxt;
+ short didopen = 0;
+ short i;
+ TupleDesc tupdesc;
+
+ CatalogCacheInitializeCache_DEBUG1;
+
/* ----------------
- * scan the caches to see if any other cache has opened the relation
+ * first switch to the cache context so our allocations
+ * do not vanish at the end of a transaction
* ----------------
*/
- for (cp = Caches; cp; cp = cp->cc_next) {
- if (strncmp(cp->cc_relname, cache->cc_relname, NAMEDATALEN) == 0) {
- if (cp->relationId != InvalidOid)
- break;
- }
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * If no relation was passed we must open it to get access to
+ * its fields. If one of the other caches has already opened
+ * it we use heap_open() instead of heap_openr()
+ * ----------------
+ */
+ if (!RelationIsValid(relation))
+ {
+ struct catcache *cp;
+
+ /* ----------------
+ * scan the caches to see if any other cache has opened the relation
+ * ----------------
+ */
+ for (cp = Caches; cp; cp = cp->cc_next)
+ {
+ if (strncmp(cp->cc_relname, cache->cc_relname, NAMEDATALEN) == 0)
+ {
+ if (cp->relationId != InvalidOid)
+ break;
+ }
+ }
+
+ /* ----------------
+ * open the relation by name or by id
+ * ----------------
+ */
+ if (cp)
+ relation = heap_open(cp->relationId);
+ else
+ {
+ relation = heap_openr(cache->cc_relname);
+ }
+
+ didopen = 1;
}
-
+
/* ----------------
- * open the relation by name or by id
+ * initialize the cache's relation id
* ----------------
*/
- if (cp)
- relation = heap_open(cp->relationId);
- else
- {
- relation = heap_openr(cache->cc_relname);
- }
-
- didopen = 1;
- }
-
- /* ----------------
- * initialize the cache's relation id
- * ----------------
- */
- Assert(RelationIsValid(relation));
- cache->relationId = RelationGetRelationId(relation);
- tupdesc = cache->cc_tupdesc = RelationGetTupleDescriptor(relation);
-
- CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %d, %d keys",
- cache->relationId, cache->cc_nkeys);
-
- /* ----------------
- * initialize cache's key information
- * ----------------
- */
- for (i = 0; i < cache->cc_nkeys; ++i) {
- CatalogCacheInitializeCache_DEBUG2;
-
- if (cache->cc_key[i] > 0) {
-
- /*
- * Yoiks. The implementation of the hashing code and the
- * implementation of int28's are at loggerheads. The right
- * thing to do is to throw out the implementation of int28's
- * altogether; until that happens, we do the right thing here
- * to guarantee that the hash key generator doesn't try to
- * dereference an int2 by mistake.
- */
-
- if (tupdesc->attrs[cache->cc_key[i]-1]->atttypid == INT28OID)
- cache->cc_klen[i] = sizeof (short);
- else
- cache->cc_klen[i] = tupdesc->attrs[cache->cc_key[i]-1]->attlen;
-
- cache->cc_skey[i].sk_procedure =
- EQPROC(tupdesc->attrs[cache->cc_key[i]-1]->atttypid);
-
- fmgr_info(cache->cc_skey[i].sk_procedure,
- (func_ptr *) &cache->cc_skey[i].sk_func,
- (int *) &cache->cc_skey[i].sk_nargs);
-
- CACHE5_elog(DEBUG, "CatalogCacheInit %16s %d %d %x",
- &relation->rd_rel->relname,
- i,
- tupdesc->attrs[ cache->cc_key[i]-1 ]->attlen,
- cache);
+ Assert(RelationIsValid(relation));
+ cache->relationId = RelationGetRelationId(relation);
+ tupdesc = cache->cc_tupdesc = RelationGetTupleDescriptor(relation);
+
+ CACHE3_elog(DEBUG, "CatalogCacheInitializeCache: relid %d, %d keys",
+ cache->relationId, cache->cc_nkeys);
+
+ /* ----------------
+ * initialize cache's key information
+ * ----------------
+ */
+ for (i = 0; i < cache->cc_nkeys; ++i)
+ {
+ CatalogCacheInitializeCache_DEBUG2;
+
+ if (cache->cc_key[i] > 0)
+ {
+
+ /*
+ * Yoiks. The implementation of the hashing code and the
+ * implementation of int28's are at loggerheads. The right
+ * thing to do is to throw out the implementation of int28's
+ * altogether; until that happens, we do the right thing here
+ * to guarantee that the hash key generator doesn't try to
+ * dereference an int2 by mistake.
+ */
+
+ if (tupdesc->attrs[cache->cc_key[i] - 1]->atttypid == INT28OID)
+ cache->cc_klen[i] = sizeof(short);
+ else
+ cache->cc_klen[i] = tupdesc->attrs[cache->cc_key[i] - 1]->attlen;
+
+ cache->cc_skey[i].sk_procedure =
+ EQPROC(tupdesc->attrs[cache->cc_key[i] - 1]->atttypid);
+
+ fmgr_info(cache->cc_skey[i].sk_procedure,
+ (func_ptr *) & cache->cc_skey[i].sk_func,
+ (int *) &cache->cc_skey[i].sk_nargs);
+
+ CACHE5_elog(DEBUG, "CatalogCacheInit %16s %d %d %x",
+ &relation->rd_rel->relname,
+ i,
+ tupdesc->attrs[cache->cc_key[i] - 1]->attlen,
+ cache);
+ }
}
- }
-
- /* ----------------
- * close the relation if we opened it
- * ----------------
- */
- if (didopen)
- heap_close(relation);
-
- /* ----------------
- * initialize index information for the cache. this
- * should only be done once per cache.
- * ----------------
- */
- if (cache->cc_indname != NULL && cache->indexId == InvalidOid)
+
+ /* ----------------
+ * close the relation if we opened it
+ * ----------------
+ */
+ if (didopen)
+ heap_close(relation);
+
+ /* ----------------
+ * initialize index information for the cache. this
+ * should only be done once per cache.
+ * ----------------
+ */
+ if (cache->cc_indname != NULL && cache->indexId == InvalidOid)
{
- if (RelationGetRelationTupleForm(relation)->relhasindex)
+ if (RelationGetRelationTupleForm(relation)->relhasindex)
{
- /*
- * If the index doesn't exist we are in trouble.
- */
- relation = index_openr( cache->cc_indname);
- Assert(relation);
- cache->indexId = RelationGetRelationId(relation);
- index_close(relation);
+
+ /*
+ * If the index doesn't exist we are in trouble.
+ */
+ relation = index_openr(cache->cc_indname);
+ Assert(relation);
+ cache->indexId = RelationGetRelationId(relation);
+ index_close(relation);
}
- else
- cache->cc_indname = NULL;
+ else
+ cache->cc_indname = NULL;
}
-
- /* ----------------
- * return to the proper memory context
- * ----------------
- */
- MemoryContextSwitchTo(oldcxt);
+
+ /* ----------------
+ * return to the proper memory context
+ * ----------------
+ */
+ MemoryContextSwitchTo(oldcxt);
}
/* --------------------------------
- * CatalogCacheSetId
+ * CatalogCacheSetId
*
- * XXX temporary function
+ * XXX temporary function
* --------------------------------
*/
#ifdef NOT_USED
void
-CatalogCacheSetId(CatCache *cacheInOutP, int id)
+CatalogCacheSetId(CatCache * cacheInOutP, int id)
{
- Assert(id == InvalidCatalogCacheId || id >= 0);
- cacheInOutP->id = id;
+ Assert(id == InvalidCatalogCacheId || id >= 0);
+ cacheInOutP->id = id;
}
+
#endif
/* ----------------
* comphash --
- * Compute a hash value, somehow.
+ * Compute a hash value, somehow.
*
* XXX explain algorithm here.
*
@@ -279,798 +289,846 @@ CatalogCacheSetId(CatCache *cacheInOutP, int id)
static long
comphash(long l, register char *v)
{
- long i;
- NameData n;
-
- CACHE3_elog(DEBUG, "comphash (%d,%x)", l, v);
-
- switch (l) {
- case 1:
- case 2:
- case 4:
- return((long) v);
- }
-
- if (l == NAMEDATALEN) {
- /* if it's a name, make sure that the values
- are null-padded.
-
- Note that this other fixed-length types can also have
- the same typelen so this may break them - XXX
- */
- namestrcpy(&n,v);
- v = n.data;
- } else
- if (l < 0)
- l = VARSIZE(v);
-
- i = 0;
- while (l--) {
- i += *v++;
- }
- return(i);
+ long i;
+ NameData n;
+
+ CACHE3_elog(DEBUG, "comphash (%d,%x)", l, v);
+
+ switch (l)
+ {
+ case 1:
+ case 2:
+ case 4:
+ return ((long) v);
+ }
+
+ if (l == NAMEDATALEN)
+ {
+
+ /*
+ * if it's a name, make sure that the values are null-padded.
+ *
+ * Note that this other fixed-length types can also have the same
+ * typelen so this may break them - XXX
+ */
+ namestrcpy(&n, v);
+ v = n.data;
+ }
+ else if (l < 0)
+ l = VARSIZE(v);
+
+ i = 0;
+ while (l--)
+ {
+ i += *v++;
+ }
+ return (i);
}
/* --------------------------------
- * CatalogCacheComputeHashIndex
+ * CatalogCacheComputeHashIndex
* --------------------------------
*/
-static Index
-CatalogCacheComputeHashIndex(struct catcache *cacheInP)
+static Index
+CatalogCacheComputeHashIndex(struct catcache * cacheInP)
{
- Index hashIndex;
- hashIndex = 0x0;
- CACHE6_elog(DEBUG,"CatalogCacheComputeHashIndex %s %d %d %d %x",
- cacheInP->cc_relname,
- cacheInP->cc_nkeys,
- cacheInP->cc_klen[0],
- cacheInP->cc_klen[1],
- cacheInP);
-
- switch (cacheInP->cc_nkeys) {
- case 4:
- hashIndex ^= comphash(cacheInP->cc_klen[3],
- (char*)cacheInP->cc_skey[3].sk_argument) << 9;
- /* FALLTHROUGH */
- case 3:
- hashIndex ^= comphash(cacheInP->cc_klen[2],
- (char*)cacheInP->cc_skey[2].sk_argument) << 6;
- /* FALLTHROUGH */
- case 2:
- hashIndex ^= comphash(cacheInP->cc_klen[1],
- (char*)cacheInP->cc_skey[1].sk_argument) << 3;
- /* FALLTHROUGH */
- case 1:
- hashIndex ^= comphash(cacheInP->cc_klen[0],
- (char*)cacheInP->cc_skey[0].sk_argument);
- break;
- default:
- elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);
- break;
- }
- hashIndex %= cacheInP->cc_size;
- return (hashIndex);
+ Index hashIndex;
+
+ hashIndex = 0x0;
+ CACHE6_elog(DEBUG, "CatalogCacheComputeHashIndex %s %d %d %d %x",
+ cacheInP->cc_relname,
+ cacheInP->cc_nkeys,
+ cacheInP->cc_klen[0],
+ cacheInP->cc_klen[1],
+ cacheInP);
+
+ switch (cacheInP->cc_nkeys)
+ {
+ case 4:
+ hashIndex ^= comphash(cacheInP->cc_klen[3],
+ (char *) cacheInP->cc_skey[3].sk_argument) << 9;
+ /* FALLTHROUGH */
+ case 3:
+ hashIndex ^= comphash(cacheInP->cc_klen[2],
+ (char *) cacheInP->cc_skey[2].sk_argument) << 6;
+ /* FALLTHROUGH */
+ case 2:
+ hashIndex ^= comphash(cacheInP->cc_klen[1],
+ (char *) cacheInP->cc_skey[1].sk_argument) << 3;
+ /* FALLTHROUGH */
+ case 1:
+ hashIndex ^= comphash(cacheInP->cc_klen[0],
+ (char *) cacheInP->cc_skey[0].sk_argument);
+ break;
+ default:
+ elog(FATAL, "CCComputeHashIndex: %d cc_nkeys", cacheInP->cc_nkeys);
+ break;
+ }
+ hashIndex %= cacheInP->cc_size;
+ return (hashIndex);
}
/* --------------------------------
- * CatalogCacheComputeTupleHashIndex
+ * CatalogCacheComputeTupleHashIndex
* --------------------------------
*/
-static Index
-CatalogCacheComputeTupleHashIndex(struct catcache *cacheInOutP,
- Relation relation,
- HeapTuple tuple)
+static Index
+CatalogCacheComputeTupleHashIndex(struct catcache * cacheInOutP,
+ Relation relation,
+ HeapTuple tuple)
{
- bool isNull = '\0';
- if (cacheInOutP->relationId == InvalidOid)
- CatalogCacheInitializeCache(cacheInOutP, relation);
- switch (cacheInOutP->cc_nkeys) {
- case 4:
- cacheInOutP->cc_skey[3].sk_argument =
- (cacheInOutP->cc_key[3] == ObjectIdAttributeNumber)
- ? (Datum)tuple->t_oid
- : (Datum)fastgetattr(tuple,
- cacheInOutP->cc_key[3],
- RelationGetTupleDescriptor(relation),
- &isNull);
- Assert(!isNull);
- /* FALLTHROUGH */
- case 3:
- cacheInOutP->cc_skey[2].sk_argument =
- (cacheInOutP->cc_key[2] == ObjectIdAttributeNumber)
- ? (Datum)tuple->t_oid
- : (Datum)fastgetattr(tuple,
- cacheInOutP->cc_key[2],
- RelationGetTupleDescriptor(relation),
- &isNull);
- Assert(!isNull);
- /* FALLTHROUGH */
- case 2:
- cacheInOutP->cc_skey[1].sk_argument =
- (cacheInOutP->cc_key[1] == ObjectIdAttributeNumber)
- ? (Datum)tuple->t_oid
- : (Datum)fastgetattr(tuple,
- cacheInOutP->cc_key[1],
- RelationGetTupleDescriptor(relation),
- &isNull);
- Assert(!isNull);
- /* FALLTHROUGH */
- case 1:
- cacheInOutP->cc_skey[0].sk_argument =
- (cacheInOutP->cc_key[0] == ObjectIdAttributeNumber)
- ? (Datum)tuple->t_oid
- : (Datum)fastgetattr(tuple,
- cacheInOutP->cc_key[0],
- RelationGetTupleDescriptor(relation),
- &isNull);
- Assert(!isNull);
- break;
- default:
- elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",
- cacheInOutP->cc_nkeys
- );
- break;
- }
-
- return
- CatalogCacheComputeHashIndex(cacheInOutP);
+ bool isNull = '\0';
+
+ if (cacheInOutP->relationId == InvalidOid)
+ CatalogCacheInitializeCache(cacheInOutP, relation);
+ switch (cacheInOutP->cc_nkeys)
+ {
+ case 4:
+ cacheInOutP->cc_skey[3].sk_argument =
+ (cacheInOutP->cc_key[3] == ObjectIdAttributeNumber)
+ ? (Datum) tuple->t_oid
+ : (Datum) fastgetattr(tuple,
+ cacheInOutP->cc_key[3],
+ RelationGetTupleDescriptor(relation),
+ &isNull);
+ Assert(!isNull);
+ /* FALLTHROUGH */
+ case 3:
+ cacheInOutP->cc_skey[2].sk_argument =
+ (cacheInOutP->cc_key[2] == ObjectIdAttributeNumber)
+ ? (Datum) tuple->t_oid
+ : (Datum) fastgetattr(tuple,
+ cacheInOutP->cc_key[2],
+ RelationGetTupleDescriptor(relation),
+ &isNull);
+ Assert(!isNull);
+ /* FALLTHROUGH */
+ case 2:
+ cacheInOutP->cc_skey[1].sk_argument =
+ (cacheInOutP->cc_key[1] == ObjectIdAttributeNumber)
+ ? (Datum) tuple->t_oid
+ : (Datum) fastgetattr(tuple,
+ cacheInOutP->cc_key[1],
+ RelationGetTupleDescriptor(relation),
+ &isNull);
+ Assert(!isNull);
+ /* FALLTHROUGH */
+ case 1:
+ cacheInOutP->cc_skey[0].sk_argument =
+ (cacheInOutP->cc_key[0] == ObjectIdAttributeNumber)
+ ? (Datum) tuple->t_oid
+ : (Datum) fastgetattr(tuple,
+ cacheInOutP->cc_key[0],
+ RelationGetTupleDescriptor(relation),
+ &isNull);
+ Assert(!isNull);
+ break;
+ default:
+ elog(FATAL, "CCComputeTupleHashIndex: %d cc_nkeys",
+ cacheInOutP->cc_nkeys
+ );
+ break;
+ }
+
+ return
+ CatalogCacheComputeHashIndex(cacheInOutP);
}
/* --------------------------------
- * CatCacheRemoveCTup
+ * CatCacheRemoveCTup
* --------------------------------
*/
static void
-CatCacheRemoveCTup(CatCache *cache, Dlelem *elt)
+CatCacheRemoveCTup(CatCache * cache, Dlelem * elt)
{
- CatCTup *ct;
- CatCTup *other_ct;
- Dlelem *other_elt;
-
- if (elt)
- ct = (CatCTup*) DLE_VAL(elt);
- else
- return;
-
- other_elt = ct->ct_node;
- other_ct = (CatCTup*)DLE_VAL(other_elt);
- DLRemove(other_elt);
- DLFreeElem(other_elt);
- free(other_ct);
- DLRemove(elt);
- DLFreeElem(elt);
- free(ct);
- --cache->cc_ntup;
+ CatCTup *ct;
+ CatCTup *other_ct;
+ Dlelem *other_elt;
+
+ if (elt)
+ ct = (CatCTup *) DLE_VAL(elt);
+ else
+ return;
+
+ other_elt = ct->ct_node;
+ other_ct = (CatCTup *) DLE_VAL(other_elt);
+ DLRemove(other_elt);
+ DLFreeElem(other_elt);
+ free(other_ct);
+ DLRemove(elt);
+ DLFreeElem(elt);
+ free(ct);
+ --cache->cc_ntup;
}
/* --------------------------------
- * CatalogCacheIdInvalidate()
+ * CatalogCacheIdInvalidate()
*
- * Invalidate a tuple given a cache id. In this case the id should always
- * be found (whether the cache has opened its relation or not). Of course,
- * if the cache has yet to open its relation, there will be no tuples so
- * no problem.
+ * Invalidate a tuple given a cache id. In this case the id should always
+ * be found (whether the cache has opened its relation or not). Of course,
+ * if the cache has yet to open its relation, there will be no tuples so
+ * no problem.
* --------------------------------
*/
void
-CatalogCacheIdInvalidate(int cacheId, /* XXX */
- Index hashIndex,
- ItemPointer pointer)
+CatalogCacheIdInvalidate(int cacheId, /* XXX */
+ Index hashIndex,
+ ItemPointer pointer)
{
- CatCache *ccp;
- CatCTup *ct;
- Dlelem *elt;
- MemoryContext oldcxt;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(hashIndex < NCCBUCK);
- Assert(ItemPointerIsValid(pointer));
- CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
-
- /* ----------------
- * switch to the cache context for our memory allocations
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * inspect every cache that could contain the tuple
- * ----------------
- */
- for (ccp = Caches; ccp; ccp = ccp->cc_next) {
- if (cacheId != ccp->id)
- continue;
+ CatCache *ccp;
+ CatCTup *ct;
+ Dlelem *elt;
+ MemoryContext oldcxt;
+
/* ----------------
- * inspect the hash bucket until we find a match or exhaust
+ * sanity checks
* ----------------
*/
- for (elt = DLGetHead(ccp->cc_cache[hashIndex]);
- elt;
- elt = DLGetSucc(elt))
- {
- ct = (CatCTup*) DLE_VAL(elt);
- if (ItemPointerEquals(pointer, &ct->ct_tup->t_ctid))
- break;
- }
-
+ Assert(hashIndex < NCCBUCK);
+ Assert(ItemPointerIsValid(pointer));
+ CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: called");
+
/* ----------------
- * if we found a matching tuple, invalidate it.
+ * switch to the cache context for our memory allocations
* ----------------
*/
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * inspect every cache that could contain the tuple
+ * ----------------
+ */
+ for (ccp = Caches; ccp; ccp = ccp->cc_next)
+ {
+ if (cacheId != ccp->id)
+ continue;
+ /* ----------------
+ * inspect the hash bucket until we find a match or exhaust
+ * ----------------
+ */
+ for (elt = DLGetHead(ccp->cc_cache[hashIndex]);
+ elt;
+ elt = DLGetSucc(elt))
+ {
+ ct = (CatCTup *) DLE_VAL(elt);
+ if (ItemPointerEquals(pointer, &ct->ct_tup->t_ctid))
+ break;
+ }
- if (elt) {
- CatCacheRemoveCTup(ccp, elt);
+ /* ----------------
+ * if we found a matching tuple, invalidate it.
+ * ----------------
+ */
- CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
+ if (elt)
+ {
+ CatCacheRemoveCTup(ccp, elt);
+
+ CACHE1_elog(DEBUG, "CatalogCacheIdInvalidate: invalidated");
+ }
+
+ if (cacheId != InvalidCatalogCacheId)
+ break;
}
-
- if (cacheId != InvalidCatalogCacheId)
- break;
- }
-
- /* ----------------
- * return to the proper memory context
- * ----------------
- */
- MemoryContextSwitchTo(oldcxt);
- /* sendpm('I', "Invalidated tuple"); */
+
+ /* ----------------
+ * return to the proper memory context
+ * ----------------
+ */
+ MemoryContextSwitchTo(oldcxt);
+ /* sendpm('I', "Invalidated tuple"); */
}
/* ----------------------------------------------------------------
- * public functions
+ * public functions
*
- * ResetSystemCache
- * InitIndexedSysCache
- * InitSysCache
- * SearchSysCache
- * RelationInvalidateCatalogCacheTuple
+ * ResetSystemCache
+ * InitIndexedSysCache
+ * InitSysCache
+ * SearchSysCache
+ * RelationInvalidateCatalogCacheTuple
* ----------------------------------------------------------------
*/
/* --------------------------------
- * ResetSystemCache
+ * ResetSystemCache
* --------------------------------
*/
void
ResetSystemCache()
{
- MemoryContext oldcxt;
- struct catcache *cache;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- CACHE1_elog(DEBUG, "ResetSystemCache called");
- if (DisableCache) {
- elog(WARN, "ResetSystemCache: Called while cache disabled");
- return;
- }
-
- /* ----------------
- * first switch to the cache context so our allocations
- * do not vanish at the end of a transaction
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * here we purge the contents of all the caches
- *
- * for each system cache
- * for each hash bucket
- * for each tuple in hash bucket
- * remove the tuple
- * ----------------
- */
- for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next) {
- int hash;
- for (hash = 0; hash < NCCBUCK; hash += 1) {
- Dlelem *elt, *nextelt;
- for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt) {
- nextelt = DLGetSucc(elt);
- CatCacheRemoveCTup(cache, elt);
- if (cache->cc_ntup == -1)
- elog(WARN, "ResetSystemCache: cc_ntup<0 (software error)");
- }
+ MemoryContext oldcxt;
+ struct catcache *cache;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ CACHE1_elog(DEBUG, "ResetSystemCache called");
+ if (DisableCache)
+ {
+ elog(WARN, "ResetSystemCache: Called while cache disabled");
+ return;
+ }
+
+ /* ----------------
+ * first switch to the cache context so our allocations
+ * do not vanish at the end of a transaction
+ * ----------------
+ */
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * here we purge the contents of all the caches
+ *
+ * for each system cache
+ * for each hash bucket
+ * for each tuple in hash bucket
+ * remove the tuple
+ * ----------------
+ */
+ for (cache = Caches; PointerIsValid(cache); cache = cache->cc_next)
+ {
+ int hash;
+
+ for (hash = 0; hash < NCCBUCK; hash += 1)
+ {
+ Dlelem *elt,
+ *nextelt;
+
+ for (elt = DLGetHead(cache->cc_cache[hash]); elt; elt = nextelt)
+ {
+ nextelt = DLGetSucc(elt);
+ CatCacheRemoveCTup(cache, elt);
+ if (cache->cc_ntup == -1)
+ elog(WARN, "ResetSystemCache: cc_ntup<0 (software error)");
+ }
+ }
+ cache->cc_ntup = 0; /* in case of WARN error above */
}
- cache->cc_ntup = 0; /* in case of WARN error above */
- }
-
- CACHE1_elog(DEBUG, "end of ResetSystemCache call");
-
- /* ----------------
- * back to the old context before we return...
- * ----------------
- */
- MemoryContextSwitchTo(oldcxt);
+
+ CACHE1_elog(DEBUG, "end of ResetSystemCache call");
+
+ /* ----------------
+ * back to the old context before we return...
+ * ----------------
+ */
+ MemoryContextSwitchTo(oldcxt);
}
/* --------------------------------
- * InitIndexedSysCache
+ * InitIndexedSysCache
*
- * This allocates and initializes a cache for a system catalog relation.
- * Actually, the cache is only partially initialized to avoid opening the
- * relation. The relation will be opened and the rest of the cache
- * structure initialized on the first access.
+ * This allocates and initializes a cache for a system catalog relation.
+ * Actually, the cache is only partially initialized to avoid opening the
+ * relation. The relation will be opened and the rest of the cache
+ * structure initialized on the first access.
* --------------------------------
*/
#ifdef CACHEDEBUG
#define InitSysCache_DEBUG1 \
elog(DEBUG, "InitSysCache: rid=%d id=%d nkeys=%d size=%d\n", \
- cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \
- for (i = 0; i < nkeys; i += 1) { \
- elog(DEBUG, "InitSysCache: key=%d len=%d skey=[%d %d %d %d]\n", \
- cp->cc_key[i], cp->cc_klen[i], \
- cp->cc_skey[i].sk_flags, \
- cp->cc_skey[i].sk_attno, \
- cp->cc_skey[i].sk_procedure, \
- cp->cc_skey[i].sk_argument); \
- }
+ cp->relationId, cp->id, cp->cc_nkeys, cp->cc_size); \
+ for (i = 0; i < nkeys; i += 1) { \
+ elog(DEBUG, "InitSysCache: key=%d len=%d skey=[%d %d %d %d]\n", \
+ cp->cc_key[i], cp->cc_klen[i], \
+ cp->cc_skey[i].sk_flags, \
+ cp->cc_skey[i].sk_attno, \
+ cp->cc_skey[i].sk_procedure, \
+ cp->cc_skey[i].sk_argument); \
+ }
#else
#define InitSysCache_DEBUG1
#endif
-CatCache*
+CatCache *
InitSysCache(char *relname,
- char *iname,
- int id,
- int nkeys,
- int key[],
- HeapTuple (*iScanfuncP)())
+ char *iname,
+ int id,
+ int nkeys,
+ int key[],
+ HeapTuple(*iScanfuncP) ())
{
- CatCache *cp;
- register int i;
- MemoryContext oldcxt;
-
- char *indname;
-
- indname = (iname) ? iname : NULL;
-
- /* ----------------
- * first switch to the cache context so our allocations
- * do not vanish at the end of a transaction
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * allocate a new cache structure
- * ----------------
- */
- cp = (CatCache *)palloc(sizeof(CatCache));
- memset((char*)cp, 0, sizeof(CatCache));
-
- /* ----------------
- * initialize the cache buckets (each bucket is a list header)
- * and the LRU tuple list
- * ----------------
- */
- {
- /*
- * We can only do this optimization because the number of hash
- * buckets never changes. Without it, we call malloc() too much.
- * We could move this to dllist.c, but the way we do this is not
- * dynamic/portabl, so why allow other routines to use it.
- */
- Dllist *cache_begin = malloc((NCCBUCK+1)*sizeof(Dllist));
- for (i = 0; i <= NCCBUCK; ++i) {
- cp->cc_cache[i] = &cache_begin[i];
- cp->cc_cache[i]->dll_head = 0;
- cp->cc_cache[i]->dll_tail = 0;
- }
- }
-
- cp->cc_lrulist = DLNewList();
-
- /* ----------------
- * Caches is the pointer to the head of the list of all the
- * system caches. here we add the new cache to the top of the list.
- * ----------------
- */
- cp->cc_next = Caches; /* list of caches (single link) */
- Caches = cp;
-
- /* ----------------
- * initialize the cache's relation information for the relation
- * corresponding to this cache and initialize some of the the new
- * cache's other internal fields.
- * ----------------
- */
- cp->relationId = InvalidOid;
- cp->indexId = InvalidOid;
- cp->cc_relname = relname;
- cp->cc_indname = indname;
- cp->cc_tupdesc = (TupleDesc) NULL;
- cp->id = id;
- cp->cc_maxtup = MAXTUP;
- cp->cc_size = NCCBUCK;
- cp->cc_nkeys = nkeys;
- cp->cc_iscanfunc = iScanfuncP;
-
- /* ----------------
- * initialize the cache's key information
- * ----------------
- */
- for (i = 0; i < nkeys; ++i) {
- cp->cc_key[i] = key[i];
- if (!key[i]) {
- elog(FATAL, "InitSysCache: called with 0 key[%d]", i);
- }
- if (key[i] < 0) {
- if (key[i] != ObjectIdAttributeNumber) {
- elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);
- } else {
- cp->cc_klen[i] = sizeof(Oid);
+ CatCache *cp;
+ register int i;
+ MemoryContext oldcxt;
+
+ char *indname;
+
+ indname = (iname) ? iname : NULL;
+
+ /* ----------------
+ * first switch to the cache context so our allocations
+ * do not vanish at the end of a transaction
+ * ----------------
+ */
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * allocate a new cache structure
+ * ----------------
+ */
+ cp = (CatCache *) palloc(sizeof(CatCache));
+ memset((char *) cp, 0, sizeof(CatCache));
+
+ /* ----------------
+ * initialize the cache buckets (each bucket is a list header)
+ * and the LRU tuple list
+ * ----------------
+ */
+ {
+
/*
- * ScanKeyEntryData and struct skey are equivalent. It looks
- * like a move was made to obsolete struct skey, but it
- * didn't reach this file. Someday we should clean up this
- * code and consolidate to ScanKeyEntry - mer 10 Nov 1991
+ * We can only do this optimization because the number of hash
+ * buckets never changes. Without it, we call malloc() too much.
+ * We could move this to dllist.c, but the way we do this is not
+ * dynamic/portabl, so why allow other routines to use it.
*/
- ScanKeyEntryInitialize(&cp->cc_skey[i],
- (bits16)0,
- (AttrNumber)key[i],
- (RegProcedure)F_OIDEQ,
- (Datum)0);
- continue;
- }
+ Dllist *cache_begin = malloc((NCCBUCK + 1) * sizeof(Dllist));
+
+ for (i = 0; i <= NCCBUCK; ++i)
+ {
+ cp->cc_cache[i] = &cache_begin[i];
+ cp->cc_cache[i]->dll_head = 0;
+ cp->cc_cache[i]->dll_tail = 0;
+ }
+ }
+
+ cp->cc_lrulist = DLNewList();
+
+ /* ----------------
+ * Caches is the pointer to the head of the list of all the
+ * system caches. here we add the new cache to the top of the list.
+ * ----------------
+ */
+ cp->cc_next = Caches; /* list of caches (single link) */
+ Caches = cp;
+
+ /* ----------------
+ * initialize the cache's relation information for the relation
+ * corresponding to this cache and initialize some of the the new
+ * cache's other internal fields.
+ * ----------------
+ */
+ cp->relationId = InvalidOid;
+ cp->indexId = InvalidOid;
+ cp->cc_relname = relname;
+ cp->cc_indname = indname;
+ cp->cc_tupdesc = (TupleDesc) NULL;
+ cp->id = id;
+ cp->cc_maxtup = MAXTUP;
+ cp->cc_size = NCCBUCK;
+ cp->cc_nkeys = nkeys;
+ cp->cc_iscanfunc = iScanfuncP;
+
+ /* ----------------
+ * initialize the cache's key information
+ * ----------------
+ */
+ for (i = 0; i < nkeys; ++i)
+ {
+ cp->cc_key[i] = key[i];
+ if (!key[i])
+ {
+ elog(FATAL, "InitSysCache: called with 0 key[%d]", i);
+ }
+ if (key[i] < 0)
+ {
+ if (key[i] != ObjectIdAttributeNumber)
+ {
+ elog(FATAL, "InitSysCache: called with %d key[%d]", key[i], i);
+ }
+ else
+ {
+ cp->cc_klen[i] = sizeof(Oid);
+
+ /*
+ * ScanKeyEntryData and struct skey are equivalent. It
+ * looks like a move was made to obsolete struct skey, but
+ * it didn't reach this file. Someday we should clean up
+ * this code and consolidate to ScanKeyEntry - mer 10 Nov
+ * 1991
+ */
+ ScanKeyEntryInitialize(&cp->cc_skey[i],
+ (bits16) 0,
+ (AttrNumber) key[i],
+ (RegProcedure) F_OIDEQ,
+ (Datum) 0);
+ continue;
+ }
+ }
+
+ cp->cc_skey[i].sk_attno = key[i];
}
-
- cp->cc_skey[i].sk_attno = key[i];
- }
-
- /* ----------------
- * all done. new cache is initialized. print some debugging
- * information, if appropriate.
- * ----------------
- */
- InitSysCache_DEBUG1;
-
- /* ----------------
- * back to the old context before we return...
- * ----------------
- */
- MemoryContextSwitchTo(oldcxt);
- return(cp);
+
+ /* ----------------
+ * all done. new cache is initialized. print some debugging
+ * information, if appropriate.
+ * ----------------
+ */
+ InitSysCache_DEBUG1;
+
+ /* ----------------
+ * back to the old context before we return...
+ * ----------------
+ */
+ MemoryContextSwitchTo(oldcxt);
+ return (cp);
}
/* --------------------------------
- * SearchSysCache
+ * SearchSysCache
*
- * This call searches a system cache for a tuple, opening the relation
- * if necessary (the first access to a particular cache).
+ * This call searches a system cache for a tuple, opening the relation
+ * if necessary (the first access to a particular cache).
* --------------------------------
*/
HeapTuple
-SearchSysCache(struct catcache *cache,
- Datum v1,
- Datum v2,
- Datum v3,
- Datum v4)
+SearchSysCache(struct catcache * cache,
+ Datum v1,
+ Datum v2,
+ Datum v3,
+ Datum v4)
{
- unsigned hash;
- CatCTup *ct = NULL;
- CatCTup *nct;
- CatCTup *nct2;
- Dlelem *elt;
- HeapTuple ntp = 0;
- Buffer buffer;
-
- Relation relation;
- MemoryContext oldcxt;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- if (cache->relationId == InvalidOid)
- CatalogCacheInitializeCache(cache, NULL);
-
- /* ----------------
- * initialize the search key information
- * ----------------
- */
- cache->cc_skey[0].sk_argument = v1;
- cache->cc_skey[1].sk_argument = v2;
- cache->cc_skey[2].sk_argument = v3;
- cache->cc_skey[3].sk_argument = v4;
-
- /* ----------------
- * find the hash bucket in which to look for the tuple
- * ----------------
- */
- hash = CatalogCacheComputeHashIndex(cache);
-
- /* ----------------
- * scan the hash bucket until we find a match or exhaust our tuples
- * ----------------
- */
- for (elt = DLGetHead(cache->cc_cache[hash]);
- elt;
- elt = DLGetSucc(elt))
+ unsigned hash;
+ CatCTup *ct = NULL;
+ CatCTup *nct;
+ CatCTup *nct2;
+ Dlelem *elt;
+ HeapTuple ntp = 0;
+ Buffer buffer;
+
+ Relation relation;
+ MemoryContext oldcxt;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ if (cache->relationId == InvalidOid)
+ CatalogCacheInitializeCache(cache, NULL);
+
+ /* ----------------
+ * initialize the search key information
+ * ----------------
+ */
+ cache->cc_skey[0].sk_argument = v1;
+ cache->cc_skey[1].sk_argument = v2;
+ cache->cc_skey[2].sk_argument = v3;
+ cache->cc_skey[3].sk_argument = v4;
+
+ /* ----------------
+ * find the hash bucket in which to look for the tuple
+ * ----------------
+ */
+ hash = CatalogCacheComputeHashIndex(cache);
+
+ /* ----------------
+ * scan the hash bucket until we find a match or exhaust our tuples
+ * ----------------
+ */
+ for (elt = DLGetHead(cache->cc_cache[hash]);
+ elt;
+ elt = DLGetSucc(elt))
{
- ct = (CatCTup*)DLE_VAL(elt);
- /* ----------------
- * see if the cached tuple matches our key.
- * (should we be worried about time ranges? -cim 10/2/90)
- * ----------------
- */
- if (heap_keytest(ct->ct_tup,
- cache->cc_tupdesc,
- cache->cc_nkeys,
- cache->cc_skey))
- break;
+ ct = (CatCTup *) DLE_VAL(elt);
+ /* ----------------
+ * see if the cached tuple matches our key.
+ * (should we be worried about time ranges? -cim 10/2/90)
+ * ----------------
+ */
+ if (heap_keytest(ct->ct_tup,
+ cache->cc_tupdesc,
+ cache->cc_nkeys,
+ cache->cc_skey))
+ break;
}
-
- /* ----------------
- * if we found a tuple in the cache, move it to the top of the
- * lru list, and return it.
- * ----------------
- */
- if (elt) {
- Dlelem* old_lru_elt;
- old_lru_elt = ((CatCTup*)DLE_VAL(elt))->ct_node;
- DLRemove(old_lru_elt);
- DLAddHead(cache->cc_lrulist, old_lru_elt);
+
+ /* ----------------
+ * if we found a tuple in the cache, move it to the top of the
+ * lru list, and return it.
+ * ----------------
+ */
+ if (elt)
+ {
+ Dlelem *old_lru_elt;
+
+ old_lru_elt = ((CatCTup *) DLE_VAL(elt))->ct_node;
+ DLRemove(old_lru_elt);
+ DLAddHead(cache->cc_lrulist, old_lru_elt);
#ifdef CACHEDEBUG
+ relation = heap_open(cache->relationId);
+ CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
+ RelationGetRelationName(relation), hash);
+ heap_close(relation);
+#endif /* CACHEDEBUG */
+
+ return (ct->ct_tup);
+ }
+
+ /* ----------------
+ * Tuple was not found in cache, so we have to try and
+ * retrieve it directly from the relation. If it's found,
+ * we add it to the cache. We must avoid recursion here,
+ * so we disable cache operations. If operations are
+ * currently disabled and we couldn't find the requested item
+ * in the cache, then this may be a recursive request, and we
+ * abort with an error.
+ * ----------------
+ */
+
+ if (DisableCache)
+ {
+ elog(WARN, "SearchSysCache: Called while cache disabled");
+ return ((HeapTuple) NULL);
+ }
+
+ /* ----------------
+ * open the relation associated with the cache
+ * ----------------
+ */
relation = heap_open(cache->relationId);
- CACHE3_elog(DEBUG, "SearchSysCache(%s): found in bucket %d",
- RelationGetRelationName(relation), hash);
- heap_close(relation);
-#endif /* CACHEDEBUG */
-
- return (ct->ct_tup);
- }
-
- /* ----------------
- * Tuple was not found in cache, so we have to try and
- * retrieve it directly from the relation. If it's found,
- * we add it to the cache. We must avoid recursion here,
- * so we disable cache operations. If operations are
- * currently disabled and we couldn't find the requested item
- * in the cache, then this may be a recursive request, and we
- * abort with an error.
- * ----------------
- */
-
- if (DisableCache) {
- elog(WARN, "SearchSysCache: Called while cache disabled");
- return((HeapTuple) NULL);
- }
-
- /* ----------------
- * open the relation associated with the cache
- * ----------------
- */
- relation = heap_open(cache->relationId);
- CACHE2_elog(DEBUG, "SearchSysCache(%s)",
- RelationGetRelationName(relation));
-
- /* ----------------
- * DisableCache and then switch to the cache memory context.
- * ----------------
- */
- DisableCache = 1;
-
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * Scan the relation to find the tuple. If there's an index, and
- * if this isn't bootstrap (initdb) time, use the index.
- * ----------------
- */
- CACHE2_elog(DEBUG, "SearchSysCache: performing scan (override==%d)",
- heapisoverride());
-
- if ((RelationGetRelationTupleForm(relation))->relhasindex
- && !IsBootstrapProcessingMode())
+ CACHE2_elog(DEBUG, "SearchSysCache(%s)",
+ RelationGetRelationName(relation));
+
+ /* ----------------
+ * DisableCache and then switch to the cache memory context.
+ * ----------------
+ */
+ DisableCache = 1;
+
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * Scan the relation to find the tuple. If there's an index, and
+ * if this isn't bootstrap (initdb) time, use the index.
+ * ----------------
+ */
+ CACHE2_elog(DEBUG, "SearchSysCache: performing scan (override==%d)",
+ heapisoverride());
+
+ if ((RelationGetRelationTupleForm(relation))->relhasindex
+ && !IsBootstrapProcessingMode())
{
- /* ----------
- * Switch back to old memory context so memory not freed
- * in the scan function will go away at transaction end.
- * wieck - 10/18/1996
- * ----------
- */
- MemoryContextSwitchTo(oldcxt);
- Assert(cache->cc_iscanfunc);
- switch(cache->cc_nkeys)
+ /* ----------
+ * Switch back to old memory context so memory not freed
+ * in the scan function will go away at transaction end.
+ * wieck - 10/18/1996
+ * ----------
+ */
+ MemoryContextSwitchTo(oldcxt);
+ Assert(cache->cc_iscanfunc);
+ switch (cache->cc_nkeys)
+ {
+ case 4:
+ ntp = cache->cc_iscanfunc(relation, v1, v2, v3, v4);
+ break;
+ case 3:
+ ntp = cache->cc_iscanfunc(relation, v1, v2, v3);
+ break;
+ case 2:
+ ntp = cache->cc_iscanfunc(relation, v1, v2);
+ break;
+ case 1:
+ ntp = cache->cc_iscanfunc(relation, v1);
+ break;
+ }
+ /* ----------
+ * Back to Cache context. If we got a tuple copy it
+ * into our context.
+ * wieck - 10/18/1996
+ * ----------
+ */
+ MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ if (HeapTupleIsValid(ntp))
{
- case 4: ntp = cache->cc_iscanfunc(relation,v1,v2,v3,v4); break;
- case 3: ntp = cache->cc_iscanfunc(relation,v1,v2,v3); break;
- case 2: ntp = cache->cc_iscanfunc(relation,v1,v2); break;
- case 1: ntp = cache->cc_iscanfunc(relation,v1); break;
+ ntp = heap_copytuple(ntp);
}
- /* ----------
- * Back to Cache context. If we got a tuple copy it
- * into our context.
- * wieck - 10/18/1996
- * ----------
- */
- MemoryContextSwitchTo((MemoryContext)CacheCxt);
- if(HeapTupleIsValid(ntp)) {
- ntp = heap_copytuple(ntp);
- }
}
- else
+ else
{
- HeapScanDesc sd;
-
- /* ----------
- * As above do the lookup in the callers memory
- * context.
- * wieck - 10/18/1996
- * ----------
- */
- MemoryContextSwitchTo(oldcxt);
-
- sd = heap_beginscan(relation, 0, NowTimeQual,
- cache->cc_nkeys, cache->cc_skey);
-
- /* should this buffer be ReleaseBuffer'd? --djm 8/20/96 */
- ntp = heap_getnext(sd, 0, &buffer);
-
- MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- if (HeapTupleIsValid(ntp)) {
- CACHE1_elog(DEBUG, "SearchSysCache: found tuple");
- ntp = heap_copytuple(ntp);
- }
-
- MemoryContextSwitchTo(oldcxt);
-
- heap_endscan(sd);
-
- MemoryContextSwitchTo((MemoryContext)CacheCxt);
+ HeapScanDesc sd;
+
+ /* ----------
+ * As above do the lookup in the callers memory
+ * context.
+ * wieck - 10/18/1996
+ * ----------
+ */
+ MemoryContextSwitchTo(oldcxt);
+
+ sd = heap_beginscan(relation, 0, NowTimeQual,
+ cache->cc_nkeys, cache->cc_skey);
+
+ /* should this buffer be ReleaseBuffer'd? --djm 8/20/96 */
+ ntp = heap_getnext(sd, 0, &buffer);
+
+ MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ if (HeapTupleIsValid(ntp))
+ {
+ CACHE1_elog(DEBUG, "SearchSysCache: found tuple");
+ ntp = heap_copytuple(ntp);
+ }
+
+ MemoryContextSwitchTo(oldcxt);
+
+ heap_endscan(sd);
+
+ MemoryContextSwitchTo((MemoryContext) CacheCxt);
}
-
- DisableCache = 0;
-
- /* ----------------
- * scan is complete. if tup is valid, we copy it and add the copy to
- * the cache.
- * ----------------
- */
- if (HeapTupleIsValid(ntp)) {
+
+ DisableCache = 0;
+
/* ----------------
- * allocate a new cache tuple holder, store the pointer
- * to the heap tuple there and initialize the list pointers.
+ * scan is complete. if tup is valid, we copy it and add the copy to
+ * the cache.
* ----------------
*/
- Dlelem *lru_elt;
-
- /* this is a little cumbersome here because we want the Dlelem's
- in both doubly linked lists to point to one another.
- That makes it easier to remove something from both the cache bucket
- and the lru list at the same time */
- nct = (CatCTup*) malloc(sizeof(CatCTup));
- nct->ct_tup = ntp;
- elt = DLNewElem(nct);
- nct2 = (CatCTup*) malloc(sizeof(CatCTup));
- nct2->ct_tup = ntp;
- lru_elt = DLNewElem(nct2);
- nct2->ct_node = elt;
- nct->ct_node = lru_elt;
-
- DLAddHead(cache->cc_lrulist, lru_elt);
- DLAddHead(cache->cc_cache[hash], elt);
+ if (HeapTupleIsValid(ntp))
+ {
+ /* ----------------
+ * allocate a new cache tuple holder, store the pointer
+ * to the heap tuple there and initialize the list pointers.
+ * ----------------
+ */
+ Dlelem *lru_elt;
+
+ /*
+ * this is a little cumbersome here because we want the Dlelem's
+ * in both doubly linked lists to point to one another. That makes
+ * it easier to remove something from both the cache bucket and
+ * the lru list at the same time
+ */
+ nct = (CatCTup *) malloc(sizeof(CatCTup));
+ nct->ct_tup = ntp;
+ elt = DLNewElem(nct);
+ nct2 = (CatCTup *) malloc(sizeof(CatCTup));
+ nct2->ct_tup = ntp;
+ lru_elt = DLNewElem(nct2);
+ nct2->ct_node = elt;
+ nct->ct_node = lru_elt;
+
+ DLAddHead(cache->cc_lrulist, lru_elt);
+ DLAddHead(cache->cc_cache[hash], elt);
+
+ /* ----------------
+ * deal with hash bucket overflow
+ * ----------------
+ */
+ if (++cache->cc_ntup > cache->cc_maxtup)
+ {
+ CatCTup *ct;
+
+ elt = DLGetTail(cache->cc_lrulist);
+ ct = (CatCTup *) DLE_VAL(elt);
+
+ if (ct != nct)
+ {
+ CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
+ RelationGetRelationName(relation));
+
+ CatCacheRemoveCTup(cache, elt);
+
+ }
+ }
+
+ CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",
+ RelationGetRelationName(relation),
+ cache->cc_ntup, cache->cc_maxtup);
+ CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",
+ RelationGetRelationName(relation), hash);
+ }
/* ----------------
- * deal with hash bucket overflow
+ * close the relation, switch back to the original memory context
+ * and return the tuple we found (or NULL)
* ----------------
*/
- if (++cache->cc_ntup > cache->cc_maxtup) {
- CatCTup *ct;
- elt = DLGetTail(cache->cc_lrulist);
- ct = (CatCTup *) DLE_VAL(elt);
-
- if (ct != nct) {
- CACHE2_elog(DEBUG, "SearchSysCache(%s): Overflow, LRU removal",
- RelationGetRelationName(relation));
-
- CatCacheRemoveCTup(cache, elt);
-
- }
- }
-
- CACHE4_elog(DEBUG, "SearchSysCache(%s): Contains %d/%d tuples",
- RelationGetRelationName(relation),
- cache->cc_ntup, cache->cc_maxtup);
- CACHE3_elog(DEBUG, "SearchSysCache(%s): put in bucket %d",
- RelationGetRelationName(relation), hash);
- }
-
- /* ----------------
- * close the relation, switch back to the original memory context
- * and return the tuple we found (or NULL)
- * ----------------
- */
- heap_close(relation);
-
- MemoryContextSwitchTo(oldcxt);
- return ntp;
+ heap_close(relation);
+
+ MemoryContextSwitchTo(oldcxt);
+ return ntp;
}
/* --------------------------------
- * RelationInvalidateCatalogCacheTuple()
+ * RelationInvalidateCatalogCacheTuple()
*
- * Invalidate a tuple from a specific relation. This call determines the
- * cache in question and calls CatalogCacheIdInvalidate(). It is -ok-
- * if the relation cannot be found, it simply means this backend has yet
- * to open it.
+ * Invalidate a tuple from a specific relation. This call determines the
+ * cache in question and calls CatalogCacheIdInvalidate(). It is -ok-
+ * if the relation cannot be found, it simply means this backend has yet
+ * to open it.
* --------------------------------
*/
void
RelationInvalidateCatalogCacheTuple(Relation relation,
- HeapTuple tuple,
- void (*function)(int, Index, ItemPointer))
+ HeapTuple tuple,
+ void (*function) (int, Index, ItemPointer))
{
- struct catcache *ccp;
- MemoryContext oldcxt;
- Oid relationId;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- Assert(HeapTupleIsValid(tuple));
- CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called");
-
- /* ----------------
- * switch to the cache memory context
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * for each cache
- * if the cache contains tuples from the specified relation
- * call the invalidation function on the tuples
- * in the proper hash bucket
- * ----------------
- */
- relationId = RelationGetRelationId(relation);
-
- for (ccp = Caches; ccp; ccp = ccp->cc_next) {
- if (relationId != ccp->relationId)
- continue;
-
- /* OPT inline simplification of CatalogCacheIdInvalidate */
- if (!PointerIsValid(function)) {
- function = CatalogCacheIdInvalidate;
+ struct catcache *ccp;
+ MemoryContext oldcxt;
+ Oid relationId;
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ Assert(HeapTupleIsValid(tuple));
+ CACHE1_elog(DEBUG, "RelationInvalidateCatalogCacheTuple: called");
+
+ /* ----------------
+ * switch to the cache memory context
+ * ----------------
+ */
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * for each cache
+ * if the cache contains tuples from the specified relation
+ * call the invalidation function on the tuples
+ * in the proper hash bucket
+ * ----------------
+ */
+ relationId = RelationGetRelationId(relation);
+
+ for (ccp = Caches; ccp; ccp = ccp->cc_next)
+ {
+ if (relationId != ccp->relationId)
+ continue;
+
+ /* OPT inline simplification of CatalogCacheIdInvalidate */
+ if (!PointerIsValid(function))
+ {
+ function = CatalogCacheIdInvalidate;
+ }
+
+ (*function) (ccp->id,
+ CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),
+ &tuple->t_ctid);
+
+ heap_close(relation);
}
-
- (*function)(ccp->id,
- CatalogCacheComputeTupleHashIndex(ccp, relation, tuple),
- &tuple->t_ctid);
-
- heap_close(relation);
- }
-
- /* ----------------
- * return to the proper memory context
- * ----------------
- */
- MemoryContextSwitchTo(oldcxt);
-
- /* sendpm('I', "Invalidated tuple"); */
-}
+ /* ----------------
+ * return to the proper memory context
+ * ----------------
+ */
+ MemoryContextSwitchTo(oldcxt);
+
+ /* sendpm('I', "Invalidated tuple"); */
+}
diff --git a/src/backend/utils/cache/fcache.c b/src/backend/utils/cache/fcache.c
index 1d86364abda..ad174c6fdf5 100644
--- a/src/backend/utils/cache/fcache.c
+++ b/src/backend/utils/cache/fcache.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* fcache.c--
- * Code for the 'function cache' used in Oper and Func nodes....
+ * Code for the 'function cache' used in Oper and Func nodes....
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.4 1996/11/10 03:03:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.5 1997/09/07 04:52:59 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,23 +23,24 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_language.h"
#include "catalog/pg_class.h"
-#include "parser/parsetree.h" /* for getrelname() */
+#include "parser/parsetree.h" /* for getrelname() */
#include "utils/builtins.h"
#include "utils/fcache.h"
#include "utils/fcache2.h"
#include "nodes/primnodes.h"
#include "nodes/execnodes.h"
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static Oid GetDynamicFuncArgType(Var *arg, ExprContext *econtext);
-static FunctionCachePtr init_fcache(Oid foid,
- bool use_syscache,
- List *argList,
- ExprContext *econtext);
+static Oid GetDynamicFuncArgType(Var * arg, ExprContext * econtext);
+static FunctionCachePtr
+init_fcache(Oid foid,
+ bool use_syscache,
+ List * argList,
+ ExprContext * econtext);
/*-----------------------------------------------------------------
*
@@ -47,259 +48,269 @@ static FunctionCachePtr init_fcache(Oid foid,
*
*
* NOTE: This function can be called when the system cache is being
- * initialized. Therefore, use_syscache should ONLY be true
- * when the function return type is interesting (ie: set_fcache).
+ * initialized. Therefore, use_syscache should ONLY be true
+ * when the function return type is interesting (ie: set_fcache).
*-----------------------------------------------------------------
*/
#define FuncArgTypeIsDynamic(arg) \
- (IsA(arg,Var) && ((Var*)arg)->varattno == InvalidAttrNumber)
+ (IsA(arg,Var) && ((Var*)arg)->varattno == InvalidAttrNumber)
-static Oid
-GetDynamicFuncArgType(Var *arg, ExprContext *econtext)
+static Oid
+GetDynamicFuncArgType(Var * arg, ExprContext * econtext)
{
- char *relname;
- int rtid;
- HeapTuple tup;
-
- Assert(IsA(arg,Var));
-
- rtid = ((Var*)arg)->varno;
- relname = (char*)getrelname(rtid, econtext->ecxt_range_table);
-
-
- tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(relname),
- 0,0,0);
- if (!tup)
- elog(WARN, "Lookup failed on type tuple for class %s",
- relname);
-
- return tup->t_oid;
+ char *relname;
+ int rtid;
+ HeapTuple tup;
+
+ Assert(IsA(arg, Var));
+
+ rtid = ((Var *) arg)->varno;
+ relname = (char *) getrelname(rtid, econtext->ecxt_range_table);
+
+
+ tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(relname),
+ 0, 0, 0);
+ if (!tup)
+ elog(WARN, "Lookup failed on type tuple for class %s",
+ relname);
+
+ return tup->t_oid;
}
-static FunctionCachePtr
+static FunctionCachePtr
init_fcache(Oid foid,
- bool use_syscache,
- List *argList,
- ExprContext *econtext)
+ bool use_syscache,
+ List * argList,
+ ExprContext * econtext)
{
- HeapTuple procedureTuple;
- HeapTuple typeTuple;
- Form_pg_proc procedureStruct;
- TypeTupleForm typeStruct;
- FunctionCachePtr retval;
- text *tmp;
- int nargs;
-
- /* ----------------
- * get the procedure tuple corresponding to the given
- * functionOid. If this fails, returnValue has been
- * pre-initialized to "null" so we just return it.
- * ----------------
- */
- retval = (FunctionCachePtr) palloc(sizeof(FunctionCache));
-
- if (!use_syscache)
- elog(WARN, "what the ????, init the fcache without the catalogs?");
-
- procedureTuple = SearchSysCacheTuple(PROOID,
- ObjectIdGetDatum(foid),
- 0,0,0);
-
- if (!HeapTupleIsValid(procedureTuple))
- elog(WARN,
- "init_fcache: %s %d",
- "Cache lookup failed for procedure", foid);
-
- /* ----------------
- * get the return type from the procedure tuple
- * ----------------
- */
- procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
-
- /* ----------------
- * get the type tuple corresponding to the return type
- * If this fails, returnValue has been pre-initialized
- * to "null" so we just return it.
- * ----------------
- */
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(procedureStruct->prorettype),
- 0,0,0);
-
- if (!HeapTupleIsValid(typeTuple))
- elog(WARN,
- "init_fcache: %s %d",
- "Cache lookup failed for type",
- (procedureStruct)->prorettype);
-
- /* ----------------
- * get the type length and by-value from the type tuple and
- * save the information in our one element cache.
- * ----------------
- */
- typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
-
- retval->typlen = (typeStruct)->typlen;
- if ((typeStruct)->typrelid == InvalidOid) {
- /* The return type is not a relation, so just use byval */
- retval->typbyval = (typeStruct)->typbyval ? true : false ;
- } else {
- /* This is a hack. We assume here that any function returning
- * a relation returns it by reference. This needs to be
- * fixed.
+ HeapTuple procedureTuple;
+ HeapTuple typeTuple;
+ Form_pg_proc procedureStruct;
+ TypeTupleForm typeStruct;
+ FunctionCachePtr retval;
+ text *tmp;
+ int nargs;
+
+ /* ----------------
+ * get the procedure tuple corresponding to the given
+ * functionOid. If this fails, returnValue has been
+ * pre-initialized to "null" so we just return it.
+ * ----------------
+ */
+ retval = (FunctionCachePtr) palloc(sizeof(FunctionCache));
+
+ if (!use_syscache)
+ elog(WARN, "what the ????, init the fcache without the catalogs?");
+
+ procedureTuple = SearchSysCacheTuple(PROOID,
+ ObjectIdGetDatum(foid),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(procedureTuple))
+ elog(WARN,
+ "init_fcache: %s %d",
+ "Cache lookup failed for procedure", foid);
+
+ /* ----------------
+ * get the return type from the procedure tuple
+ * ----------------
+ */
+ procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
+
+ /* ----------------
+ * get the type tuple corresponding to the return type
+ * If this fails, returnValue has been pre-initialized
+ * to "null" so we just return it.
+ * ----------------
+ */
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(procedureStruct->prorettype),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(typeTuple))
+ elog(WARN,
+ "init_fcache: %s %d",
+ "Cache lookup failed for type",
+ (procedureStruct)->prorettype);
+
+ /* ----------------
+ * get the type length and by-value from the type tuple and
+ * save the information in our one element cache.
+ * ----------------
*/
- retval->typbyval = false;
- }
- retval->foid = foid;
- retval->language = procedureStruct->prolang;
- retval->func_state = (char *)NULL;
- retval->setArg = NULL;
- retval->hasSetArg = false;
- retval->oneResult = ! procedureStruct->proretset;
- retval->istrusted = procedureStruct->proistrusted;
-
- /*
- * If we are returning exactly one result then we have to copy
- * tuples and by reference results because we have to end the execution
- * before we return the results. When you do this everything allocated
- * by the executor (i.e. slots and tuples) is freed.
- */
- if ((retval->language == SQLlanguageId) &&
- (retval->oneResult) &&
- !(retval->typbyval))
+ typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple);
+
+ retval->typlen = (typeStruct)->typlen;
+ if ((typeStruct)->typrelid == InvalidOid)
+ {
+ /* The return type is not a relation, so just use byval */
+ retval->typbyval = (typeStruct)->typbyval ? true : false;
+ }
+ else
{
- Form_pg_class relationStruct;
- HeapTuple relationTuple;
- TupleDesc td;
- TupleTableSlot *slot;
-
- slot = makeNode(TupleTableSlot);
- slot->ttc_shouldFree = true;
- slot->ttc_descIsNew = true;
- slot->ttc_tupleDescriptor = (TupleDesc) NULL;
- slot->ttc_buffer = InvalidBuffer;
- slot->ttc_whichplan = -1;
- retval->funcSlot = (Pointer)slot;
-
- relationTuple = (HeapTuple)
- SearchSysCacheTuple(RELNAME,
- PointerGetDatum(&typeStruct->typname),
- 0,0,0);
-
- if (relationTuple)
+
+ /*
+ * This is a hack. We assume here that any function returning a
+ * relation returns it by reference. This needs to be fixed.
+ */
+ retval->typbyval = false;
+ }
+ retval->foid = foid;
+ retval->language = procedureStruct->prolang;
+ retval->func_state = (char *) NULL;
+ retval->setArg = NULL;
+ retval->hasSetArg = false;
+ retval->oneResult = !procedureStruct->proretset;
+ retval->istrusted = procedureStruct->proistrusted;
+
+ /*
+ * If we are returning exactly one result then we have to copy tuples
+ * and by reference results because we have to end the execution
+ * before we return the results. When you do this everything
+ * allocated by the executor (i.e. slots and tuples) is freed.
+ */
+ if ((retval->language == SQLlanguageId) &&
+ (retval->oneResult) &&
+ !(retval->typbyval))
+ {
+ Form_pg_class relationStruct;
+ HeapTuple relationTuple;
+ TupleDesc td;
+ TupleTableSlot *slot;
+
+ slot = makeNode(TupleTableSlot);
+ slot->ttc_shouldFree = true;
+ slot->ttc_descIsNew = true;
+ slot->ttc_tupleDescriptor = (TupleDesc) NULL;
+ slot->ttc_buffer = InvalidBuffer;
+ slot->ttc_whichplan = -1;
+ retval->funcSlot = (Pointer) slot;
+
+ relationTuple = (HeapTuple)
+ SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(&typeStruct->typname),
+ 0, 0, 0);
+
+ if (relationTuple)
{
- relationStruct = (Form_pg_class)GETSTRUCT(relationTuple);
- td = CreateTemplateTupleDesc(relationStruct->relnatts);
+ relationStruct = (Form_pg_class) GETSTRUCT(relationTuple);
+ td = CreateTemplateTupleDesc(relationStruct->relnatts);
}
- else
- td = CreateTemplateTupleDesc(1);
-
- ((TupleTableSlot*)retval->funcSlot)->ttc_tupleDescriptor = td;
+ else
+ td = CreateTemplateTupleDesc(1);
+
+ ((TupleTableSlot *) retval->funcSlot)->ttc_tupleDescriptor = td;
}
- else
- retval->funcSlot = (char *)NULL;
-
- nargs = procedureStruct->pronargs;
- retval->nargs = nargs;
-
- if (nargs > 0)
+ else
+ retval->funcSlot = (char *) NULL;
+
+ nargs = procedureStruct->pronargs;
+ retval->nargs = nargs;
+
+ if (nargs > 0)
{
- Oid *argTypes;
-
- retval->nullVect = (bool *)palloc((retval->nargs)*sizeof(bool));
-
- if (retval->language == SQLlanguageId)
+ Oid *argTypes;
+
+ retval->nullVect = (bool *) palloc((retval->nargs) * sizeof(bool));
+
+ if (retval->language == SQLlanguageId)
{
- int i;
- List *oneArg;
-
- retval->argOidVect =
- (Oid *)palloc(retval->nargs*sizeof(Oid));
- argTypes = procedureStruct->proargtypes;
- memmove(retval->argOidVect,
- argTypes,
- (retval->nargs)*sizeof(Oid));
-
- for (i=0;
- argList;
- i++, argList = lnext(argList))
+ int i;
+ List *oneArg;
+
+ retval->argOidVect =
+ (Oid *) palloc(retval->nargs * sizeof(Oid));
+ argTypes = procedureStruct->proargtypes;
+ memmove(retval->argOidVect,
+ argTypes,
+ (retval->nargs) * sizeof(Oid));
+
+ for (i = 0;
+ argList;
+ i++, argList = lnext(argList))
{
- oneArg = lfirst(argList);
- if (FuncArgTypeIsDynamic(oneArg))
- retval->argOidVect[i] = GetDynamicFuncArgType((Var*)oneArg,
- econtext);
+ oneArg = lfirst(argList);
+ if (FuncArgTypeIsDynamic(oneArg))
+ retval->argOidVect[i] = GetDynamicFuncArgType((Var *) oneArg,
+ econtext);
}
}
- else
- retval->argOidVect = (Oid *)NULL;
+ else
+ retval->argOidVect = (Oid *) NULL;
}
- else
+ else
{
- retval->argOidVect = (Oid *)NULL;
- retval->nullVect = (BoolPtr)NULL;
+ retval->argOidVect = (Oid *) NULL;
+ retval->nullVect = (BoolPtr) NULL;
}
-
- /*
- * XXX this is the first varlena in the struct. If the order
- * changes for some reason this will fail.
- */
- if (procedureStruct->prolang == SQLlanguageId)
+
+ /*
+ * XXX this is the first varlena in the struct. If the order changes
+ * for some reason this will fail.
+ */
+ if (procedureStruct->prolang == SQLlanguageId)
{
- retval->src = textout(&(procedureStruct->prosrc));
- retval->bin = (char *) NULL;
+ retval->src = textout(&(procedureStruct->prosrc));
+ retval->bin = (char *) NULL;
}
- else
+ else
{
-
- /*
- * I'm not sure that we even need to do this at all.
- */
-
- /*
- * We do for untrusted functions.
- */
-
- if (procedureStruct->proistrusted)
- retval->bin = (char *) NULL;
- else {
- tmp = (text *)
- SearchSysCacheGetAttribute(PROOID,
- Anum_pg_proc_probin,
- ObjectIdGetDatum(foid),
- 0,0,0);
- retval->bin = textout(tmp);
- }
- retval->src = (char *) NULL;
+
+ /*
+ * I'm not sure that we even need to do this at all.
+ */
+
+ /*
+ * We do for untrusted functions.
+ */
+
+ if (procedureStruct->proistrusted)
+ retval->bin = (char *) NULL;
+ else
+ {
+ tmp = (text *)
+ SearchSysCacheGetAttribute(PROOID,
+ Anum_pg_proc_probin,
+ ObjectIdGetDatum(foid),
+ 0, 0, 0);
+ retval->bin = textout(tmp);
+ }
+ retval->src = (char *) NULL;
}
-
-
-
-
- if (retval->language != SQLlanguageId)
- fmgr_info(foid, &(retval->func), &(retval->nargs));
- else
- retval->func = (func_ptr)NULL;
-
-
- return(retval);
+
+
+
+
+ if (retval->language != SQLlanguageId)
+ fmgr_info(foid, &(retval->func), &(retval->nargs));
+ else
+ retval->func = (func_ptr) NULL;
+
+
+ return (retval);
}
void
-setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext)
+setFcache(Node * node, Oid foid, List * argList, ExprContext * econtext)
{
- Func *fnode;
- Oper *onode;
- FunctionCachePtr fcache;
-
- fcache = init_fcache(foid, true, argList, econtext);
-
- if (IsA(node,Oper)) {
- onode = (Oper*) node;
- onode->op_fcache = fcache;
- }else if (IsA(node,Func)) {
- fnode = (Func*) node;
- fnode->func_fcache = fcache;
- }else {
- elog(WARN, "init_fcache: node must be Oper or Func!");
- }
+ Func *fnode;
+ Oper *onode;
+ FunctionCachePtr fcache;
+
+ fcache = init_fcache(foid, true, argList, econtext);
+
+ if (IsA(node, Oper))
+ {
+ onode = (Oper *) node;
+ onode->op_fcache = fcache;
+ }
+ else if (IsA(node, Func))
+ {
+ fnode = (Func *) node;
+ fnode->func_fcache = fcache;
+ }
+ else
+ {
+ elog(WARN, "init_fcache: node must be Oper or Func!");
+ }
}
diff --git a/src/backend/utils/cache/inval.c b/src/backend/utils/cache/inval.c
index 4f52e4e5f4c..4fb8a5eb6ed 100644
--- a/src/backend/utils/cache/inval.c
+++ b/src/backend/utils/cache/inval.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* inval.c--
- * POSTGRES cache invalidation dispatcher code.
+ * POSTGRES cache invalidation dispatcher code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.4 1997/08/19 21:35:06 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/inval.c,v 1.5 1997/09/07 04:53:01 momjian Exp $
*
* Note - this code is real crufty...
*
@@ -17,11 +17,11 @@
#include <miscadmin.h>
-#include "access/heapam.h" /* XXX to support hacks below */
+#include "access/heapam.h" /* XXX to support hacks below */
#include "access/htup.h"
#include "catalog/catalog.h"
#include "storage/bufpage.h"
-#include "storage/buf.h" /* XXX for InvalidBuffer */
+#include "storage/buf.h" /* XXX for InvalidBuffer */
#include "storage/ipc.h"
#include "storage/sinval.h"
#include "utils/catcache.h"
@@ -29,593 +29,615 @@
#include "utils/rel.h"
#include "utils/relcache.h"
#include "catalog/catname.h" /* XXX to support hacks below */
-#include "utils/syscache.h" /* XXX to support the hacks below */
+#include "utils/syscache.h" /* XXX to support the hacks below */
static InvalidationEntry InvalidationEntryAllocate(uint16 size);
-static void LocalInvalidInvalidate(LocalInvalid invalid, void (*function)());
-static LocalInvalid LocalInvalidRegister(LocalInvalid invalid,
+static void LocalInvalidInvalidate(LocalInvalid invalid, void (*function) ());
+static LocalInvalid
+LocalInvalidRegister(LocalInvalid invalid,
InvalidationEntry entry);
-static void getmyrelids(void);
+static void getmyrelids(void);
/* ----------------
- * private invalidation structures
+ * private invalidation structures
* ----------------
*/
-typedef struct CatalogInvalidationData {
- Index cacheId;
- Index hashIndex;
- ItemPointerData pointerData;
-} CatalogInvalidationData;
+typedef struct CatalogInvalidationData
+{
+ Index cacheId;
+ Index hashIndex;
+ ItemPointerData pointerData;
+} CatalogInvalidationData;
-typedef struct RelationInvalidationData {
- Oid relationId;
- Oid objectId;
-} RelationInvalidationData;
+typedef struct RelationInvalidationData
+{
+ Oid relationId;
+ Oid objectId;
+} RelationInvalidationData;
-typedef union AnyInvalidation {
- CatalogInvalidationData catalog;
- RelationInvalidationData relation;
-} AnyInvalidation;
+typedef union AnyInvalidation
+{
+ CatalogInvalidationData catalog;
+ RelationInvalidationData relation;
+} AnyInvalidation;
-typedef struct InvalidationMessageData {
- char kind;
- AnyInvalidation any;
-} InvalidationMessageData;
+typedef struct InvalidationMessageData
+{
+ char kind;
+ AnyInvalidation any;
+} InvalidationMessageData;
-typedef InvalidationMessageData *InvalidationMessage;
+typedef InvalidationMessageData *InvalidationMessage;
/* ----------------
- * variables and macros
+ * variables and macros
* ----------------
*/
-static LocalInvalid Invalid = EmptyLocalInvalid; /* XXX global */
-static bool RefreshWhenInvalidate = false;
+static LocalInvalid Invalid = EmptyLocalInvalid; /* XXX global */
+static bool RefreshWhenInvalidate = false;
-Oid MyRelationRelationId = InvalidOid;
-Oid MyAttributeRelationId = InvalidOid;
-Oid MyAMRelationId = InvalidOid;
-Oid MyAMOPRelationId = InvalidOid;
+Oid MyRelationRelationId = InvalidOid;
+Oid MyAttributeRelationId = InvalidOid;
+Oid MyAMRelationId = InvalidOid;
+Oid MyAMOPRelationId = InvalidOid;
#define ValidateHacks() \
- if (!OidIsValid(MyRelationRelationId)) getmyrelids()
+ if (!OidIsValid(MyRelationRelationId)) getmyrelids()
/* ----------------------------------------------------------------
- * "local" invalidation support functions
+ * "local" invalidation support functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * InvalidationEntryAllocate--
- * Allocates an invalidation entry.
+ * InvalidationEntryAllocate--
+ * Allocates an invalidation entry.
* --------------------------------
*/
-static InvalidationEntry
+static InvalidationEntry
InvalidationEntryAllocate(uint16 size)
{
- InvalidationEntryData *entryDataP;
- entryDataP = (InvalidationEntryData *)
- malloc(sizeof (char *) + size); /* XXX alignment */
- entryDataP->nextP = NULL;
- return ((Pointer) &entryDataP->userData);
+ InvalidationEntryData *entryDataP;
+
+ entryDataP = (InvalidationEntryData *)
+ malloc(sizeof(char *) + size); /* XXX alignment */
+ entryDataP->nextP = NULL;
+ return ((Pointer) & entryDataP->userData);
}
/* --------------------------------
- * LocalInvalidRegister --
- * Returns a new local cache invalidation state containing a new entry.
+ * LocalInvalidRegister --
+ * Returns a new local cache invalidation state containing a new entry.
* --------------------------------
*/
-static LocalInvalid
+static LocalInvalid
LocalInvalidRegister(LocalInvalid invalid,
- InvalidationEntry entry)
+ InvalidationEntry entry)
{
- Assert(PointerIsValid(entry));
-
- ((InvalidationUserData *)entry)->dataP[-1] =
- (InvalidationUserData *)invalid;
-
- return (entry);
+ Assert(PointerIsValid(entry));
+
+ ((InvalidationUserData *) entry)->dataP[-1] =
+ (InvalidationUserData *) invalid;
+
+ return (entry);
}
/* --------------------------------
- * LocalInvalidInvalidate--
- * Processes, then frees all entries in a local cache
- * invalidation state.
+ * LocalInvalidInvalidate--
+ * Processes, then frees all entries in a local cache
+ * invalidation state.
* --------------------------------
*/
static void
-LocalInvalidInvalidate(LocalInvalid invalid, void (*function)())
+LocalInvalidInvalidate(LocalInvalid invalid, void (*function) ())
{
- InvalidationEntryData *entryDataP;
-
- while (PointerIsValid(invalid)) {
- entryDataP = (InvalidationEntryData *)
- &((InvalidationUserData *)invalid)->dataP[-1];
-
- if (PointerIsValid(function)) {
- (*function)((Pointer) &entryDataP->userData);
+ InvalidationEntryData *entryDataP;
+
+ while (PointerIsValid(invalid))
+ {
+ entryDataP = (InvalidationEntryData *)
+ & ((InvalidationUserData *) invalid)->dataP[-1];
+
+ if (PointerIsValid(function))
+ {
+ (*function) ((Pointer) & entryDataP->userData);
+ }
+
+ invalid = (Pointer) entryDataP->nextP;
+
+ /* help catch errors */
+ entryDataP->nextP = (InvalidationUserData *) NULL;
+
+ free((Pointer) entryDataP);
}
-
- invalid = (Pointer) entryDataP->nextP;
-
- /* help catch errors */
- entryDataP->nextP = (InvalidationUserData *) NULL;
-
- free((Pointer)entryDataP);
- }
}
/* ----------------------------------------------------------------
- * private support functions
+ * private support functions
* ----------------------------------------------------------------
*/
/* --------------------------------
- * CacheIdRegisterLocalInvalid
+ * CacheIdRegisterLocalInvalid
* --------------------------------
*/
#ifdef INVALIDDEBUG
#define CacheIdRegisterLocalInvalid_DEBUG1 \
elog(DEBUG, "CacheIdRegisterLocalInvalid(%d, %d, [%d, %d])", \
- cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
- ItemPointerGetOffsetNumber(pointer))
+ cacheId, hashIndex, ItemPointerGetBlockNumber(pointer), \
+ ItemPointerGetOffsetNumber(pointer))
#else
#define CacheIdRegisterLocalInvalid_DEBUG1
-#endif /* INVALIDDEBUG */
-
+#endif /* INVALIDDEBUG */
+
static void
CacheIdRegisterLocalInvalid(Index cacheId,
- Index hashIndex,
- ItemPointer pointer)
+ Index hashIndex,
+ ItemPointer pointer)
{
- InvalidationMessage message;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
- CacheIdRegisterLocalInvalid_DEBUG1;
-
- /* ----------------
- * create a message describing the system catalog tuple
- * we wish to invalidate.
- * ----------------
- */
- message = (InvalidationMessage)
- InvalidationEntryAllocate(sizeof (InvalidationMessageData));
-
- message->kind = 'c';
- message->any.catalog.cacheId = cacheId;
- message->any.catalog.hashIndex = hashIndex;
-
- ItemPointerCopy(pointer, &message->any.catalog.pointerData);
-
- /* ----------------
- * Note: Invalid is a global variable
- * ----------------
- */
- Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry)message);
+ InvalidationMessage message;
+
+ /* ----------------
+ * debugging stuff
+ * ----------------
+ */
+ CacheIdRegisterLocalInvalid_DEBUG1;
+
+ /* ----------------
+ * create a message describing the system catalog tuple
+ * we wish to invalidate.
+ * ----------------
+ */
+ message = (InvalidationMessage)
+ InvalidationEntryAllocate(sizeof(InvalidationMessageData));
+
+ message->kind = 'c';
+ message->any.catalog.cacheId = cacheId;
+ message->any.catalog.hashIndex = hashIndex;
+
+ ItemPointerCopy(pointer, &message->any.catalog.pointerData);
+
+ /* ----------------
+ * Note: Invalid is a global variable
+ * ----------------
+ */
+ Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry) message);
}
/* --------------------------------
- * RelationIdRegisterLocalInvalid
+ * RelationIdRegisterLocalInvalid
* --------------------------------
*/
static void
RelationIdRegisterLocalInvalid(Oid relationId, Oid objectId)
{
- InvalidationMessage message;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
+ InvalidationMessage message;
+
+ /* ----------------
+ * debugging stuff
+ * ----------------
+ */
#ifdef INVALIDDEBUG
- elog(DEBUG, "RelationRegisterLocalInvalid(%d, %d)", relationId,
- objectId);
-#endif /* defined(INVALIDDEBUG) */
-
- /* ----------------
- * create a message describing the relation descriptor
- * we wish to invalidate.
- * ----------------
- */
- message = (InvalidationMessage)
- InvalidationEntryAllocate(sizeof (InvalidationMessageData));
-
- message->kind = 'r';
- message->any.relation.relationId = relationId;
- message->any.relation.objectId = objectId;
-
- /* ----------------
- * Note: Invalid is a global variable
- * ----------------
- */
- Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry)message);
+ elog(DEBUG, "RelationRegisterLocalInvalid(%d, %d)", relationId,
+ objectId);
+#endif /* defined(INVALIDDEBUG) */
+
+ /* ----------------
+ * create a message describing the relation descriptor
+ * we wish to invalidate.
+ * ----------------
+ */
+ message = (InvalidationMessage)
+ InvalidationEntryAllocate(sizeof(InvalidationMessageData));
+
+ message->kind = 'r';
+ message->any.relation.relationId = relationId;
+ message->any.relation.objectId = objectId;
+
+ /* ----------------
+ * Note: Invalid is a global variable
+ * ----------------
+ */
+ Invalid = LocalInvalidRegister(Invalid, (InvalidationEntry) message);
}
/* --------------------------------
- * getmyrelids
+ * getmyrelids
* --------------------------------
*/
static void
getmyrelids()
{
- HeapTuple tuple;
-
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(RelationRelationName),
- 0,0,0);
- Assert(HeapTupleIsValid(tuple));
- MyRelationRelationId = tuple->t_oid;
-
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(AttributeRelationName),
- 0,0,0);
- Assert(HeapTupleIsValid(tuple));
- MyAttributeRelationId = tuple->t_oid;
-
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(AccessMethodRelationName),
- 0,0,0);
- Assert(HeapTupleIsValid(tuple));
- MyAMRelationId = tuple->t_oid;
-
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(AccessMethodOperatorRelationName),
- 0,0,0);
- Assert(HeapTupleIsValid(tuple));
- MyAMOPRelationId = tuple->t_oid;
+ HeapTuple tuple;
+
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(RelationRelationName),
+ 0, 0, 0);
+ Assert(HeapTupleIsValid(tuple));
+ MyRelationRelationId = tuple->t_oid;
+
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(AttributeRelationName),
+ 0, 0, 0);
+ Assert(HeapTupleIsValid(tuple));
+ MyAttributeRelationId = tuple->t_oid;
+
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(AccessMethodRelationName),
+ 0, 0, 0);
+ Assert(HeapTupleIsValid(tuple));
+ MyAMRelationId = tuple->t_oid;
+
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(AccessMethodOperatorRelationName),
+ 0, 0, 0);
+ Assert(HeapTupleIsValid(tuple));
+ MyAMOPRelationId = tuple->t_oid;
}
/* --------------------------------
- * CacheIdInvalidate
+ * CacheIdInvalidate
*
- * This routine can invalidate an tuple in a system catalog cache
- * or a cached relation descriptor. You pay your money and you
- * take your chances...
+ * This routine can invalidate an tuple in a system catalog cache
+ * or a cached relation descriptor. You pay your money and you
+ * take your chances...
* --------------------------------
*/
#ifdef INVALIDDEBUG
#define CacheIdInvalidate_DEBUG1 \
elog(DEBUG, "CacheIdInvalidate(%d, %d, 0x%x[%d])", cacheId, hashIndex,\
- pointer, ItemPointerIsValid(pointer))
+ pointer, ItemPointerIsValid(pointer))
#else
#define CacheIdInvalidate_DEBUG1
-#endif /* defined(INVALIDDEBUG) */
-
+#endif /* defined(INVALIDDEBUG) */
+
static void
CacheIdInvalidate(Index cacheId,
- Index hashIndex,
- ItemPointer pointer)
+ Index hashIndex,
+ ItemPointer pointer)
{
- /* ----------------
- * assume that if the item pointer is valid, then we are
- * invalidating an item in the specified system catalog cache.
- * ----------------
- */
- if (ItemPointerIsValid(pointer)) {
- CatalogCacheIdInvalidate(cacheId, hashIndex, pointer);
- return;
- }
-
- CacheIdInvalidate_DEBUG1;
-
- ValidateHacks(); /* XXX */
-
- /* ----------------
- * if the cacheId is the oid of any of the tuples in the
- * following system relations, then assume we are invalidating
- * a relation descriptor
- * ----------------
- */
- if (cacheId == MyRelationRelationId) {
- RelationIdInvalidateRelationCacheByRelationId(hashIndex);
- return;
- }
-
- if (cacheId == MyAttributeRelationId) {
- RelationIdInvalidateRelationCacheByRelationId(hashIndex);
- return;
- }
-
- if (cacheId == MyAMRelationId) {
- RelationIdInvalidateRelationCacheByAccessMethodId(hashIndex);
- return;
- }
-
- if (cacheId == MyAMOPRelationId) {
- RelationIdInvalidateRelationCacheByAccessMethodId(InvalidOid);
- return;
- }
-
- /* ----------------
- * Yow! the caller asked us to invalidate something else.
- * ----------------
- */
- elog(FATAL, "CacheIdInvalidate: cacheId=%d relation id?", cacheId);
+ /* ----------------
+ * assume that if the item pointer is valid, then we are
+ * invalidating an item in the specified system catalog cache.
+ * ----------------
+ */
+ if (ItemPointerIsValid(pointer))
+ {
+ CatalogCacheIdInvalidate(cacheId, hashIndex, pointer);
+ return;
+ }
+
+ CacheIdInvalidate_DEBUG1;
+
+ ValidateHacks(); /* XXX */
+
+ /* ----------------
+ * if the cacheId is the oid of any of the tuples in the
+ * following system relations, then assume we are invalidating
+ * a relation descriptor
+ * ----------------
+ */
+ if (cacheId == MyRelationRelationId)
+ {
+ RelationIdInvalidateRelationCacheByRelationId(hashIndex);
+ return;
+ }
+
+ if (cacheId == MyAttributeRelationId)
+ {
+ RelationIdInvalidateRelationCacheByRelationId(hashIndex);
+ return;
+ }
+
+ if (cacheId == MyAMRelationId)
+ {
+ RelationIdInvalidateRelationCacheByAccessMethodId(hashIndex);
+ return;
+ }
+
+ if (cacheId == MyAMOPRelationId)
+ {
+ RelationIdInvalidateRelationCacheByAccessMethodId(InvalidOid);
+ return;
+ }
+
+ /* ----------------
+ * Yow! the caller asked us to invalidate something else.
+ * ----------------
+ */
+ elog(FATAL, "CacheIdInvalidate: cacheId=%d relation id?", cacheId);
}
/* --------------------------------
- * ResetSystemCaches
+ * ResetSystemCaches
*
- * this blows away all tuples in the system catalog caches and
- * all the cached relation descriptors (and closes the files too).
+ * this blows away all tuples in the system catalog caches and
+ * all the cached relation descriptors (and closes the files too).
* --------------------------------
*/
static void
ResetSystemCaches()
{
- ResetSystemCache();
- RelationCacheInvalidate(false);
+ ResetSystemCache();
+ RelationCacheInvalidate(false);
}
/* --------------------------------
- * InvalidationMessageRegisterSharedInvalid
+ * InvalidationMessageRegisterSharedInvalid
* --------------------------------
*/
#ifdef INVALIDDEBUG
#define InvalidationMessageRegisterSharedInvalid_DEBUG1 \
elog(DEBUG,\
- "InvalidationMessageRegisterSharedInvalid(c, %d, %d, [%d, %d])",\
- message->any.catalog.cacheId,\
- message->any.catalog.hashIndex,\
- ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
- ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
+ "InvalidationMessageRegisterSharedInvalid(c, %d, %d, [%d, %d])",\
+ message->any.catalog.cacheId,\
+ message->any.catalog.hashIndex,\
+ ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
+ ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
#define InvalidationMessageRegisterSharedInvalid_DEBUG2 \
- elog(DEBUG, \
- "InvalidationMessageRegisterSharedInvalid(r, %d, %d)", \
- message->any.relation.relationId, \
- message->any.relation.objectId)
-#else
+ elog(DEBUG, \
+ "InvalidationMessageRegisterSharedInvalid(r, %d, %d)", \
+ message->any.relation.relationId, \
+ message->any.relation.objectId)
+#else
#define InvalidationMessageRegisterSharedInvalid_DEBUG1
#define InvalidationMessageRegisterSharedInvalid_DEBUG2
-#endif /* INVALIDDEBUG */
-
+#endif /* INVALIDDEBUG */
+
static void
InvalidationMessageRegisterSharedInvalid(InvalidationMessage message)
{
- Assert(PointerIsValid(message));
-
- switch (message->kind) {
- case 'c': /* cached system catalog tuple */
- InvalidationMessageRegisterSharedInvalid_DEBUG1;
-
- RegisterSharedInvalid(message->any.catalog.cacheId,
- message->any.catalog.hashIndex,
- &message->any.catalog.pointerData);
- break;
-
- case 'r': /* cached relation descriptor */
- InvalidationMessageRegisterSharedInvalid_DEBUG2;
-
- RegisterSharedInvalid(message->any.relation.relationId,
- message->any.relation.objectId,
- (ItemPointer) NULL);
- break;
-
- default:
- elog(FATAL,
- "InvalidationMessageRegisterSharedInvalid: `%c' kind",
- message->kind);
- }
+ Assert(PointerIsValid(message));
+
+ switch (message->kind)
+ {
+ case 'c': /* cached system catalog tuple */
+ InvalidationMessageRegisterSharedInvalid_DEBUG1;
+
+ RegisterSharedInvalid(message->any.catalog.cacheId,
+ message->any.catalog.hashIndex,
+ &message->any.catalog.pointerData);
+ break;
+
+ case 'r': /* cached relation descriptor */
+ InvalidationMessageRegisterSharedInvalid_DEBUG2;
+
+ RegisterSharedInvalid(message->any.relation.relationId,
+ message->any.relation.objectId,
+ (ItemPointer) NULL);
+ break;
+
+ default:
+ elog(FATAL,
+ "InvalidationMessageRegisterSharedInvalid: `%c' kind",
+ message->kind);
+ }
}
/* --------------------------------
- * InvalidationMessageCacheInvalidate
+ * InvalidationMessageCacheInvalidate
* --------------------------------
*/
#ifdef INVALIDDEBUG
#define InvalidationMessageCacheInvalidate_DEBUG1 \
elog(DEBUG, "InvalidationMessageCacheInvalidate(c, %d, %d, [%d, %d])",\
- message->any.catalog.cacheId,\
- message->any.catalog.hashIndex,\
- ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
- ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
+ message->any.catalog.cacheId,\
+ message->any.catalog.hashIndex,\
+ ItemPointerGetBlockNumber(&message->any.catalog.pointerData),\
+ ItemPointerGetOffsetNumber(&message->any.catalog.pointerData))
#define InvalidationMessageCacheInvalidate_DEBUG2 \
- elog(DEBUG, "InvalidationMessageCacheInvalidate(r, %d, %d)", \
- message->any.relation.relationId, \
- message->any.relation.objectId)
+ elog(DEBUG, "InvalidationMessageCacheInvalidate(r, %d, %d)", \
+ message->any.relation.relationId, \
+ message->any.relation.objectId)
#else
#define InvalidationMessageCacheInvalidate_DEBUG1
#define InvalidationMessageCacheInvalidate_DEBUG2
-#endif /* defined(INVALIDDEBUG) */
-
+#endif /* defined(INVALIDDEBUG) */
+
static void
InvalidationMessageCacheInvalidate(InvalidationMessage message)
{
- Assert(PointerIsValid(message));
-
- switch (message->kind) {
- case 'c': /* cached system catalog tuple */
- InvalidationMessageCacheInvalidate_DEBUG1;
-
- CatalogCacheIdInvalidate(message->any.catalog.cacheId,
- message->any.catalog.hashIndex,
- &message->any.catalog.pointerData);
- break;
-
- case 'r': /* cached relation descriptor */
- InvalidationMessageCacheInvalidate_DEBUG2;
-
- /* XXX ignore this--is this correct ??? */
- break;
-
- default:
- elog(FATAL, "InvalidationMessageCacheInvalidate: `%c' kind",
- message->kind);
- }
+ Assert(PointerIsValid(message));
+
+ switch (message->kind)
+ {
+ case 'c': /* cached system catalog tuple */
+ InvalidationMessageCacheInvalidate_DEBUG1;
+
+ CatalogCacheIdInvalidate(message->any.catalog.cacheId,
+ message->any.catalog.hashIndex,
+ &message->any.catalog.pointerData);
+ break;
+
+ case 'r': /* cached relation descriptor */
+ InvalidationMessageCacheInvalidate_DEBUG2;
+
+ /* XXX ignore this--is this correct ??? */
+ break;
+
+ default:
+ elog(FATAL, "InvalidationMessageCacheInvalidate: `%c' kind",
+ message->kind);
+ }
}
/* --------------------------------
- * RelationInvalidateRelationCache
+ * RelationInvalidateRelationCache
* --------------------------------
*/
static void
RelationInvalidateRelationCache(Relation relation,
- HeapTuple tuple,
- void (*function)())
+ HeapTuple tuple,
+ void (*function) ())
{
- Oid relationId;
- Oid objectId = (Oid)0;
-
- /* ----------------
- * get the relation object id
- * ----------------
- */
- ValidateHacks(); /* XXX */
- relationId = RelationGetRelationId(relation);
-
- /* ----------------
- *
- * ----------------
- */
- if (relationId == MyRelationRelationId) {
- objectId = tuple->t_oid;
- } else if (relationId == MyAttributeRelationId) {
- objectId = ((AttributeTupleForm)GETSTRUCT(tuple))->attrelid;
- } else if (relationId == MyAMRelationId) {
- objectId = tuple->t_oid;
- } else if (relationId == MyAMOPRelationId) {
- ; /* objectId is unused */
- } else
- return;
-
- /* ----------------
- * can't handle immediate relation descriptor invalidation
- * ----------------
- */
- Assert(PointerIsValid(function));
-
- (*function)(relationId, objectId);
+ Oid relationId;
+ Oid objectId = (Oid) 0;
+
+ /* ----------------
+ * get the relation object id
+ * ----------------
+ */
+ ValidateHacks(); /* XXX */
+ relationId = RelationGetRelationId(relation);
+
+ /* ----------------
+ *
+ * ----------------
+ */
+ if (relationId == MyRelationRelationId)
+ {
+ objectId = tuple->t_oid;
+ }
+ else if (relationId == MyAttributeRelationId)
+ {
+ objectId = ((AttributeTupleForm) GETSTRUCT(tuple))->attrelid;
+ }
+ else if (relationId == MyAMRelationId)
+ {
+ objectId = tuple->t_oid;
+ }
+ else if (relationId == MyAMOPRelationId)
+ {
+ ; /* objectId is unused */
+ }
+ else
+ return;
+
+ /* ----------------
+ * can't handle immediate relation descriptor invalidation
+ * ----------------
+ */
+ Assert(PointerIsValid(function));
+
+ (*function) (relationId, objectId);
}
/*
* DiscardInvalid --
- * Causes the invalidated cache state to be discarded.
+ * Causes the invalidated cache state to be discarded.
*
* Note:
- * This should be called as the first step in processing a transaction.
- * This should be called while waiting for a query from the front end
- * when other backends are active.
+ * This should be called as the first step in processing a transaction.
+ * This should be called while waiting for a query from the front end
+ * when other backends are active.
*/
void
DiscardInvalid()
{
- /* ----------------
- * debugging stuff
- * ----------------
- */
+ /* ----------------
+ * debugging stuff
+ * ----------------
+ */
#ifdef INVALIDDEBUG
- elog(DEBUG, "DiscardInvalid called");
-#endif /* defined(INVALIDDEBUG) */
-
- InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);
+ elog(DEBUG, "DiscardInvalid called");
+#endif /* defined(INVALIDDEBUG) */
+
+ InvalidateSharedInvalid(CacheIdInvalidate, ResetSystemCaches);
}
/*
* RegisterInvalid --
- * Causes registration of invalidated state with other backends iff true.
+ * Causes registration of invalidated state with other backends iff true.
*
* Note:
- * This should be called as the last step in processing a transaction.
+ * This should be called as the last step in processing a transaction.
*/
void
RegisterInvalid(bool send)
{
- /* ----------------
- * debugging stuff
- * ----------------
- */
+ /* ----------------
+ * debugging stuff
+ * ----------------
+ */
#ifdef INVALIDDEBUG
- elog(DEBUG, "RegisterInvalid(%d) called", send);
-#endif /* defined(INVALIDDEBUG) */
-
- /* ----------------
- * Note: Invalid is a global variable
- * ----------------
- */
- if (send)
- LocalInvalidInvalidate(Invalid,
- InvalidationMessageRegisterSharedInvalid);
- else
- LocalInvalidInvalidate(Invalid,
- InvalidationMessageCacheInvalidate);
-
- Invalid = EmptyLocalInvalid;
+ elog(DEBUG, "RegisterInvalid(%d) called", send);
+#endif /* defined(INVALIDDEBUG) */
+
+ /* ----------------
+ * Note: Invalid is a global variable
+ * ----------------
+ */
+ if (send)
+ LocalInvalidInvalidate(Invalid,
+ InvalidationMessageRegisterSharedInvalid);
+ else
+ LocalInvalidInvalidate(Invalid,
+ InvalidationMessageCacheInvalidate);
+
+ Invalid = EmptyLocalInvalid;
}
/*
* SetRefreshWhenInvalidate --
- * Causes the local caches to be immediately refreshed iff true.
+ * Causes the local caches to be immediately refreshed iff true.
*/
void
SetRefreshWhenInvalidate(bool on)
{
#ifdef INVALIDDEBUG
- elog(DEBUG, "RefreshWhenInvalidate(%d) called", on);
-#endif /* defined(INVALIDDEBUG) */
-
- RefreshWhenInvalidate = on;
+ elog(DEBUG, "RefreshWhenInvalidate(%d) called", on);
+#endif /* defined(INVALIDDEBUG) */
+
+ RefreshWhenInvalidate = on;
}
/*
* RelationIdInvalidateHeapTuple --
- * Causes the given tuple in a relation to be invalidated.
+ * Causes the given tuple in a relation to be invalidated.
*
* Note:
- * Assumes object id is valid.
- * Assumes tuple is valid.
+ * Assumes object id is valid.
+ * Assumes tuple is valid.
*/
#ifdef INVALIDDEBUG
#define RelationInvalidateHeapTuple_DEBUG1 \
elog(DEBUG, "RelationInvalidateHeapTuple(%.16s, [%d,%d])", \
- RelationGetRelationName(relation), \
- ItemPointerGetBlockNumber(&tuple->t_ctid), \
- ItemPointerGetOffsetNumber(&tuple->t_ctid))
+ RelationGetRelationName(relation), \
+ ItemPointerGetBlockNumber(&tuple->t_ctid), \
+ ItemPointerGetOffsetNumber(&tuple->t_ctid))
#else
#define RelationInvalidateHeapTuple_DEBUG1
-#endif /* defined(INVALIDDEBUG) */
-
+#endif /* defined(INVALIDDEBUG) */
+
void
RelationInvalidateHeapTuple(Relation relation, HeapTuple tuple)
{
- /* ----------------
- * sanity checks
- * ----------------
- */
- Assert(RelationIsValid(relation));
- Assert(HeapTupleIsValid(tuple));
-
- if (IsBootstrapProcessingMode())
- return;
- /* ----------------
- * this only works for system relations now
- * ----------------
- */
- if (! IsSystemRelationName(RelationGetRelationTupleForm(relation)->relname.data))
- return;
-
- /* ----------------
- * debugging stuff
- * ----------------
- */
- RelationInvalidateHeapTuple_DEBUG1;
-
- /* ----------------
- *
- * ----------------
- */
- RelationInvalidateCatalogCacheTuple(relation,
- tuple,
- CacheIdRegisterLocalInvalid);
-
- RelationInvalidateRelationCache(relation,
- tuple,
- RelationIdRegisterLocalInvalid);
-
- if (RefreshWhenInvalidate)
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ Assert(RelationIsValid(relation));
+ Assert(HeapTupleIsValid(tuple));
+
+ if (IsBootstrapProcessingMode())
+ return;
+ /* ----------------
+ * this only works for system relations now
+ * ----------------
+ */
+ if (!IsSystemRelationName(RelationGetRelationTupleForm(relation)->relname.data))
+ return;
+
+ /* ----------------
+ * debugging stuff
+ * ----------------
+ */
+ RelationInvalidateHeapTuple_DEBUG1;
+
+ /* ----------------
+ *
+ * ----------------
+ */
RelationInvalidateCatalogCacheTuple(relation,
- tuple,
- (void (*)()) NULL);
-}
+ tuple,
+ CacheIdRegisterLocalInvalid);
+ RelationInvalidateRelationCache(relation,
+ tuple,
+ RelationIdRegisterLocalInvalid);
+
+ if (RefreshWhenInvalidate)
+ RelationInvalidateCatalogCacheTuple(relation,
+ tuple,
+ (void (*) ()) NULL);
+}
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 9de0c3fb89b..37280036970 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -1,20 +1,20 @@
/*-------------------------------------------------------------------------
*
* lsyscache.c--
- * Routines to access information within system caches
+ * Routines to access information within system caches
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.3 1997/08/19 21:35:11 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.4 1997/09/07 04:53:04 momjian Exp $
*
* NOTES
- * Eventually, the index information should go through here, too.
- *
- * Most of these routines call SearchSysCacheStruct() and thus simply
- * (1) allocate some space for the return struct and (2) call it.
- *
+ * Eventually, the index information should go through here, too.
+ *
+ * Most of these routines call SearchSysCacheStruct() and thus simply
+ * (1) allocate some space for the return struct and (2) call it.
+ *
*-------------------------------------------------------------------------
*/
#include <string.h>
@@ -34,99 +34,100 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
-/* ---------- AMOP CACHES ---------- */
+/* ---------- AMOP CACHES ---------- */
-/*
+/*
* op_class -
- *
- * Return t iff operator 'opno' is in operator class 'opclass'.
- *
+ *
+ * Return t iff operator 'opno' is in operator class 'opclass'.
+ *
*/
bool
op_class(Oid opno, int32 opclass, Oid amopid)
{
- FormData_pg_amop amoptup;
-
- if (SearchSysCacheStruct(AMOPOPID,
- (char *) &amoptup,
- ObjectIdGetDatum(opclass),
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(amopid),
- 0))
- return(true);
- else
- return(false);
+ FormData_pg_amop amoptup;
+
+ if (SearchSysCacheStruct(AMOPOPID,
+ (char *) &amoptup,
+ ObjectIdGetDatum(opclass),
+ ObjectIdGetDatum(opno),
+ ObjectIdGetDatum(amopid),
+ 0))
+ return (true);
+ else
+ return (false);
}
-/* ---------- ATTRIBUTE CACHES ---------- */
+/* ---------- ATTRIBUTE CACHES ---------- */
-/*
+/*
* get_attname -
- *
- * Given the relation id and the attribute number,
- * return the "attname" field from the attribute relation.
- *
+ *
+ * Given the relation id and the attribute number,
+ * return the "attname" field from the attribute relation.
+ *
*/
-char*
+char *
get_attname(Oid relid, AttrNumber attnum)
{
- FormData_pg_attribute att_tup;
- char *retval;
-
- if (SearchSysCacheStruct(ATTNUM,
- (char*)&att_tup,
- ObjectIdGetDatum(relid),
- UInt16GetDatum(attnum),
- 0,0)) {
- retval = pstrdup(att_tup.attname.data);
-
- return(retval);
- }
- else
- return(NULL);
+ FormData_pg_attribute att_tup;
+ char *retval;
+
+ if (SearchSysCacheStruct(ATTNUM,
+ (char *) &att_tup,
+ ObjectIdGetDatum(relid),
+ UInt16GetDatum(attnum),
+ 0, 0))
+ {
+ retval = pstrdup(att_tup.attname.data);
+
+ return (retval);
+ }
+ else
+ return (NULL);
}
-/*
+/*
* get_attnum -
- *
- * Given the relation id and the attribute name,
- * return the "attnum" field from the attribute relation.
- *
+ *
+ * Given the relation id and the attribute name,
+ * return the "attnum" field from the attribute relation.
+ *
*/
AttrNumber
get_attnum(Oid relid, char *attname)
{
- FormData_pg_attribute att_tup;
-
- if (SearchSysCacheStruct(ATTNAME, (char *) &att_tup,
- ObjectIdGetDatum(relid),
- PointerGetDatum(attname),
- 0,0))
- return(att_tup.attnum);
- else
- return(InvalidAttrNumber);
+ FormData_pg_attribute att_tup;
+
+ if (SearchSysCacheStruct(ATTNAME, (char *) &att_tup,
+ ObjectIdGetDatum(relid),
+ PointerGetDatum(attname),
+ 0, 0))
+ return (att_tup.attnum);
+ else
+ return (InvalidAttrNumber);
}
-/*
+/*
* get_atttype -
- *
- * Given the relation OID and the attribute number with the relation,
- * return the attribute type OID.
- *
+ *
+ * Given the relation OID and the attribute number with the relation,
+ * return the attribute type OID.
+ *
*/
Oid
get_atttype(Oid relid, AttrNumber attnum)
{
- AttributeTupleForm att_tup = (AttributeTupleForm)palloc(sizeof(*att_tup));
-
- if (SearchSysCacheStruct(ATTNUM,
- (char *) att_tup,
- ObjectIdGetDatum(relid),
- UInt16GetDatum(attnum),
- 0,0))
- return(att_tup->atttypid);
- else
- return((Oid)NULL);
+ AttributeTupleForm att_tup = (AttributeTupleForm) palloc(sizeof(*att_tup));
+
+ if (SearchSysCacheStruct(ATTNUM,
+ (char *) att_tup,
+ ObjectIdGetDatum(relid),
+ UInt16GetDatum(attnum),
+ 0, 0))
+ return (att_tup->atttypid);
+ else
+ return ((Oid) NULL);
}
/* This routine uses the attname instead of the attnum because it
@@ -136,353 +137,366 @@ get_atttype(Oid relid, AttrNumber attnum)
bool
get_attisset(Oid relid, char *attname)
{
- HeapTuple htup;
- AttrNumber attno;
- AttributeTupleForm att_tup;
-
- attno = get_attnum(relid, attname);
-
- htup = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relid),
- PointerGetDatum(attname),
- 0,0);
- if (!HeapTupleIsValid(htup))
- elog(WARN, "get_attisset: no attribute %.16s in relation %d",
- attname, relid);
- if (heap_attisnull(htup, attno))
- return(false);
- else {
- att_tup = (AttributeTupleForm)GETSTRUCT(htup);
- return(att_tup->attisset);
- }
+ HeapTuple htup;
+ AttrNumber attno;
+ AttributeTupleForm att_tup;
+
+ attno = get_attnum(relid, attname);
+
+ htup = SearchSysCacheTuple(ATTNAME,
+ ObjectIdGetDatum(relid),
+ PointerGetDatum(attname),
+ 0, 0);
+ if (!HeapTupleIsValid(htup))
+ elog(WARN, "get_attisset: no attribute %.16s in relation %d",
+ attname, relid);
+ if (heap_attisnull(htup, attno))
+ return (false);
+ else
+ {
+ att_tup = (AttributeTupleForm) GETSTRUCT(htup);
+ return (att_tup->attisset);
+ }
}
-/* ---------- INDEX CACHE ---------- */
+/* ---------- INDEX CACHE ---------- */
-/* watch this space...
+/* watch this space...
*/
-/* ---------- OPERATOR CACHE ---------- */
+/* ---------- OPERATOR CACHE ---------- */
-/*
+/*
* get_opcode -
- *
- * Returns the regproc id of the routine used to implement an
- * operator given the operator uid.
- *
+ *
+ * Returns the regproc id of the routine used to implement an
+ * operator given the operator uid.
+ *
*/
RegProcedure
get_opcode(Oid opno)
{
- FormData_pg_operator optup;
-
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0,0,0))
- return(optup.oprcode);
- else
- return((RegProcedure)NULL);
+ FormData_pg_operator optup;
+
+ if (SearchSysCacheStruct(OPROID, (char *) &optup,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0))
+ return (optup.oprcode);
+ else
+ return ((RegProcedure) NULL);
}
/*
* get_opname -
- * returns the name of the operator with the given opno
+ * returns the name of the operator with the given opno
*
* Note: return the struct so that it gets copied.
*/
-char*
+char *
get_opname(Oid opno)
{
- FormData_pg_operator optup;
-
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0,0,0))
- return (pstrdup(optup.oprname.data));
- else {
- elog(WARN, "can't look up operator %d\n", opno);
- return NULL;
- }
+ FormData_pg_operator optup;
+
+ if (SearchSysCacheStruct(OPROID, (char *) &optup,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0))
+ return (pstrdup(optup.oprname.data));
+ else
+ {
+ elog(WARN, "can't look up operator %d\n", opno);
+ return NULL;
+ }
}
-/*
+/*
* op_mergesortable -
- *
- * Returns the left and right sort operators and types corresponding to a
- * mergesortable operator, or nil if the operator is not mergesortable.
- *
+ *
+ * Returns the left and right sort operators and types corresponding to a
+ * mergesortable operator, or nil if the operator is not mergesortable.
+ *
*/
bool
-op_mergesortable(Oid opno, Oid ltype, Oid rtype, Oid *leftOp, Oid *rightOp)
+op_mergesortable(Oid opno, Oid ltype, Oid rtype, Oid * leftOp, Oid * rightOp)
{
- FormData_pg_operator optup;
-
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0,0,0) &&
- optup.oprlsortop &&
- optup.oprrsortop &&
- optup.oprleft == ltype &&
- optup.oprright == rtype) {
-
- *leftOp = ObjectIdGetDatum(optup.oprlsortop);
- *rightOp = ObjectIdGetDatum(optup.oprrsortop);
- return TRUE;
- } else {
- return FALSE;
- }
+ FormData_pg_operator optup;
+
+ if (SearchSysCacheStruct(OPROID, (char *) &optup,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0) &&
+ optup.oprlsortop &&
+ optup.oprrsortop &&
+ optup.oprleft == ltype &&
+ optup.oprright == rtype)
+ {
+
+ *leftOp = ObjectIdGetDatum(optup.oprlsortop);
+ *rightOp = ObjectIdGetDatum(optup.oprrsortop);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
}
-/*
+/*
* op_hashjoinable--
- *
- * Returns the hash operator corresponding to a hashjoinable operator,
+ *
+ * Returns the hash operator corresponding to a hashjoinable operator,
* or nil if the operator is not hashjoinable.
- *
+ *
*/
Oid
op_hashjoinable(Oid opno, Oid ltype, Oid rtype)
{
- FormData_pg_operator optup;
-
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0,0,0) &&
- optup.oprcanhash &&
- optup.oprleft == ltype &&
- optup.oprright == rtype)
- return(opno);
- else
- return(InvalidOid);
+ FormData_pg_operator optup;
+
+ if (SearchSysCacheStruct(OPROID, (char *) &optup,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0) &&
+ optup.oprcanhash &&
+ optup.oprleft == ltype &&
+ optup.oprright == rtype)
+ return (opno);
+ else
+ return (InvalidOid);
}
-/*
+/*
* get_commutator -
- *
- * Returns the corresponding commutator of an operator.
- *
+ *
+ * Returns the corresponding commutator of an operator.
+ *
*/
Oid
get_commutator(Oid opno)
{
- FormData_pg_operator optup;
-
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0,0,0))
- return(optup.oprcom);
- else
- return((Oid)NULL);
+ FormData_pg_operator optup;
+
+ if (SearchSysCacheStruct(OPROID, (char *) &optup,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0))
+ return (optup.oprcom);
+ else
+ return ((Oid) NULL);
}
HeapTuple
get_operator_tuple(Oid opno)
{
- HeapTuple optup;
-
- if ((optup = SearchSysCacheTuple(OPROID,
- ObjectIdGetDatum(opno),
- 0,0,0)))
- return(optup);
- else
- return((HeapTuple)NULL);
+ HeapTuple optup;
+
+ if ((optup = SearchSysCacheTuple(OPROID,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0)))
+ return (optup);
+ else
+ return ((HeapTuple) NULL);
}
-/*
+/*
* get_negator -
- *
- * Returns the corresponding negator of an operator.
- *
+ *
+ * Returns the corresponding negator of an operator.
+ *
*/
Oid
get_negator(Oid opno)
{
- FormData_pg_operator optup;
-
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0,0,0))
- return(optup.oprnegate);
- else
- return((Oid)NULL);
+ FormData_pg_operator optup;
+
+ if (SearchSysCacheStruct(OPROID, (char *) &optup,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0))
+ return (optup.oprnegate);
+ else
+ return ((Oid) NULL);
}
-/*
+/*
* get_oprrest -
- *
- * Returns procedure id for computing selectivity of an operator.
- *
+ *
+ * Returns procedure id for computing selectivity of an operator.
+ *
*/
RegProcedure
get_oprrest(Oid opno)
{
- FormData_pg_operator optup;
-
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0,0,0))
- return(optup.oprrest );
- else
- return((RegProcedure) NULL);
+ FormData_pg_operator optup;
+
+ if (SearchSysCacheStruct(OPROID, (char *) &optup,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0))
+ return (optup.oprrest);
+ else
+ return ((RegProcedure) NULL);
}
-/*
+/*
* get_oprjoin -
- *
- * Returns procedure id for computing selectivity of a join.
- *
+ *
+ * Returns procedure id for computing selectivity of a join.
+ *
*/
RegProcedure
get_oprjoin(Oid opno)
{
- FormData_pg_operator optup;
-
- if (SearchSysCacheStruct(OPROID, (char *) &optup,
- ObjectIdGetDatum(opno),
- 0,0,0))
- return(optup.oprjoin);
- else
- return((RegProcedure)NULL);
+ FormData_pg_operator optup;
+
+ if (SearchSysCacheStruct(OPROID, (char *) &optup,
+ ObjectIdGetDatum(opno),
+ 0, 0, 0))
+ return (optup.oprjoin);
+ else
+ return ((RegProcedure) NULL);
}
-/* ---------- RELATION CACHE ---------- */
+/* ---------- RELATION CACHE ---------- */
-/*
+/*
* get_relnatts -
- *
- * Returns the number of attributes for a given relation.
- *
+ *
+ * Returns the number of attributes for a given relation.
+ *
*/
int
get_relnatts(Oid relid)
{
- FormData_pg_class reltup;
-
- if (SearchSysCacheStruct(RELOID, (char *) &reltup,
- ObjectIdGetDatum(relid),
- 0,0,0))
- return(reltup.relnatts);
- else
- return(InvalidAttrNumber);
+ FormData_pg_class reltup;
+
+ if (SearchSysCacheStruct(RELOID, (char *) &reltup,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0))
+ return (reltup.relnatts);
+ else
+ return (InvalidAttrNumber);
}
-/*
+/*
* get_rel_name -
- *
- * Returns the name of a given relation.
- *
+ *
+ * Returns the name of a given relation.
+ *
*/
-char*
+char *
get_rel_name(Oid relid)
{
- FormData_pg_class reltup;
-
- if ((SearchSysCacheStruct(RELOID,
- (char*)&reltup,
- ObjectIdGetDatum(relid),
- 0,0,0))) {
- return (pstrdup(reltup.relname.data));
- } else
- return(NULL);
+ FormData_pg_class reltup;
+
+ if ((SearchSysCacheStruct(RELOID,
+ (char *) &reltup,
+ ObjectIdGetDatum(relid),
+ 0, 0, 0)))
+ {
+ return (pstrdup(reltup.relname.data));
+ }
+ else
+ return (NULL);
}
-/* ---------- TYPE CACHE ---------- */
+/* ---------- TYPE CACHE ---------- */
-/*
+/*
* get_typlen -
- *
- * Given the type OID, return the length of the type.
- *
+ *
+ * Given the type OID, return the length of the type.
+ *
*/
int16
get_typlen(Oid typid)
{
- TypeTupleFormData typtup;
-
- if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
- ObjectIdGetDatum(typid),
- 0,0,0))
- return(typtup.typlen);
- else
- return((int16)NULL);
+ TypeTupleFormData typtup;
+
+ if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0))
+ return (typtup.typlen);
+ else
+ return ((int16) NULL);
}
-/*
+/*
* get_typbyval -
- *
- * Given the type OID, determine whether the type is returned by value or
- * not. Returns 1 if by value, 0 if by reference.
- *
+ *
+ * Given the type OID, determine whether the type is returned by value or
+ * not. Returns 1 if by value, 0 if by reference.
+ *
*/
bool
get_typbyval(Oid typid)
{
- TypeTupleFormData typtup;
-
- if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
- ObjectIdGetDatum(typid),
- 0,0,0))
- return((bool)typtup.typbyval);
- else
- return(false);
+ TypeTupleFormData typtup;
+
+ if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0))
+ return ((bool) typtup.typbyval);
+ else
+ return (false);
}
-/*
+/*
* get_typbyval -
- *
- * Given the type OID, determine whether the type is returned by value or
- * not. Returns 1 if by value, 0 if by reference.
- *
+ *
+ * Given the type OID, determine whether the type is returned by value or
+ * not. Returns 1 if by value, 0 if by reference.
+ *
*/
#ifdef NOT_USED
char
get_typalign(Oid typid)
{
- TypeTupleFormData typtup;
-
- if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
- ObjectIdGetDatum(typid),
- 0,0,0))
- return(typtup.typalign);
- else
- return ('i');
+ TypeTupleFormData typtup;
+
+ if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0))
+ return (typtup.typalign);
+ else
+ return ('i');
}
+
#endif
-/*
- * get_typdefault -
- *
- * Given the type OID, return the default value of the ADT.
- *
+/*
+ * get_typdefault -
+ *
+ * Given the type OID, return the default value of the ADT.
+ *
*/
struct varlena *
get_typdefault(Oid typid)
{
- struct varlena *typdefault =
- (struct varlena *)TypeDefaultRetrieve (typid);
- return(typdefault);
+ struct varlena *typdefault =
+ (struct varlena *) TypeDefaultRetrieve(typid);
+
+ return (typdefault);
}
-/*
+/*
* get_typtype -
- *
- * Given the type OID, find if it is a basic type, a named relation
- * or the generic type 'relation'.
- * It returns the null char if the cache lookup fails...
- *
+ *
+ * Given the type OID, find if it is a basic type, a named relation
+ * or the generic type 'relation'.
+ * It returns the null char if the cache lookup fails...
+ *
*/
#ifdef NOT_USED
char
get_typtype(Oid typid)
{
- TypeTupleFormData typtup;
-
- if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
- ObjectIdGetDatum(typid),
- 0,0,0)) {
- return(typtup.typtype);
- } else {
- return('\0');
- }
+ TypeTupleFormData typtup;
+
+ if (SearchSysCacheStruct(TYPOID, (char *) &typtup,
+ ObjectIdGetDatum(typid),
+ 0, 0, 0))
+ {
+ return (typtup.typtype);
+ }
+ else
+ {
+ return ('\0');
+ }
}
+
#endif
diff --git a/src/backend/utils/cache/rel.c b/src/backend/utils/cache/rel.c
index 33eabad1a85..4e45138037c 100644
--- a/src/backend/utils/cache/rel.c
+++ b/src/backend/utils/cache/rel.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* rel.c--
- * POSTGRES relation descriptor code.
+ * POSTGRES relation descriptor code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/rel.c,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/rel.c,v 1.2 1997/09/07 04:53:07 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,57 +21,56 @@
#include "storage/fd.h"
-/*
- * RelationIsValid is now a macro in rel.h -cim 4/27/91
+/*
+ * RelationIsValid is now a macro in rel.h -cim 4/27/91
*
- * Many of the RelationGet...() functions are now macros in rel.h
- * -mer 3/2/92
+ * Many of the RelationGet...() functions are now macros in rel.h
+ * -mer 3/2/92
*/
/*
* RelationGetIndexStrategy --
- * Returns index strategy for a relation.
+ * Returns index strategy for a relation.
*
* Note:
- * Assumes relation descriptor is valid.
- * Assumes relation descriptor is for an index relation.
+ * Assumes relation descriptor is valid.
+ * Assumes relation descriptor is for an index relation.
*/
IndexStrategy
RelationGetIndexStrategy(Relation relation)
{
- return relation->rd_istrat;
+ return relation->rd_istrat;
}
/*
* RelationSetIndexSupport --
- * Sets index strategy and support info for a relation.
+ * Sets index strategy and support info for a relation.
*
* Note:
- * Assumes relation descriptor is a valid pointer to sufficient space.
- * Assumes index strategy is valid. Assumes support is valid if non-
- * NULL.
+ * Assumes relation descriptor is a valid pointer to sufficient space.
+ * Assumes index strategy is valid. Assumes support is valid if non-
+ * NULL.
*/
/* ----------------
- * RelationSetIndexSupport
+ * RelationSetIndexSupport
*
- * This routine saves two pointers -- one to the IndexStrategy, and
- * one to the RegProcs that support the indexed access method. These
- * pointers are stored in the space following the attribute data in the
- * reldesc.
+ * This routine saves two pointers -- one to the IndexStrategy, and
+ * one to the RegProcs that support the indexed access method. These
+ * pointers are stored in the space following the attribute data in the
+ * reldesc.
*
- * NEW: the index strategy and support are now stored in real fields
- * at the end of the structure - jolly
+ * NEW: the index strategy and support are now stored in real fields
+ * at the end of the structure - jolly
* ----------------
*/
void
RelationSetIndexSupport(Relation relation,
- IndexStrategy strategy,
- RegProcedure *support)
+ IndexStrategy strategy,
+ RegProcedure * support)
{
- Assert(PointerIsValid(relation));
- Assert(IndexStrategyIsValid(strategy));
-
- relation->rd_istrat = strategy;
- relation->rd_support = support;
-}
+ Assert(PointerIsValid(relation));
+ Assert(IndexStrategyIsValid(strategy));
+ relation->rd_istrat = strategy;
+ relation->rd_support = support;
+}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index a54f1d81387..704d673279b 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1,41 +1,41 @@
/*-------------------------------------------------------------------------
*
* relcache.c--
- * POSTGRES relation descriptor cache code
+ * POSTGRES relation descriptor cache code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.20 1997/09/01 08:04:38 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.21 1997/09/07 04:53:08 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
- * RelationInitialize - initialize relcache
- * RelationIdCacheGetRelation - get a reldesc from the cache (id)
- * RelationNameCacheGetRelation - get a reldesc from the cache (name)
- * RelationIdGetRelation - get a reldesc by relation id
- * RelationNameGetRelation - get a reldesc by relation name
- * RelationClose - close an open relation
- * RelationFlushRelation - flush relation information
+ * RelationInitialize - initialize relcache
+ * RelationIdCacheGetRelation - get a reldesc from the cache (id)
+ * RelationNameCacheGetRelation - get a reldesc from the cache (name)
+ * RelationIdGetRelation - get a reldesc by relation id
+ * RelationNameGetRelation - get a reldesc by relation name
+ * RelationClose - close an open relation
+ * RelationFlushRelation - flush relation information
*
* NOTES
- * This file is in the process of being cleaned up
- * before I add system attribute indexing. -cim 1/13/91
+ * This file is in the process of being cleaned up
+ * before I add system attribute indexing. -cim 1/13/91
*
- * The following code contains many undocumented hacks. Please be
- * careful....
+ * The following code contains many undocumented hacks. Please be
+ * careful....
*
*/
#include <sys/types.h>
-#include <stdio.h> /* for sprintf() */
+#include <stdio.h> /* for sprintf() */
#include <errno.h>
#include <sys/file.h>
#include <fcntl.h>
#include <string.h>
-
+
#include "postgres.h"
#include "miscadmin.h"
@@ -51,21 +51,21 @@
#include "access/tupdesc.h"
#include "access/tupmacs.h"
#include "access/xact.h"
-
+
#include "storage/buf.h"
-#include "storage/fd.h" /* for SEEK_ */
+#include "storage/fd.h" /* for SEEK_ */
#include "storage/lmgr.h"
#include "storage/bufmgr.h"
-
+
#include "lib/hasht.h"
-
+
#include "utils/memutils.h"
#include "utils/mcxt.h"
#include "utils/rel.h"
#include "utils/relcache.h"
#include "utils/hsearch.h"
#include "utils/relcache.h"
-
+
#include "catalog/catname.h"
#include "catalog/catalog.h"
#include "utils/syscache.h"
@@ -87,1744 +87,1813 @@
#include "catalog/index.h"
#include "fmgr.h"
-static void RelationFlushRelation(Relation *relationPtr,
- bool onlyFlushReferenceCountZero);
+static void
+RelationFlushRelation(Relation * relationPtr,
+ bool onlyFlushReferenceCountZero);
static Relation RelationNameCacheGetRelation(char *relationName);
-static void init_irels(void);
-static void write_irels(void);
+static void init_irels(void);
+static void write_irels(void);
/* ----------------
- * defines
+ * defines
* ----------------
*/
#define private static
#define INIT_FILENAME "pg_internal.init"
/* ----------------
- * externs
+ * externs
* ----------------
*/
-extern bool AMI_OVERRIDE; /* XXX style */
+extern bool AMI_OVERRIDE; /* XXX style */
extern GlobalMemory CacheCxt; /* from utils/cache/catcache.c */
/* ----------------
- * hardcoded tuple descriptors. see lib/backend/catalog/pg_attribute.h
+ * hardcoded tuple descriptors. see lib/backend/catalog/pg_attribute.h
* ----------------
*/
-FormData_pg_attribute Desc_pg_class[Natts_pg_class] = { Schema_pg_class };
-FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = { Schema_pg_attribute };
-FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = { Schema_pg_proc };
-FormData_pg_attribute Desc_pg_type[Natts_pg_type] = { Schema_pg_type };
-FormData_pg_attribute Desc_pg_variable[Natts_pg_variable] = { Schema_pg_variable };
-FormData_pg_attribute Desc_pg_log[Natts_pg_log] = { Schema_pg_log };
-FormData_pg_attribute Desc_pg_time[Natts_pg_time] = { Schema_pg_time };
+FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};
+FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute};
+FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc};
+FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type};
+FormData_pg_attribute Desc_pg_variable[Natts_pg_variable] = {Schema_pg_variable};
+FormData_pg_attribute Desc_pg_log[Natts_pg_log] = {Schema_pg_log};
+FormData_pg_attribute Desc_pg_time[Natts_pg_time] = {Schema_pg_time};
/* ----------------
- * global variables
+ * global variables
*
- * Relations are cached two ways, by name and by id,
- * thus there are two hash tables for referencing them.
+ * Relations are cached two ways, by name and by id,
+ * thus there are two hash tables for referencing them.
* ----------------
*/
-HTAB *RelationNameCache;
-HTAB *RelationIdCache;
+HTAB *RelationNameCache;
+HTAB *RelationIdCache;
/* ----------------
- * RelationBuildDescInfo exists so code can be shared
- * between RelationIdGetRelation() and RelationNameGetRelation()
+ * RelationBuildDescInfo exists so code can be shared
+ * between RelationIdGetRelation() and RelationNameGetRelation()
* ----------------
*/
-typedef struct RelationBuildDescInfo {
- int infotype; /* lookup by id or by name */
+typedef struct RelationBuildDescInfo
+{
+ int infotype; /* lookup by id or by name */
#define INFO_RELID 1
#define INFO_RELNAME 2
- union {
- Oid info_id; /* relation object id */
- char *info_name; /* relation name */
- } i;
-} RelationBuildDescInfo;
-
-typedef struct relidcacheent {
- Oid reloid;
- Relation reldesc;
-} RelIdCacheEnt;
-
-typedef struct relnamecacheent {
- NameData relname;
- Relation reldesc;
-} RelNameCacheEnt;
+ union
+ {
+ Oid info_id;/* relation object id */
+ char *info_name; /* relation name */
+ } i;
+} RelationBuildDescInfo;
+
+typedef struct relidcacheent
+{
+ Oid reloid;
+ Relation reldesc;
+} RelIdCacheEnt;
+
+typedef struct relnamecacheent
+{
+ NameData relname;
+ Relation reldesc;
+} RelNameCacheEnt;
/* -----------------
- * macros to manipulate name cache and id cache
+ * macros to manipulate name cache and id cache
* -----------------
*/
#define RelationCacheInsert(RELATION) \
- { RelIdCacheEnt *idhentry; RelNameCacheEnt *namehentry; \
- char *relname; Oid reloid; bool found; \
- relname = (RELATION->rd_rel->relname).data; \
- namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
- relname, \
- HASH_ENTER, \
- &found); \
- if (namehentry == NULL) { \
- elog(FATAL, "can't insert into relation descriptor cache"); \
- } \
- if (found && !IsBootstrapProcessingMode()) { \
- /* used to give notice -- now just keep quiet */ ; \
- } \
- namehentry->reldesc = RELATION; \
- reloid = RELATION->rd_id; \
- idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
- (char *)&reloid, \
- HASH_ENTER, \
- &found); \
- if (idhentry == NULL) { \
- elog(FATAL, "can't insert into relation descriptor cache"); \
- } \
- if (found && !IsBootstrapProcessingMode()) { \
- /* used to give notice -- now just keep quiet */ ; \
- } \
- idhentry->reldesc = RELATION; \
- }
-#define RelationNameCacheLookup(NAME, RELATION) \
- { RelNameCacheEnt *hentry; bool found; \
- hentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
- (char *)NAME,HASH_FIND,&found); \
- if (hentry == NULL) { \
- elog(FATAL, "error in CACHE"); \
- } \
- if (found) { \
- RELATION = hentry->reldesc; \
- } \
- else { \
- RELATION = NULL; \
- } \
- }
-#define RelationIdCacheLookup(ID, RELATION) \
- { RelIdCacheEnt *hentry; bool found; \
- hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
- (char *)&(ID),HASH_FIND, &found); \
- if (hentry == NULL) { \
- elog(FATAL, "error in CACHE"); \
- } \
- if (found) { \
- RELATION = hentry->reldesc; \
- } \
- else { \
- RELATION = NULL; \
- } \
- }
+ { RelIdCacheEnt *idhentry; RelNameCacheEnt *namehentry; \
+ char *relname; Oid reloid; bool found; \
+ relname = (RELATION->rd_rel->relname).data; \
+ namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
+ relname, \
+ HASH_ENTER, \
+ &found); \
+ if (namehentry == NULL) { \
+ elog(FATAL, "can't insert into relation descriptor cache"); \
+ } \
+ if (found && !IsBootstrapProcessingMode()) { \
+ /* used to give notice -- now just keep quiet */ ; \
+ } \
+ namehentry->reldesc = RELATION; \
+ reloid = RELATION->rd_id; \
+ idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
+ (char *)&reloid, \
+ HASH_ENTER, \
+ &found); \
+ if (idhentry == NULL) { \
+ elog(FATAL, "can't insert into relation descriptor cache"); \
+ } \
+ if (found && !IsBootstrapProcessingMode()) { \
+ /* used to give notice -- now just keep quiet */ ; \
+ } \
+ idhentry->reldesc = RELATION; \
+ }
+#define RelationNameCacheLookup(NAME, RELATION) \
+ { RelNameCacheEnt *hentry; bool found; \
+ hentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
+ (char *)NAME,HASH_FIND,&found); \
+ if (hentry == NULL) { \
+ elog(FATAL, "error in CACHE"); \
+ } \
+ if (found) { \
+ RELATION = hentry->reldesc; \
+ } \
+ else { \
+ RELATION = NULL; \
+ } \
+ }
+#define RelationIdCacheLookup(ID, RELATION) \
+ { RelIdCacheEnt *hentry; bool found; \
+ hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
+ (char *)&(ID),HASH_FIND, &found); \
+ if (hentry == NULL) { \
+ elog(FATAL, "error in CACHE"); \
+ } \
+ if (found) { \
+ RELATION = hentry->reldesc; \
+ } \
+ else { \
+ RELATION = NULL; \
+ } \
+ }
#define RelationCacheDelete(RELATION) \
- { RelNameCacheEnt *namehentry; RelIdCacheEnt *idhentry; \
- char *relname; Oid reloid; bool found; \
- relname = (RELATION->rd_rel->relname).data; \
- namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
- relname, \
- HASH_REMOVE, \
- &found); \
- if (namehentry == NULL) { \
- elog(FATAL, "can't delete from relation descriptor cache"); \
- } \
- if (!found) { \
- elog(NOTICE, "trying to delete a reldesc that does not exist."); \
- } \
- reloid = RELATION->rd_id; \
- idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
- (char *)&reloid, \
- HASH_REMOVE, &found); \
- if (idhentry == NULL) { \
- elog(FATAL, "can't delete from relation descriptor cache"); \
- } \
- if (!found) { \
- elog(NOTICE, "trying to delete a reldesc that does not exist."); \
- } \
- }
+ { RelNameCacheEnt *namehentry; RelIdCacheEnt *idhentry; \
+ char *relname; Oid reloid; bool found; \
+ relname = (RELATION->rd_rel->relname).data; \
+ namehentry = (RelNameCacheEnt*)hash_search(RelationNameCache, \
+ relname, \
+ HASH_REMOVE, \
+ &found); \
+ if (namehentry == NULL) { \
+ elog(FATAL, "can't delete from relation descriptor cache"); \
+ } \
+ if (!found) { \
+ elog(NOTICE, "trying to delete a reldesc that does not exist."); \
+ } \
+ reloid = RELATION->rd_id; \
+ idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \
+ (char *)&reloid, \
+ HASH_REMOVE, &found); \
+ if (idhentry == NULL) { \
+ elog(FATAL, "can't delete from relation descriptor cache"); \
+ } \
+ if (!found) { \
+ elog(NOTICE, "trying to delete a reldesc that does not exist."); \
+ } \
+ }
/* non-export function prototypes */
-static void formrdesc(char *relationName, u_int natts,
- FormData_pg_attribute att[]);
+static void
+formrdesc(char *relationName, u_int natts,
+ FormData_pg_attribute att[]);
+
+#if 0 /* See comments at line 1304 */
+static void RelationFlushIndexes(Relation * r, Oid accessMethodId);
-#if 0 /* See comments at line 1304 */
-static void RelationFlushIndexes(Relation *r, Oid accessMethodId);
#endif
static HeapTuple ScanPgRelation(RelationBuildDescInfo buildinfo);
static HeapTuple scan_pg_rel_seq(RelationBuildDescInfo buildinfo);
static HeapTuple scan_pg_rel_ind(RelationBuildDescInfo buildinfo);
static Relation AllocateRelationDesc(u_int natts, Form_pg_class relp);
-static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
- Relation relation, u_int natts);
-static void build_tupdesc_seq(RelationBuildDescInfo buildinfo,
- Relation relation, u_int natts);
-static void build_tupdesc_ind(RelationBuildDescInfo buildinfo,
- Relation relation, u_int natts);
+static void
+RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
+ Relation relation, u_int natts);
+static void
+build_tupdesc_seq(RelationBuildDescInfo buildinfo,
+ Relation relation, u_int natts);
+static void
+build_tupdesc_ind(RelationBuildDescInfo buildinfo,
+ Relation relation, u_int natts);
static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo);
-static void IndexedAccessMethodInitialize(Relation relation);
-static void AttrDefaultFetch (Relation relation);
-static void RelCheckFetch (Relation relation);
+static void IndexedAccessMethodInitialize(Relation relation);
+static void AttrDefaultFetch(Relation relation);
+static void RelCheckFetch(Relation relation);
-extern void RelationBuildTriggers (Relation relation);
-extern void FreeTriggerDesc (Relation relation);
+extern void RelationBuildTriggers(Relation relation);
+extern void FreeTriggerDesc(Relation relation);
/*
* newlyCreatedRelns -
- * relations created during this transaction. We need to keep track of
- * these.
+ * relations created during this transaction. We need to keep track of
+ * these.
*/
-static List *newlyCreatedRelns = NULL;
+static List *newlyCreatedRelns = NULL;
/* ----------------------------------------------------------------
- * RelationIdGetRelation() and RelationNameGetRelation()
- * support functions
+ * RelationIdGetRelation() and RelationNameGetRelation()
+ * support functions
* ----------------------------------------------------------------
*/
-
-#if NOT_USED /* XXX This doesn't seem to be used anywhere */
+
+#if NOT_USED /* XXX This doesn't seem to be used
+ * anywhere */
/* --------------------------------
- * BuildDescInfoError returns a string appropriate to
- * the buildinfo passed to it
+ * BuildDescInfoError returns a string appropriate to
+ * the buildinfo passed to it
* --------------------------------
*/
-static char *
+static char *
BuildDescInfoError(RelationBuildDescInfo buildinfo)
{
- static char errBuf[64];
-
- memset(errBuf, 0, (int) sizeof(errBuf));
- switch(buildinfo.infotype) {
- case INFO_RELID:
- sprintf(errBuf, "(relation id %d)", buildinfo.i.info_id);
- break;
- case INFO_RELNAME:
- sprintf(errBuf, "(relation name %s)", buildinfo.i.info_name);
- break;
- }
-
- return errBuf;
+ static char errBuf[64];
+
+ memset(errBuf, 0, (int) sizeof(errBuf));
+ switch (buildinfo.infotype)
+ {
+ case INFO_RELID:
+ sprintf(errBuf, "(relation id %d)", buildinfo.i.info_id);
+ break;
+ case INFO_RELNAME:
+ sprintf(errBuf, "(relation name %s)", buildinfo.i.info_name);
+ break;
+ }
+
+ return errBuf;
}
+
#endif
/* --------------------------------
- * ScanPgRelation
+ * ScanPgRelation
*
- * this is used by RelationBuildDesc to find a pg_class
- * tuple matching either a relation name or a relation id
- * as specified in buildinfo.
+ * this is used by RelationBuildDesc to find a pg_class
+ * tuple matching either a relation name or a relation id
+ * as specified in buildinfo.
* --------------------------------
*/
-static HeapTuple
+static HeapTuple
ScanPgRelation(RelationBuildDescInfo buildinfo)
{
- /*
- * If this is bootstrap time (initdb), then we can't use the system
- * catalog indices, because they may not exist yet. Otherwise, we
- * can, and do.
- */
-
- if (IsBootstrapProcessingMode())
- return (scan_pg_rel_seq(buildinfo));
- else
- return (scan_pg_rel_ind(buildinfo));
+
+ /*
+ * If this is bootstrap time (initdb), then we can't use the system
+ * catalog indices, because they may not exist yet. Otherwise, we
+ * can, and do.
+ */
+
+ if (IsBootstrapProcessingMode())
+ return (scan_pg_rel_seq(buildinfo));
+ else
+ return (scan_pg_rel_ind(buildinfo));
}
-static HeapTuple
+static HeapTuple
scan_pg_rel_seq(RelationBuildDescInfo buildinfo)
{
- HeapTuple pg_class_tuple;
- HeapTuple return_tuple;
- Relation pg_class_desc;
- HeapScanDesc pg_class_scan;
- ScanKeyData key;
- Buffer buf;
-
- /* ----------------
- * form a scan key
- * ----------------
- */
- switch (buildinfo.infotype) {
- case INFO_RELID:
- ScanKeyEntryInitialize(&key, 0,
- ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(buildinfo.i.info_id));
- break;
-
- case INFO_RELNAME:
- ScanKeyEntryInitialize(&key, 0,
- Anum_pg_class_relname,
- Character16EqualRegProcedure,
- NameGetDatum(buildinfo.i.info_name));
- break;
-
- default:
- elog(WARN, "ScanPgRelation: bad buildinfo");
- return NULL;
- }
-
- /* ----------------
- * open pg_class and fetch a tuple
- * ----------------
- */
- pg_class_desc = heap_openr(RelationRelationName);
- if (!IsInitProcessingMode())
- RelationSetLockForRead(pg_class_desc);
- pg_class_scan =
- heap_beginscan(pg_class_desc, 0, NowTimeQual, 1, &key);
- pg_class_tuple = heap_getnext(pg_class_scan, 0, &buf);
-
- /* ----------------
- * get set to return tuple
- * ----------------
- */
- if (! HeapTupleIsValid(pg_class_tuple)) {
- return_tuple = pg_class_tuple;
- } else {
- /* ------------------
- * a satanic bug used to live here: pg_class_tuple used to be
- * returned here without having the corresponding buffer pinned.
- * so when the buffer gets replaced, all hell breaks loose.
- * this bug is discovered and killed by wei on 9/27/91.
- * -------------------
+ HeapTuple pg_class_tuple;
+ HeapTuple return_tuple;
+ Relation pg_class_desc;
+ HeapScanDesc pg_class_scan;
+ ScanKeyData key;
+ Buffer buf;
+
+ /* ----------------
+ * form a scan key
+ * ----------------
*/
- return_tuple = (HeapTuple) palloc((Size) pg_class_tuple->t_len);
- memmove((char *) return_tuple,
- (char *) pg_class_tuple,
- (int) pg_class_tuple->t_len);
- ReleaseBuffer(buf);
- }
-
- /* all done */
- heap_endscan(pg_class_scan);
- if (!IsInitProcessingMode())
- RelationUnsetLockForRead(pg_class_desc);
- heap_close(pg_class_desc);
-
- return return_tuple;
+ switch (buildinfo.infotype)
+ {
+ case INFO_RELID:
+ ScanKeyEntryInitialize(&key, 0,
+ ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(buildinfo.i.info_id));
+ break;
+
+ case INFO_RELNAME:
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_class_relname,
+ Character16EqualRegProcedure,
+ NameGetDatum(buildinfo.i.info_name));
+ break;
+
+ default:
+ elog(WARN, "ScanPgRelation: bad buildinfo");
+ return NULL;
+ }
+
+ /* ----------------
+ * open pg_class and fetch a tuple
+ * ----------------
+ */
+ pg_class_desc = heap_openr(RelationRelationName);
+ if (!IsInitProcessingMode())
+ RelationSetLockForRead(pg_class_desc);
+ pg_class_scan =
+ heap_beginscan(pg_class_desc, 0, NowTimeQual, 1, &key);
+ pg_class_tuple = heap_getnext(pg_class_scan, 0, &buf);
+
+ /* ----------------
+ * get set to return tuple
+ * ----------------
+ */
+ if (!HeapTupleIsValid(pg_class_tuple))
+ {
+ return_tuple = pg_class_tuple;
+ }
+ else
+ {
+ /* ------------------
+ * a satanic bug used to live here: pg_class_tuple used to be
+ * returned here without having the corresponding buffer pinned.
+ * so when the buffer gets replaced, all hell breaks loose.
+ * this bug is discovered and killed by wei on 9/27/91.
+ * -------------------
+ */
+ return_tuple = (HeapTuple) palloc((Size) pg_class_tuple->t_len);
+ memmove((char *) return_tuple,
+ (char *) pg_class_tuple,
+ (int) pg_class_tuple->t_len);
+ ReleaseBuffer(buf);
+ }
+
+ /* all done */
+ heap_endscan(pg_class_scan);
+ if (!IsInitProcessingMode())
+ RelationUnsetLockForRead(pg_class_desc);
+ heap_close(pg_class_desc);
+
+ return return_tuple;
}
-static HeapTuple
+static HeapTuple
scan_pg_rel_ind(RelationBuildDescInfo buildinfo)
{
- Relation pg_class_desc;
- HeapTuple return_tuple;
-
- pg_class_desc = heap_openr(RelationRelationName);
- if (!IsInitProcessingMode())
- RelationSetLockForRead(pg_class_desc);
-
- switch (buildinfo.infotype) {
- case INFO_RELID:
- return_tuple = ClassOidIndexScan(pg_class_desc, buildinfo.i.info_id);
- break;
-
- case INFO_RELNAME:
- return_tuple = ClassNameIndexScan(pg_class_desc,
- buildinfo.i.info_name);
- break;
-
- default:
- elog(WARN, "ScanPgRelation: bad buildinfo");
- /* XXX I hope this is right. It seems better than returning
- * an uninitialized value */
- return_tuple = NULL;
- }
-
- /* all done */
- if (!IsInitProcessingMode())
- RelationUnsetLockForRead(pg_class_desc);
- heap_close(pg_class_desc);
-
- return return_tuple;
+ Relation pg_class_desc;
+ HeapTuple return_tuple;
+
+ pg_class_desc = heap_openr(RelationRelationName);
+ if (!IsInitProcessingMode())
+ RelationSetLockForRead(pg_class_desc);
+
+ switch (buildinfo.infotype)
+ {
+ case INFO_RELID:
+ return_tuple = ClassOidIndexScan(pg_class_desc, buildinfo.i.info_id);
+ break;
+
+ case INFO_RELNAME:
+ return_tuple = ClassNameIndexScan(pg_class_desc,
+ buildinfo.i.info_name);
+ break;
+
+ default:
+ elog(WARN, "ScanPgRelation: bad buildinfo");
+
+ /*
+ * XXX I hope this is right. It seems better than returning an
+ * uninitialized value
+ */
+ return_tuple = NULL;
+ }
+
+ /* all done */
+ if (!IsInitProcessingMode())
+ RelationUnsetLockForRead(pg_class_desc);
+ heap_close(pg_class_desc);
+
+ return return_tuple;
}
/* ----------------
- * AllocateRelationDesc
+ * AllocateRelationDesc
*
- * This is used to allocate memory for a new relation descriptor
- * and initialize the rd_rel field.
+ * This is used to allocate memory for a new relation descriptor
+ * and initialize the rd_rel field.
* ----------------
*/
-static Relation
+static Relation
AllocateRelationDesc(u_int natts, Form_pg_class relp)
{
- Relation relation;
- Size len;
- Form_pg_class relationTupleForm;
-
- /* ----------------
- * allocate space for the relation tuple form
- * ----------------
- */
- relationTupleForm = (Form_pg_class)
- palloc((Size) (sizeof(FormData_pg_class)));
-
- memmove((char *) relationTupleForm, (char *) relp, CLASS_TUPLE_SIZE);
-
- /* ----------------
- * allocate space for new relation descriptor
- */
- len = sizeof(RelationData) + 10; /* + 10 is voodoo XXX mao */
-
- relation = (Relation) palloc(len);
-
- /* ----------------
- * clear new reldesc
- * ----------------
- */
- memset((char *) relation, 0, len);
-
- /* initialize attribute tuple form */
- relation->rd_att = CreateTemplateTupleDesc(natts);
-
- /*and initialize relation tuple form */
- relation->rd_rel = relationTupleForm;
-
- return relation;
+ Relation relation;
+ Size len;
+ Form_pg_class relationTupleForm;
+
+ /* ----------------
+ * allocate space for the relation tuple form
+ * ----------------
+ */
+ relationTupleForm = (Form_pg_class)
+ palloc((Size) (sizeof(FormData_pg_class)));
+
+ memmove((char *) relationTupleForm, (char *) relp, CLASS_TUPLE_SIZE);
+
+ /* ----------------
+ * allocate space for new relation descriptor
+ */
+ len = sizeof(RelationData) + 10; /* + 10 is voodoo XXX mao */
+
+ relation = (Relation) palloc(len);
+
+ /* ----------------
+ * clear new reldesc
+ * ----------------
+ */
+ memset((char *) relation, 0, len);
+
+ /* initialize attribute tuple form */
+ relation->rd_att = CreateTemplateTupleDesc(natts);
+
+ /* and initialize relation tuple form */
+ relation->rd_rel = relationTupleForm;
+
+ return relation;
}
/* --------------------------------
- * RelationBuildTupleDesc
+ * RelationBuildTupleDesc
*
- * Form the relation's tuple descriptor from information in
- * the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
+ * Form the relation's tuple descriptor from information in
+ * the pg_attribute, pg_attrdef & pg_relcheck system cataloges.
* --------------------------------
*/
static void
-RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
- Relation relation,
- u_int natts)
+RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
+ Relation relation,
+ u_int natts)
{
- /*
- * If this is bootstrap time (initdb), then we can't use the system
- * catalog indices, because they may not exist yet. Otherwise, we
- * can, and do.
- */
-
- if (IsBootstrapProcessingMode())
- build_tupdesc_seq(buildinfo, relation, natts);
- else
- build_tupdesc_ind(buildinfo, relation, natts);
+
+ /*
+ * If this is bootstrap time (initdb), then we can't use the system
+ * catalog indices, because they may not exist yet. Otherwise, we
+ * can, and do.
+ */
+
+ if (IsBootstrapProcessingMode())
+ build_tupdesc_seq(buildinfo, relation, natts);
+ else
+ build_tupdesc_ind(buildinfo, relation, natts);
}
static void
build_tupdesc_seq(RelationBuildDescInfo buildinfo,
- Relation relation,
- u_int natts)
+ Relation relation,
+ u_int natts)
{
- HeapTuple pg_attribute_tuple;
- Relation pg_attribute_desc;
- HeapScanDesc pg_attribute_scan;
- AttributeTupleForm attp;
- ScanKeyData key;
- int need;
-
- /* ----------------
- * form a scan key
- * ----------------
- */
- ScanKeyEntryInitialize(&key, 0,
- Anum_pg_attribute_attrelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relation->rd_id));
-
- /* ----------------
- * open pg_attribute and begin a scan
- * ----------------
- */
- pg_attribute_desc = heap_openr(AttributeRelationName);
- pg_attribute_scan =
- heap_beginscan(pg_attribute_desc, 0, NowTimeQual, 1, &key);
-
- /* ----------------
- * add attribute data to relation->rd_att
- * ----------------
- */
- need = natts;
-
- pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0, (Buffer *) NULL);
- while (HeapTupleIsValid(pg_attribute_tuple) && need > 0) {
- attp = (AttributeTupleForm) GETSTRUCT(pg_attribute_tuple);
-
- if (attp->attnum > 0) {
- relation->rd_att->attrs[attp->attnum - 1] =
- (AttributeTupleForm)palloc(ATTRIBUTE_TUPLE_SIZE);
-
- memmove((char *) (relation->rd_att->attrs[attp->attnum - 1]),
- (char *) attp,
- ATTRIBUTE_TUPLE_SIZE);
- need--;
+ HeapTuple pg_attribute_tuple;
+ Relation pg_attribute_desc;
+ HeapScanDesc pg_attribute_scan;
+ AttributeTupleForm attp;
+ ScanKeyData key;
+ int need;
+
+ /* ----------------
+ * form a scan key
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_attribute_attrelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relation->rd_id));
+
+ /* ----------------
+ * open pg_attribute and begin a scan
+ * ----------------
+ */
+ pg_attribute_desc = heap_openr(AttributeRelationName);
+ pg_attribute_scan =
+ heap_beginscan(pg_attribute_desc, 0, NowTimeQual, 1, &key);
+
+ /* ----------------
+ * add attribute data to relation->rd_att
+ * ----------------
+ */
+ need = natts;
+
+ pg_attribute_tuple = heap_getnext(pg_attribute_scan, 0, (Buffer *) NULL);
+ while (HeapTupleIsValid(pg_attribute_tuple) && need > 0)
+ {
+ attp = (AttributeTupleForm) GETSTRUCT(pg_attribute_tuple);
+
+ if (attp->attnum > 0)
+ {
+ relation->rd_att->attrs[attp->attnum - 1] =
+ (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+
+ memmove((char *) (relation->rd_att->attrs[attp->attnum - 1]),
+ (char *) attp,
+ ATTRIBUTE_TUPLE_SIZE);
+ need--;
+ }
+ pg_attribute_tuple = heap_getnext(pg_attribute_scan,
+ 0, (Buffer *) NULL);
}
- pg_attribute_tuple = heap_getnext(pg_attribute_scan,
- 0, (Buffer *) NULL);
- }
-
- if (need > 0)
- elog(WARN, "catalog is missing %d attribute%s for relid %d",
- need, (need == 1 ? "" : "s"), relation->rd_id);
-
- /* ----------------
- * end the scan and close the attribute relation
- * ----------------
- */
- heap_endscan(pg_attribute_scan);
- heap_close(pg_attribute_desc);
+
+ if (need > 0)
+ elog(WARN, "catalog is missing %d attribute%s for relid %d",
+ need, (need == 1 ? "" : "s"), relation->rd_id);
+
+ /* ----------------
+ * end the scan and close the attribute relation
+ * ----------------
+ */
+ heap_endscan(pg_attribute_scan);
+ heap_close(pg_attribute_desc);
}
static void
build_tupdesc_ind(RelationBuildDescInfo buildinfo,
- Relation relation,
- u_int natts)
+ Relation relation,
+ u_int natts)
{
- Relation attrel;
- HeapTuple atttup;
- AttributeTupleForm attp;
- TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
- AttrDefault *attrdef = NULL;
- int ndef = 0;
- int i;
-
- constr->has_not_null = false;
-
- attrel = heap_openr(AttributeRelationName);
-
- for (i = 1; i <= relation->rd_rel->relnatts; i++) {
-
- atttup = (HeapTuple) AttributeNumIndexScan(attrel, relation->rd_id, i);
-
- if (!HeapTupleIsValid(atttup))
- elog(WARN, "cannot find attribute %d of relation %.*s", i,
- NAMEDATALEN, &(relation->rd_rel->relname.data[0]));
- attp = (AttributeTupleForm) GETSTRUCT(atttup);
-
- relation->rd_att->attrs[i - 1] =
- (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
-
- memmove((char *) (relation->rd_att->attrs[i - 1]),
- (char *) attp,
- ATTRIBUTE_TUPLE_SIZE);
-
- /* Update if this attribute have a constraint */
- if (attp->attnotnull)
- constr->has_not_null = true;
-
- if (attp->atthasdef)
+ Relation attrel;
+ HeapTuple atttup;
+ AttributeTupleForm attp;
+ TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
+ AttrDefault *attrdef = NULL;
+ int ndef = 0;
+ int i;
+
+ constr->has_not_null = false;
+
+ attrel = heap_openr(AttributeRelationName);
+
+ for (i = 1; i <= relation->rd_rel->relnatts; i++)
{
- if ( attrdef == NULL )
- attrdef = (AttrDefault*) palloc (relation->rd_rel->relnatts *
- sizeof (AttrDefault));
- attrdef[ndef].adnum = i;
- attrdef[ndef].adbin = NULL;
- attrdef[ndef].adsrc = NULL;
- ndef++;
+
+ atttup = (HeapTuple) AttributeNumIndexScan(attrel, relation->rd_id, i);
+
+ if (!HeapTupleIsValid(atttup))
+ elog(WARN, "cannot find attribute %d of relation %.*s", i,
+ NAMEDATALEN, &(relation->rd_rel->relname.data[0]));
+ attp = (AttributeTupleForm) GETSTRUCT(atttup);
+
+ relation->rd_att->attrs[i - 1] =
+ (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+
+ memmove((char *) (relation->rd_att->attrs[i - 1]),
+ (char *) attp,
+ ATTRIBUTE_TUPLE_SIZE);
+
+ /* Update if this attribute have a constraint */
+ if (attp->attnotnull)
+ constr->has_not_null = true;
+
+ if (attp->atthasdef)
+ {
+ if (attrdef == NULL)
+ attrdef = (AttrDefault *) palloc(relation->rd_rel->relnatts *
+ sizeof(AttrDefault));
+ attrdef[ndef].adnum = i;
+ attrdef[ndef].adbin = NULL;
+ attrdef[ndef].adsrc = NULL;
+ ndef++;
+ }
}
- }
-
- heap_close(attrel);
-
- if ( constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks )
- {
- relation->rd_att->constr = constr;
-
- if ( ndef > 0 ) /* DEFAULTs */
- {
- if ( ndef < relation->rd_rel->relnatts )
- constr->defval = (AttrDefault*)
- repalloc (attrdef, ndef * sizeof (AttrDefault));
- else
- constr->defval = attrdef;
- constr->num_defval = ndef;
- AttrDefaultFetch (relation);
- }
- else
- constr->num_defval = 0;
-
- if ( relation->rd_rel->relchecks > 0 ) /* CHECKs */
+
+ heap_close(attrel);
+
+ if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks)
{
- constr->num_check = relation->rd_rel->relchecks;
- constr->check = (ConstrCheck *) palloc (constr->num_check *
- sizeof (ConstrCheck));
- memset (constr->check, 0, constr->num_check * sizeof (ConstrCheck));
- RelCheckFetch (relation);
+ relation->rd_att->constr = constr;
+
+ if (ndef > 0) /* DEFAULTs */
+ {
+ if (ndef < relation->rd_rel->relnatts)
+ constr->defval = (AttrDefault *)
+ repalloc(attrdef, ndef * sizeof(AttrDefault));
+ else
+ constr->defval = attrdef;
+ constr->num_defval = ndef;
+ AttrDefaultFetch(relation);
+ }
+ else
+ constr->num_defval = 0;
+
+ if (relation->rd_rel->relchecks > 0) /* CHECKs */
+ {
+ constr->num_check = relation->rd_rel->relchecks;
+ constr->check = (ConstrCheck *) palloc(constr->num_check *
+ sizeof(ConstrCheck));
+ memset(constr->check, 0, constr->num_check * sizeof(ConstrCheck));
+ RelCheckFetch(relation);
+ }
+ else
+ constr->num_check = 0;
}
else
- constr->num_check = 0;
- }
- else
- {
- pfree (constr);
- relation->rd_att->constr = NULL;
- }
-
+ {
+ pfree(constr);
+ relation->rd_att->constr = NULL;
+ }
+
}
/* --------------------------------
- * RelationBuildRuleLock
+ * RelationBuildRuleLock
*
- * Form the relation's rewrite rules from information in
- * the pg_rewrite system catalog.
+ * Form the relation's rewrite rules from information in
+ * the pg_rewrite system catalog.
* --------------------------------
*/
static void
RelationBuildRuleLock(Relation relation)
{
- HeapTuple pg_rewrite_tuple;
- Relation pg_rewrite_desc;
- TupleDesc pg_rewrite_tupdesc;
- HeapScanDesc pg_rewrite_scan;
- ScanKeyData key;
- RuleLock *rulelock;
- int numlocks;
- RewriteRule **rules;
- int maxlocks;
-
- /* ----------------
- * form an array to hold the rewrite rules (the array is extended if
- * necessary)
- * ----------------
- */
- maxlocks = 4;
- rules = (RewriteRule **)palloc(sizeof(RewriteRule*)*maxlocks);
- numlocks = 0;
-
- /* ----------------
- * form a scan key
- * ----------------
- */
- ScanKeyEntryInitialize(&key, 0,
- Anum_pg_rewrite_ev_class,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relation->rd_id));
-
- /* ----------------
- * open pg_attribute and begin a scan
- * ----------------
- */
- pg_rewrite_desc = heap_openr(RewriteRelationName);
- pg_rewrite_scan =
- heap_beginscan(pg_rewrite_desc, 0, NowTimeQual, 1, &key);
- pg_rewrite_tupdesc =
- RelationGetTupleDescriptor(pg_rewrite_desc);
-
- /* ----------------
- * add attribute data to relation->rd_att
- * ----------------
- */
- while ((pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0,
- (Buffer *) NULL)) != NULL) {
- bool isnull;
- char *ruleaction = NULL;
- char *rule_evqual_string;
- RewriteRule *rule;
-
- rule = (RewriteRule *)palloc(sizeof(RewriteRule));
-
- rule->ruleId = pg_rewrite_tuple->t_oid;
-
- rule->event =
- (int)heap_getattr(pg_rewrite_tuple, InvalidBuffer,
- Anum_pg_rewrite_ev_type, pg_rewrite_tupdesc,
- &isnull) - 48;
- rule->attrno =
- (int)heap_getattr(pg_rewrite_tuple, InvalidBuffer,
- Anum_pg_rewrite_ev_attr, pg_rewrite_tupdesc,
- &isnull);
- rule->isInstead =
- !!heap_getattr(pg_rewrite_tuple, InvalidBuffer,
- Anum_pg_rewrite_is_instead, pg_rewrite_tupdesc,
- &isnull);
-
- ruleaction =
- heap_getattr(pg_rewrite_tuple, InvalidBuffer,
- Anum_pg_rewrite_action, pg_rewrite_tupdesc,
- &isnull);
- rule_evqual_string =
- heap_getattr(pg_rewrite_tuple, InvalidBuffer,
- Anum_pg_rewrite_ev_qual, pg_rewrite_tupdesc,
- &isnull);
-
- ruleaction = textout((struct varlena *)ruleaction);
- rule_evqual_string = textout((struct varlena *)rule_evqual_string);
-
- rule->actions = (List*)stringToNode(ruleaction);
- rule->qual = (Node*)stringToNode(rule_evqual_string);
-
- rules[numlocks++] = rule;
- if (numlocks==maxlocks) {
- maxlocks *= 2;
- rules =
- (RewriteRule **)repalloc(rules, sizeof(RewriteRule*)*maxlocks);
+ HeapTuple pg_rewrite_tuple;
+ Relation pg_rewrite_desc;
+ TupleDesc pg_rewrite_tupdesc;
+ HeapScanDesc pg_rewrite_scan;
+ ScanKeyData key;
+ RuleLock *rulelock;
+ int numlocks;
+ RewriteRule **rules;
+ int maxlocks;
+
+ /* ----------------
+ * form an array to hold the rewrite rules (the array is extended if
+ * necessary)
+ * ----------------
+ */
+ maxlocks = 4;
+ rules = (RewriteRule **) palloc(sizeof(RewriteRule *) * maxlocks);
+ numlocks = 0;
+
+ /* ----------------
+ * form a scan key
+ * ----------------
+ */
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_rewrite_ev_class,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relation->rd_id));
+
+ /* ----------------
+ * open pg_attribute and begin a scan
+ * ----------------
+ */
+ pg_rewrite_desc = heap_openr(RewriteRelationName);
+ pg_rewrite_scan =
+ heap_beginscan(pg_rewrite_desc, 0, NowTimeQual, 1, &key);
+ pg_rewrite_tupdesc =
+ RelationGetTupleDescriptor(pg_rewrite_desc);
+
+ /* ----------------
+ * add attribute data to relation->rd_att
+ * ----------------
+ */
+ while ((pg_rewrite_tuple = heap_getnext(pg_rewrite_scan, 0,
+ (Buffer *) NULL)) != NULL)
+ {
+ bool isnull;
+ char *ruleaction = NULL;
+ char *rule_evqual_string;
+ RewriteRule *rule;
+
+ rule = (RewriteRule *) palloc(sizeof(RewriteRule));
+
+ rule->ruleId = pg_rewrite_tuple->t_oid;
+
+ rule->event =
+ (int) heap_getattr(pg_rewrite_tuple, InvalidBuffer,
+ Anum_pg_rewrite_ev_type, pg_rewrite_tupdesc,
+ &isnull) - 48;
+ rule->attrno =
+ (int) heap_getattr(pg_rewrite_tuple, InvalidBuffer,
+ Anum_pg_rewrite_ev_attr, pg_rewrite_tupdesc,
+ &isnull);
+ rule->isInstead =
+ !!heap_getattr(pg_rewrite_tuple, InvalidBuffer,
+ Anum_pg_rewrite_is_instead, pg_rewrite_tupdesc,
+ &isnull);
+
+ ruleaction =
+ heap_getattr(pg_rewrite_tuple, InvalidBuffer,
+ Anum_pg_rewrite_action, pg_rewrite_tupdesc,
+ &isnull);
+ rule_evqual_string =
+ heap_getattr(pg_rewrite_tuple, InvalidBuffer,
+ Anum_pg_rewrite_ev_qual, pg_rewrite_tupdesc,
+ &isnull);
+
+ ruleaction = textout((struct varlena *) ruleaction);
+ rule_evqual_string = textout((struct varlena *) rule_evqual_string);
+
+ rule->actions = (List *) stringToNode(ruleaction);
+ rule->qual = (Node *) stringToNode(rule_evqual_string);
+
+ rules[numlocks++] = rule;
+ if (numlocks == maxlocks)
+ {
+ maxlocks *= 2;
+ rules =
+ (RewriteRule **) repalloc(rules, sizeof(RewriteRule *) * maxlocks);
+ }
}
- }
-
- /* ----------------
- * end the scan and close the attribute relation
- * ----------------
- */
- heap_endscan(pg_rewrite_scan);
- heap_close(pg_rewrite_desc);
-
- /* ----------------
- * form a RuleLock and insert into relation
- * ----------------
- */
- rulelock = (RuleLock *)palloc(sizeof(RuleLock));
- rulelock->numLocks = numlocks;
- rulelock->rules = rules;
-
- relation->rd_rules = rulelock;
- return;
+
+ /* ----------------
+ * end the scan and close the attribute relation
+ * ----------------
+ */
+ heap_endscan(pg_rewrite_scan);
+ heap_close(pg_rewrite_desc);
+
+ /* ----------------
+ * form a RuleLock and insert into relation
+ * ----------------
+ */
+ rulelock = (RuleLock *) palloc(sizeof(RuleLock));
+ rulelock->numLocks = numlocks;
+ rulelock->rules = rules;
+
+ relation->rd_rules = rulelock;
+ return;
}
/* --------------------------------
- * RelationBuildDesc
- *
- * To build a relation descriptor, we have to allocate space,
- * open the underlying unix file and initialize the following
- * fields:
+ * RelationBuildDesc
+ *
+ * To build a relation descriptor, we have to allocate space,
+ * open the underlying unix file and initialize the following
+ * fields:
*
- * File rd_fd; open file descriptor
- * int rd_nblocks; number of blocks in rel
- * it will be set in ambeginscan()
- * uint16 rd_refcnt; reference count
- * Form_pg_am rd_am; AM tuple
- * Form_pg_class rd_rel; RELATION tuple
- * Oid rd_id; relations's object id
- * Pointer lockInfo; ptr. to misc. info.
- * TupleDesc rd_att; tuple desciptor
+ * File rd_fd; open file descriptor
+ * int rd_nblocks; number of blocks in rel
+ * it will be set in ambeginscan()
+ * uint16 rd_refcnt; reference count
+ * Form_pg_am rd_am; AM tuple
+ * Form_pg_class rd_rel; RELATION tuple
+ * Oid rd_id; relations's object id
+ * Pointer lockInfo; ptr. to misc. info.
+ * TupleDesc rd_att; tuple desciptor
*
- * Note: rd_ismem (rel is in-memory only) is currently unused
- * by any part of the system. someday this will indicate that
- * the relation lives only in the main-memory buffer pool
- * -cim 2/4/91
+ * Note: rd_ismem (rel is in-memory only) is currently unused
+ * by any part of the system. someday this will indicate that
+ * the relation lives only in the main-memory buffer pool
+ * -cim 2/4/91
* --------------------------------
*/
-static Relation
+static Relation
RelationBuildDesc(RelationBuildDescInfo buildinfo)
{
- File fd;
- Relation relation;
- u_int natts;
- Oid relid;
- Oid relam;
- Form_pg_class relp;
-
- MemoryContext oldcxt;
-
- HeapTuple pg_class_tuple;
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * find the tuple in pg_class corresponding to the given relation id
- * ----------------
- */
- pg_class_tuple = ScanPgRelation(buildinfo);
-
- /* ----------------
- * if no such tuple exists, return NULL
- * ----------------
- */
- if (! HeapTupleIsValid(pg_class_tuple)) {
-
- MemoryContextSwitchTo(oldcxt);
-
- return NULL;
- }
-
- /* ----------------
- * get information from the pg_class_tuple
- * ----------------
- */
- relid = pg_class_tuple->t_oid;
- relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
- natts = relp->relnatts;
-
- /* ----------------
- * allocate storage for the relation descriptor,
- * initialize relation->rd_rel and get the access method id.
- * ----------------
- */
- relation = AllocateRelationDesc(natts, relp);
- relam = relation->rd_rel->relam;
-
- /* ----------------
- * initialize the relation's relation id (relation->rd_id)
- * ----------------
- */
- relation->rd_id = relid;
-
- /* ----------------
- * initialize relation->rd_refcnt
- * ----------------
- */
- RelationSetReferenceCount(relation, 1);
-
- /* ----------------
- * normal relations are not nailed into the cache
- * ----------------
- */
- relation->rd_isnailed = false;
-
- /* ----------------
- * initialize the access method information (relation->rd_am)
- * ----------------
- */
- if (OidIsValid(relam)) {
- relation->rd_am = (Form_pg_am)
- AccessMethodObjectIdGetAccessMethodTupleForm(relam);
- }
-
- /* ----------------
- * initialize the tuple descriptor (relation->rd_att).
- * remember, rd_att is an array of attribute pointers that lives
- * off the end of the relation descriptor structure so space was
- * already allocated for it by AllocateRelationDesc.
- * ----------------
- */
- RelationBuildTupleDesc(buildinfo, relation, natts);
-
- /* ----------------
- * initialize rules that affect this relation
- * ----------------
- */
- if (relp->relhasrules) {
- RelationBuildRuleLock(relation);
- } else {
- relation->rd_rules = NULL;
- }
-
- /* Triggers */
- if ( relp->reltriggers > 0 )
- RelationBuildTriggers (relation);
- else
- relation->trigdesc = NULL;
-
- /* ----------------
- * initialize index strategy and support information for this relation
- * ----------------
- */
- if (OidIsValid(relam)) {
- IndexedAccessMethodInitialize(relation);
- }
-
- /* ----------------
- * initialize the relation lock manager information
- * ----------------
- */
- RelationInitLockInfo(relation); /* see lmgr.c */
-
- /* ----------------
- * open the relation and assign the file descriptor returned
- * by the storage manager code to rd_fd.
- * ----------------
- */
- fd = smgropen(relp->relsmgr, relation);
-
- Assert (fd >= -1);
- if (fd == -1)
- elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
- &relp->relname);
-
- relation->rd_fd = fd;
-
- /* ----------------
- * insert newly created relation into proper relcaches,
- * restore memory context and return the new reldesc.
- * ----------------
- */
-
- RelationCacheInsert(relation);
-
- /* -------------------
- * free the memory allocated for pg_class_tuple
- * and for lock data pointed to by pg_class_tuple
- * -------------------
- */
- pfree(pg_class_tuple);
-
- MemoryContextSwitchTo(oldcxt);
-
- return relation;
+ File fd;
+ Relation relation;
+ u_int natts;
+ Oid relid;
+ Oid relam;
+ Form_pg_class relp;
+
+ MemoryContext oldcxt;
+
+ HeapTuple pg_class_tuple;
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * find the tuple in pg_class corresponding to the given relation id
+ * ----------------
+ */
+ pg_class_tuple = ScanPgRelation(buildinfo);
+
+ /* ----------------
+ * if no such tuple exists, return NULL
+ * ----------------
+ */
+ if (!HeapTupleIsValid(pg_class_tuple))
+ {
+
+ MemoryContextSwitchTo(oldcxt);
+
+ return NULL;
+ }
+
+ /* ----------------
+ * get information from the pg_class_tuple
+ * ----------------
+ */
+ relid = pg_class_tuple->t_oid;
+ relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
+ natts = relp->relnatts;
+
+ /* ----------------
+ * allocate storage for the relation descriptor,
+ * initialize relation->rd_rel and get the access method id.
+ * ----------------
+ */
+ relation = AllocateRelationDesc(natts, relp);
+ relam = relation->rd_rel->relam;
+
+ /* ----------------
+ * initialize the relation's relation id (relation->rd_id)
+ * ----------------
+ */
+ relation->rd_id = relid;
+
+ /* ----------------
+ * initialize relation->rd_refcnt
+ * ----------------
+ */
+ RelationSetReferenceCount(relation, 1);
+
+ /* ----------------
+ * normal relations are not nailed into the cache
+ * ----------------
+ */
+ relation->rd_isnailed = false;
+
+ /* ----------------
+ * initialize the access method information (relation->rd_am)
+ * ----------------
+ */
+ if (OidIsValid(relam))
+ {
+ relation->rd_am = (Form_pg_am)
+ AccessMethodObjectIdGetAccessMethodTupleForm(relam);
+ }
+
+ /* ----------------
+ * initialize the tuple descriptor (relation->rd_att).
+ * remember, rd_att is an array of attribute pointers that lives
+ * off the end of the relation descriptor structure so space was
+ * already allocated for it by AllocateRelationDesc.
+ * ----------------
+ */
+ RelationBuildTupleDesc(buildinfo, relation, natts);
+
+ /* ----------------
+ * initialize rules that affect this relation
+ * ----------------
+ */
+ if (relp->relhasrules)
+ {
+ RelationBuildRuleLock(relation);
+ }
+ else
+ {
+ relation->rd_rules = NULL;
+ }
+
+ /* Triggers */
+ if (relp->reltriggers > 0)
+ RelationBuildTriggers(relation);
+ else
+ relation->trigdesc = NULL;
+
+ /* ----------------
+ * initialize index strategy and support information for this relation
+ * ----------------
+ */
+ if (OidIsValid(relam))
+ {
+ IndexedAccessMethodInitialize(relation);
+ }
+
+ /* ----------------
+ * initialize the relation lock manager information
+ * ----------------
+ */
+ RelationInitLockInfo(relation); /* see lmgr.c */
+
+ /* ----------------
+ * open the relation and assign the file descriptor returned
+ * by the storage manager code to rd_fd.
+ * ----------------
+ */
+ fd = smgropen(relp->relsmgr, relation);
+
+ Assert(fd >= -1);
+ if (fd == -1)
+ elog(NOTICE, "RelationIdBuildRelation: smgropen(%s): %m",
+ &relp->relname);
+
+ relation->rd_fd = fd;
+
+ /* ----------------
+ * insert newly created relation into proper relcaches,
+ * restore memory context and return the new reldesc.
+ * ----------------
+ */
+
+ RelationCacheInsert(relation);
+
+ /* -------------------
+ * free the memory allocated for pg_class_tuple
+ * and for lock data pointed to by pg_class_tuple
+ * -------------------
+ */
+ pfree(pg_class_tuple);
+
+ MemoryContextSwitchTo(oldcxt);
+
+ return relation;
}
static void
IndexedAccessMethodInitialize(Relation relation)
{
- IndexStrategy strategy;
- RegProcedure *support;
- int natts;
- Size stratSize;
- Size supportSize;
- uint16 relamstrategies;
- uint16 relamsupport;
-
- natts = relation->rd_rel->relnatts;
- relamstrategies = relation->rd_am->amstrategies;
- stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
- strategy = (IndexStrategy) palloc(stratSize);
- relamsupport = relation->rd_am->amsupport;
-
- if (relamsupport > 0) {
- supportSize = natts * (relamsupport * sizeof (RegProcedure));
- support = (RegProcedure *) palloc(supportSize);
- } else {
- support = (RegProcedure *) NULL;
- }
-
- IndexSupportInitialize(strategy, support,
- relation->rd_att->attrs[0]->attrelid,
- relation->rd_rel->relam,
- relamstrategies, relamsupport, natts);
-
- RelationSetIndexSupport(relation, strategy, support);
+ IndexStrategy strategy;
+ RegProcedure *support;
+ int natts;
+ Size stratSize;
+ Size supportSize;
+ uint16 relamstrategies;
+ uint16 relamsupport;
+
+ natts = relation->rd_rel->relnatts;
+ relamstrategies = relation->rd_am->amstrategies;
+ stratSize = AttributeNumberGetIndexStrategySize(natts, relamstrategies);
+ strategy = (IndexStrategy) palloc(stratSize);
+ relamsupport = relation->rd_am->amsupport;
+
+ if (relamsupport > 0)
+ {
+ supportSize = natts * (relamsupport * sizeof(RegProcedure));
+ support = (RegProcedure *) palloc(supportSize);
+ }
+ else
+ {
+ support = (RegProcedure *) NULL;
+ }
+
+ IndexSupportInitialize(strategy, support,
+ relation->rd_att->attrs[0]->attrelid,
+ relation->rd_rel->relam,
+ relamstrategies, relamsupport, natts);
+
+ RelationSetIndexSupport(relation, strategy, support);
}
/* --------------------------------
- * formrdesc
+ * formrdesc
*
- * This is a special version of RelationBuildDesc()
- * used by RelationInitialize() in initializing the
- * relcache. The system relation descriptors built
- * here are all nailed in the descriptor caches, for
- * bootstrapping.
+ * This is a special version of RelationBuildDesc()
+ * used by RelationInitialize() in initializing the
+ * relcache. The system relation descriptors built
+ * here are all nailed in the descriptor caches, for
+ * bootstrapping.
* --------------------------------
*/
static void
formrdesc(char *relationName,
- u_int natts,
- FormData_pg_attribute att[])
+ u_int natts,
+ FormData_pg_attribute att[])
{
- Relation relation;
- Size len;
- int i;
-
- /* ----------------
- * allocate new relation desc
- * ----------------
- */
- len = sizeof (RelationData);
- relation = (Relation) palloc(len);
- memset((char *)relation, 0,len);
-
- /* ----------------
- * don't open the unix file yet..
- * ----------------
- */
- relation->rd_fd = -1;
-
- /* ----------------
- * initialize reference count
- * ----------------
- */
- RelationSetReferenceCount(relation, 1);
-
- /* ----------------
- * initialize relation tuple form
- * ----------------
- */
- relation->rd_rel = (Form_pg_class)
- palloc((Size) (sizeof(*relation->rd_rel)));
- memset(relation->rd_rel, 0, sizeof(FormData_pg_class));
- namestrcpy(&relation->rd_rel->relname, relationName);
-
- /* ----------------
- initialize attribute tuple form
- */
- relation->rd_att = CreateTemplateTupleDesc(natts);
-
- /*
- * For debugging purposes, it's important to distinguish between
- * shared and non-shared relations, even at bootstrap time. There's
- * code in the buffer manager that traces allocations that has to
- * know about this.
- */
-
- if (IsSystemRelationName(relationName)) {
- relation->rd_rel->relowner = 6; /* XXX use sym const */
- relation->rd_rel->relisshared =
- IsSharedSystemRelationName(relationName);
- } else {
- relation->rd_rel->relowner = InvalidOid; /* XXX incorrect*/
- relation->rd_rel->relisshared = false;
- }
-
- relation->rd_rel->relpages = 1; /* XXX */
- relation->rd_rel->reltuples = 1; /* XXX */
- relation->rd_rel->relkind = RELKIND_RELATION;
- relation->rd_rel->relarch = 'n';
- relation->rd_rel->relnatts = (uint16) natts;
- relation->rd_isnailed = true;
-
- /* ----------------
- * initialize tuple desc info
- * ----------------
- */
- for (i = 0; i < natts; i++) {
- relation->rd_att->attrs[i] =
- (AttributeTupleForm)palloc(ATTRIBUTE_TUPLE_SIZE);
-
- memset((char *)relation->rd_att->attrs[i], 0,
- ATTRIBUTE_TUPLE_SIZE);
- memmove((char *)relation->rd_att->attrs[i],
- (char *)&att[i],
- ATTRIBUTE_TUPLE_SIZE);
- }
-
- /* ----------------
- * initialize relation id
- * ----------------
- */
- relation->rd_id = relation->rd_att->attrs[0]->attrelid;
-
- /* ----------------
- * add new reldesc to relcache
- * ----------------
- */
- RelationCacheInsert(relation);
- /*
- * Determining this requires a scan on pg_class, but to do the
- * scan the rdesc for pg_class must already exist. Therefore
- * we must do the check (and possible set) after cache insertion.
- */
- relation->rd_rel->relhasindex =
- CatalogHasIndex(relationName, relation->rd_id);
+ Relation relation;
+ Size len;
+ int i;
+
+ /* ----------------
+ * allocate new relation desc
+ * ----------------
+ */
+ len = sizeof(RelationData);
+ relation = (Relation) palloc(len);
+ memset((char *) relation, 0, len);
+
+ /* ----------------
+ * don't open the unix file yet..
+ * ----------------
+ */
+ relation->rd_fd = -1;
+
+ /* ----------------
+ * initialize reference count
+ * ----------------
+ */
+ RelationSetReferenceCount(relation, 1);
+
+ /* ----------------
+ * initialize relation tuple form
+ * ----------------
+ */
+ relation->rd_rel = (Form_pg_class)
+ palloc((Size) (sizeof(*relation->rd_rel)));
+ memset(relation->rd_rel, 0, sizeof(FormData_pg_class));
+ namestrcpy(&relation->rd_rel->relname, relationName);
+
+ /* ----------------
+ initialize attribute tuple form
+ */
+ relation->rd_att = CreateTemplateTupleDesc(natts);
+
+ /*
+ * For debugging purposes, it's important to distinguish between
+ * shared and non-shared relations, even at bootstrap time. There's
+ * code in the buffer manager that traces allocations that has to know
+ * about this.
+ */
+
+ if (IsSystemRelationName(relationName))
+ {
+ relation->rd_rel->relowner = 6; /* XXX use sym const */
+ relation->rd_rel->relisshared =
+ IsSharedSystemRelationName(relationName);
+ }
+ else
+ {
+ relation->rd_rel->relowner = InvalidOid; /* XXX incorrect */
+ relation->rd_rel->relisshared = false;
+ }
+
+ relation->rd_rel->relpages = 1; /* XXX */
+ relation->rd_rel->reltuples = 1; /* XXX */
+ relation->rd_rel->relkind = RELKIND_RELATION;
+ relation->rd_rel->relarch = 'n';
+ relation->rd_rel->relnatts = (uint16) natts;
+ relation->rd_isnailed = true;
+
+ /* ----------------
+ * initialize tuple desc info
+ * ----------------
+ */
+ for (i = 0; i < natts; i++)
+ {
+ relation->rd_att->attrs[i] =
+ (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
+
+ memset((char *) relation->rd_att->attrs[i], 0,
+ ATTRIBUTE_TUPLE_SIZE);
+ memmove((char *) relation->rd_att->attrs[i],
+ (char *) &att[i],
+ ATTRIBUTE_TUPLE_SIZE);
+ }
+
+ /* ----------------
+ * initialize relation id
+ * ----------------
+ */
+ relation->rd_id = relation->rd_att->attrs[0]->attrelid;
+
+ /* ----------------
+ * add new reldesc to relcache
+ * ----------------
+ */
+ RelationCacheInsert(relation);
+
+ /*
+ * Determining this requires a scan on pg_class, but to do the scan
+ * the rdesc for pg_class must already exist. Therefore we must do
+ * the check (and possible set) after cache insertion.
+ */
+ relation->rd_rel->relhasindex =
+ CatalogHasIndex(relationName, relation->rd_id);
}
/* ----------------------------------------------------------------
- * Relation Descriptor Lookup Interface
+ * Relation Descriptor Lookup Interface
* ----------------------------------------------------------------
*/
/* --------------------------------
- * RelationIdCacheGetRelation
+ * RelationIdCacheGetRelation
*
- * only try to get the reldesc by looking up the cache
- * do not go to the disk. this is used by BlockPrepareFile()
- * and RelationIdGetRelation below.
+ * only try to get the reldesc by looking up the cache
+ * do not go to the disk. this is used by BlockPrepareFile()
+ * and RelationIdGetRelation below.
* --------------------------------
*/
Relation
RelationIdCacheGetRelation(Oid relationId)
{
- Relation rd;
-
- RelationIdCacheLookup(relationId, rd);
-
- if (RelationIsValid(rd)) {
- if (rd->rd_fd == -1) {
- rd->rd_fd = smgropen(rd->rd_rel->relsmgr, rd);
- Assert(rd->rd_fd != -1);
+ Relation rd;
+
+ RelationIdCacheLookup(relationId, rd);
+
+ if (RelationIsValid(rd))
+ {
+ if (rd->rd_fd == -1)
+ {
+ rd->rd_fd = smgropen(rd->rd_rel->relsmgr, rd);
+ Assert(rd->rd_fd != -1);
+ }
+
+ RelationIncrementReferenceCount(rd);
+ RelationSetLockForDescriptorOpen(rd);
+
}
-
- RelationIncrementReferenceCount(rd);
- RelationSetLockForDescriptorOpen(rd);
-
- }
-
- return(rd);
+
+ return (rd);
}
/* --------------------------------
- * RelationNameCacheGetRelation
+ * RelationNameCacheGetRelation
* --------------------------------
*/
-static Relation
+static Relation
RelationNameCacheGetRelation(char *relationName)
{
- Relation rd;
- NameData name;
-
- /* make sure that the name key used for hash lookup is properly
- null-padded */
- namestrcpy(&name, relationName);
- RelationNameCacheLookup(name.data, rd);
-
- if (RelationIsValid(rd)) {
- if (rd->rd_fd == -1) {
- rd->rd_fd = smgropen(rd->rd_rel->relsmgr, rd);
- Assert(rd->rd_fd != -1);
+ Relation rd;
+ NameData name;
+
+ /*
+ * make sure that the name key used for hash lookup is properly
+ * null-padded
+ */
+ namestrcpy(&name, relationName);
+ RelationNameCacheLookup(name.data, rd);
+
+ if (RelationIsValid(rd))
+ {
+ if (rd->rd_fd == -1)
+ {
+ rd->rd_fd = smgropen(rd->rd_rel->relsmgr, rd);
+ Assert(rd->rd_fd != -1);
+ }
+
+ RelationIncrementReferenceCount(rd);
+ RelationSetLockForDescriptorOpen(rd);
+
}
-
- RelationIncrementReferenceCount(rd);
- RelationSetLockForDescriptorOpen(rd);
-
- }
-
- return(rd);
+
+ return (rd);
}
/* --------------------------------
- * RelationIdGetRelation
+ * RelationIdGetRelation
*
- * return a relation descriptor based on its id.
- * return a cached value if possible
+ * return a relation descriptor based on its id.
+ * return a cached value if possible
* --------------------------------
*/
Relation
RelationIdGetRelation(Oid relationId)
{
- Relation rd;
- RelationBuildDescInfo buildinfo;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_RelationIdGetRelation);
- IncrHeapAccessStat(global_RelationIdGetRelation);
-
- /* ----------------
- * first try and get a reldesc from the cache
- * ----------------
- */
- rd = RelationIdCacheGetRelation(relationId);
- if (RelationIsValid(rd))
- return rd;
-
- /* ----------------
- * no reldesc in the cache, so have RelationBuildDesc()
- * build one and add it.
- * ----------------
- */
- buildinfo.infotype = INFO_RELID;
- buildinfo.i.info_id = relationId;
-
- rd = RelationBuildDesc(buildinfo);
- return
- rd;
+ Relation rd;
+ RelationBuildDescInfo buildinfo;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_RelationIdGetRelation);
+ IncrHeapAccessStat(global_RelationIdGetRelation);
+
+ /* ----------------
+ * first try and get a reldesc from the cache
+ * ----------------
+ */
+ rd = RelationIdCacheGetRelation(relationId);
+ if (RelationIsValid(rd))
+ return rd;
+
+ /* ----------------
+ * no reldesc in the cache, so have RelationBuildDesc()
+ * build one and add it.
+ * ----------------
+ */
+ buildinfo.infotype = INFO_RELID;
+ buildinfo.i.info_id = relationId;
+
+ rd = RelationBuildDesc(buildinfo);
+ return
+ rd;
}
/* --------------------------------
- * RelationNameGetRelation
+ * RelationNameGetRelation
*
- * return a relation descriptor based on its name.
- * return a cached value if possible
+ * return a relation descriptor based on its name.
+ * return a cached value if possible
* --------------------------------
*/
Relation
RelationNameGetRelation(char *relationName)
{
- Relation rd;
- RelationBuildDescInfo buildinfo;
-
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_RelationNameGetRelation);
- IncrHeapAccessStat(global_RelationNameGetRelation);
-
- /* ----------------
- * first try and get a reldesc from the cache
- * ----------------
- */
- rd = RelationNameCacheGetRelation(relationName);
- if (RelationIsValid(rd))
+ Relation rd;
+ RelationBuildDescInfo buildinfo;
+
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_RelationNameGetRelation);
+ IncrHeapAccessStat(global_RelationNameGetRelation);
+
+ /* ----------------
+ * first try and get a reldesc from the cache
+ * ----------------
+ */
+ rd = RelationNameCacheGetRelation(relationName);
+ if (RelationIsValid(rd))
+ return rd;
+
+ /* ----------------
+ * no reldesc in the cache, so have RelationBuildDesc()
+ * build one and add it.
+ * ----------------
+ */
+ buildinfo.infotype = INFO_RELNAME;
+ buildinfo.i.info_name = relationName;
+
+ rd = RelationBuildDesc(buildinfo);
return rd;
-
- /* ----------------
- * no reldesc in the cache, so have RelationBuildDesc()
- * build one and add it.
- * ----------------
- */
- buildinfo.infotype = INFO_RELNAME;
- buildinfo.i.info_name = relationName;
-
- rd = RelationBuildDesc(buildinfo);
- return rd;
}
/* ----------------
- * old "getreldesc" interface.
+ * old "getreldesc" interface.
* ----------------
*/
#ifdef NOT_USED
Relation
getreldesc(char *relationName)
{
- /* ----------------
- * increment access statistics
- * ----------------
- */
- IncrHeapAccessStat(local_getreldesc);
- IncrHeapAccessStat(global_getreldesc);
-
- return RelationNameGetRelation(relationName);
+ /* ----------------
+ * increment access statistics
+ * ----------------
+ */
+ IncrHeapAccessStat(local_getreldesc);
+ IncrHeapAccessStat(global_getreldesc);
+
+ return RelationNameGetRelation(relationName);
}
+
#endif
/* ----------------------------------------------------------------
- * cache invalidation support routines
+ * cache invalidation support routines
* ----------------------------------------------------------------
*/
/* --------------------------------
- * RelationClose - close an open relation
+ * RelationClose - close an open relation
* --------------------------------
*/
void
RelationClose(Relation relation)
{
- /* Note: no locking manipulations needed */
- RelationDecrementReferenceCount(relation);
+ /* Note: no locking manipulations needed */
+ RelationDecrementReferenceCount(relation);
}
/* --------------------------------
* RelationFlushRelation
*
- * Actually blows away a relation... RelationFree doesn't do
- * anything anymore.
+ * Actually blows away a relation... RelationFree doesn't do
+ * anything anymore.
* --------------------------------
*/
static void
-RelationFlushRelation(Relation *relationPtr,
- bool onlyFlushReferenceCountZero)
+RelationFlushRelation(Relation * relationPtr,
+ bool onlyFlushReferenceCountZero)
{
- MemoryContext oldcxt;
- Relation relation = *relationPtr;
-
- if (relation->rd_isnailed) {
- /* this is a nailed special relation for bootstraping */
- return;
- }
-
- if (!onlyFlushReferenceCountZero ||
- RelationHasReferenceCountZero(relation)) {
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- RelationCacheDelete(relation);
-
- FreeTupleDesc (relation->rd_att);
-
- FreeTriggerDesc (relation);
+ MemoryContext oldcxt;
+ Relation relation = *relationPtr;
-#if 0
- if (relation->rd_rules) {
- int j;
- for(j=0; j < relation->rd_rules->numLocks; j++) {
- pfree(relation->rd_rules->rules[j]);
- }
- pfree(relation->rd_rules->rules);
- pfree(relation->rd_rules);
+ if (relation->rd_isnailed)
+ {
+ /* this is a nailed special relation for bootstraping */
+ return;
}
+
+ if (!onlyFlushReferenceCountZero ||
+ RelationHasReferenceCountZero(relation))
+ {
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ RelationCacheDelete(relation);
+
+ FreeTupleDesc(relation->rd_att);
+
+ FreeTriggerDesc(relation);
+
+#if 0
+ if (relation->rd_rules)
+ {
+ int j;
+
+ for (j = 0; j < relation->rd_rules->numLocks; j++)
+ {
+ pfree(relation->rd_rules->rules[j]);
+ }
+ pfree(relation->rd_rules->rules);
+ pfree(relation->rd_rules);
+ }
#endif
-
- pfree(RelationGetLockInfo(relation));
- pfree(RelationGetRelationTupleForm(relation));
- pfree(relation);
-
- MemoryContextSwitchTo(oldcxt);
- }
+
+ pfree(RelationGetLockInfo(relation));
+ pfree(RelationGetRelationTupleForm(relation));
+ pfree(relation);
+
+ MemoryContextSwitchTo(oldcxt);
+ }
}
/* --------------------------------
- * RelationForgetRelation -
- * RelationFlushRelation + if the relation is local then get rid of
- * the relation descriptor from the newly created relation list.
+ * RelationForgetRelation -
+ * RelationFlushRelation + if the relation is local then get rid of
+ * the relation descriptor from the newly created relation list.
* --------------------------------
*/
void
-RelationForgetRelation (Oid rid)
+RelationForgetRelation(Oid rid)
{
- Relation relation;
-
- RelationIdCacheLookup (rid, relation);
- Assert ( PointerIsValid (relation) );
-
- if ( relation->rd_islocal )
- {
- MemoryContext oldcxt;
- List *curr;
- List *prev = NIL;
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- foreach (curr, newlyCreatedRelns)
- {
- Relation reln = lfirst(curr);
-
- Assert ( reln != NULL && reln->rd_islocal );
- if ( reln->rd_id == rid )
- break;
- prev = curr;
- }
- if ( curr == NIL )
- elog (FATAL, "Local relation %s not found in list",
- (RelationGetRelationName(relation))->data);
- if ( prev == NIL )
- newlyCreatedRelns = lnext (newlyCreatedRelns);
- else
- lnext (prev) = lnext (curr);
- pfree (curr);
- MemoryContextSwitchTo(oldcxt);
- }
-
- RelationFlushRelation (&relation, false);
+ Relation relation;
+
+ RelationIdCacheLookup(rid, relation);
+ Assert(PointerIsValid(relation));
+
+ if (relation->rd_islocal)
+ {
+ MemoryContext oldcxt;
+ List *curr;
+ List *prev = NIL;
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ foreach(curr, newlyCreatedRelns)
+ {
+ Relation reln = lfirst(curr);
+
+ Assert(reln != NULL && reln->rd_islocal);
+ if (reln->rd_id == rid)
+ break;
+ prev = curr;
+ }
+ if (curr == NIL)
+ elog(FATAL, "Local relation %s not found in list",
+ (RelationGetRelationName(relation))->data);
+ if (prev == NIL)
+ newlyCreatedRelns = lnext(newlyCreatedRelns);
+ else
+ lnext(prev) = lnext(curr);
+ pfree(curr);
+ MemoryContextSwitchTo(oldcxt);
+ }
+
+ RelationFlushRelation(&relation, false);
}
/* --------------------------------
- * RelationIdInvalidateRelationCacheByRelationId
+ * RelationIdInvalidateRelationCacheByRelationId
* --------------------------------
*/
void
RelationIdInvalidateRelationCacheByRelationId(Oid relationId)
{
- Relation relation;
-
- RelationIdCacheLookup(relationId, relation);
-
- /*
- * "local" relations are invalidated by RelationPurgeLocalRelation.
- * (This is to make LocalBufferSync's life easier: want the descriptor
- * to hang around for a while. In fact, won't we want this for
- * BufferSync also? But I'll leave it for now since I don't want to
- * break anything.) - ay 3/95
- */
- if (PointerIsValid(relation) && !relation->rd_islocal) {
+ Relation relation;
+
+ RelationIdCacheLookup(relationId, relation);
+
/*
- * The boolean onlyFlushReferenceCountZero in RelationFlushReln()
- * should be set to true when we are incrementing the command
- * counter and to false when we are starting a new xaction. This
- * can be determined by checking the current xaction status.
+ * "local" relations are invalidated by RelationPurgeLocalRelation.
+ * (This is to make LocalBufferSync's life easier: want the descriptor
+ * to hang around for a while. In fact, won't we want this for
+ * BufferSync also? But I'll leave it for now since I don't want to
+ * break anything.) - ay 3/95
*/
- RelationFlushRelation(&relation, CurrentXactInProgress());
- }
+ if (PointerIsValid(relation) && !relation->rd_islocal)
+ {
+
+ /*
+ * The boolean onlyFlushReferenceCountZero in RelationFlushReln()
+ * should be set to true when we are incrementing the command
+ * counter and to false when we are starting a new xaction. This
+ * can be determined by checking the current xaction status.
+ */
+ RelationFlushRelation(&relation, CurrentXactInProgress());
+ }
}
-#if NOT_USED /* See comments at line 1304 */
+#if NOT_USED /* See comments at line 1304 */
/* --------------------------------
- * RelationIdInvalidateRelationCacheByAccessMethodId
+ * RelationIdInvalidateRelationCacheByAccessMethodId
*
- * RelationFlushIndexes is needed for use with HashTableWalk..
+ * RelationFlushIndexes is needed for use with HashTableWalk..
* --------------------------------
*/
static void
-RelationFlushIndexes(Relation *r,
- Oid accessMethodId)
+RelationFlushIndexes(Relation * r,
+ Oid accessMethodId)
{
- Relation relation = *r;
-
- if (!RelationIsValid(relation)) {
- elog(NOTICE, "inval call to RFI");
- return;
- }
-
- if (relation->rd_rel->relkind == RELKIND_INDEX && /* XXX style */
- (!OidIsValid(accessMethodId) ||
- relation->rd_rel->relam == accessMethodId))
+ Relation relation = *r;
+
+ if (!RelationIsValid(relation))
+ {
+ elog(NOTICE, "inval call to RFI");
+ return;
+ }
+
+ if (relation->rd_rel->relkind == RELKIND_INDEX && /* XXX style */
+ (!OidIsValid(accessMethodId) ||
+ relation->rd_rel->relam == accessMethodId))
{
- RelationFlushRelation(&relation, false);
+ RelationFlushRelation(&relation, false);
}
}
+
#endif
void
RelationIdInvalidateRelationCacheByAccessMethodId(Oid accessMethodId)
{
-# if 0
- /*
- * 25 aug 1992: mao commented out the ht walk below. it should be
- * doing the right thing, in theory, but flushing reldescs for index
- * relations apparently doesn't work. we want to cut 4.0.1, and i
- * don't want to introduce new bugs. this code never executed before,
- * so i'm turning it off for now. after the release is cut, i'll
- * fix this up.
- */
-
- HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushIndexes,
- accessMethodId);
-# else
- return;
-# endif
+#if 0
+
+ /*
+ * 25 aug 1992: mao commented out the ht walk below. it should be
+ * doing the right thing, in theory, but flushing reldescs for index
+ * relations apparently doesn't work. we want to cut 4.0.1, and i
+ * don't want to introduce new bugs. this code never executed before,
+ * so i'm turning it off for now. after the release is cut, i'll fix
+ * this up.
+ */
+
+ HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushIndexes,
+ accessMethodId);
+#else
+ return;
+#endif
}
/*
* RelationCacheInvalidate
*
- * Will blow away either all the cached relation descriptors or
- * those that have a zero reference count.
+ * Will blow away either all the cached relation descriptors or
+ * those that have a zero reference count.
*
*/
void
RelationCacheInvalidate(bool onlyFlushReferenceCountZero)
{
- HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushRelation,
- onlyFlushReferenceCountZero);
-
- /*
- * nailed-in reldescs will still be in the cache...
- * 7 hardwired heaps + 3 hardwired indices == 10 total.
- */
- if (!onlyFlushReferenceCountZero) {
- Assert(RelationNameCache->hctl->nkeys == 10);
- Assert(RelationIdCache->hctl->nkeys == 10);
- }
+ HashTableWalk(RelationNameCache, (HashtFunc) RelationFlushRelation,
+ onlyFlushReferenceCountZero);
+
+ /*
+ * nailed-in reldescs will still be in the cache... 7 hardwired heaps
+ * + 3 hardwired indices == 10 total.
+ */
+ if (!onlyFlushReferenceCountZero)
+ {
+ Assert(RelationNameCache->hctl->nkeys == 10);
+ Assert(RelationIdCache->hctl->nkeys == 10);
+ }
}
-
+
/* --------------------------------
- * RelationRegisterRelation -
- * register the Relation descriptor of a newly created relation
- * with the relation descriptor Cache.
+ * RelationRegisterRelation -
+ * register the Relation descriptor of a newly created relation
+ * with the relation descriptor Cache.
* --------------------------------
*/
void
RelationRegisterRelation(Relation relation)
{
- MemoryContext oldcxt;
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- if (oldcxt != (MemoryContext)CacheCxt)
- elog(NOIND,"RelationRegisterRelation: WARNING: Context != CacheCxt");
-
- RelationCacheInsert(relation);
-
- RelationInitLockInfo(relation);
-
- /*
- * we've just created the relation. It is invisible to anyone else
- * before the transaction is committed. Setting rd_islocal allows us
- * to use the local buffer manager for select/insert/etc before the end
- * of transaction. (We also need to keep track of relations
- * created during a transaction and does the necessary clean up at
- * the end of the transaction.) - ay 3/95
- */
- relation->rd_islocal = TRUE;
- newlyCreatedRelns = lcons(relation, newlyCreatedRelns);
-
- MemoryContextSwitchTo(oldcxt);
+ MemoryContext oldcxt;
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ if (oldcxt != (MemoryContext) CacheCxt)
+ elog(NOIND, "RelationRegisterRelation: WARNING: Context != CacheCxt");
+
+ RelationCacheInsert(relation);
+
+ RelationInitLockInfo(relation);
+
+ /*
+ * we've just created the relation. It is invisible to anyone else
+ * before the transaction is committed. Setting rd_islocal allows us
+ * to use the local buffer manager for select/insert/etc before the
+ * end of transaction. (We also need to keep track of relations
+ * created during a transaction and does the necessary clean up at the
+ * end of the transaction.) - ay 3/95
+ */
+ relation->rd_islocal = TRUE;
+ newlyCreatedRelns = lcons(relation, newlyCreatedRelns);
+
+ MemoryContextSwitchTo(oldcxt);
}
/*
* RelationPurgeLocalRelation -
- * find all the Relation descriptors marked rd_islocal and reset them.
- * This should be called at the end of a transaction (commit/abort) when
- * the "local" relations will become visible to others and the multi-user
- * buffer pool should be used.
+ * find all the Relation descriptors marked rd_islocal and reset them.
+ * This should be called at the end of a transaction (commit/abort) when
+ * the "local" relations will become visible to others and the multi-user
+ * buffer pool should be used.
*/
void
RelationPurgeLocalRelation(bool xactCommitted)
{
- MemoryContext oldcxt;
-
- if (newlyCreatedRelns==NULL)
- return;
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- while (newlyCreatedRelns) {
- List *l = newlyCreatedRelns;
- Relation reln = lfirst(l);
-
- Assert(reln!=NULL && reln->rd_islocal);
-
- if (!xactCommitted) {
- /*
- * remove the file if we abort. This is so that files for
- * tables created inside a transaction block get removed.
- */
- if(reln->rd_istemp) {
- if(!(reln->rd_tmpunlinked)) {
- smgrunlink(reln->rd_rel->relsmgr, reln);
- reln->rd_tmpunlinked = TRUE;
- }
- } else {
- smgrunlink(reln->rd_rel->relsmgr, reln);
- }
- }
- else if ( !IsBootstrapProcessingMode () && !(reln->rd_istemp) )
- /*
- * RelationFlushRelation () below will flush relation information
- * from the cache. We must call smgrclose to flush relation
- * information from SMGR & FMGR, too. We assume that for temp
- * relations smgrunlink is already called by heap_destroyr
- * and we skip smgrclose for them. - vadim 05/22/97
- */
- smgrclose(reln->rd_rel->relsmgr, reln);
-
- reln->rd_islocal = FALSE;
+ MemoryContext oldcxt;
- if (!IsBootstrapProcessingMode())
- RelationFlushRelation(&reln, FALSE);
-
- newlyCreatedRelns = lnext(newlyCreatedRelns);
- pfree(l);
- }
+ if (newlyCreatedRelns == NULL)
+ return;
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
- MemoryContextSwitchTo(oldcxt);
+ while (newlyCreatedRelns)
+ {
+ List *l = newlyCreatedRelns;
+ Relation reln = lfirst(l);
+
+ Assert(reln != NULL && reln->rd_islocal);
+
+ if (!xactCommitted)
+ {
+
+ /*
+ * remove the file if we abort. This is so that files for
+ * tables created inside a transaction block get removed.
+ */
+ if (reln->rd_istemp)
+ {
+ if (!(reln->rd_tmpunlinked))
+ {
+ smgrunlink(reln->rd_rel->relsmgr, reln);
+ reln->rd_tmpunlinked = TRUE;
+ }
+ }
+ else
+ {
+ smgrunlink(reln->rd_rel->relsmgr, reln);
+ }
+ }
+ else if (!IsBootstrapProcessingMode() && !(reln->rd_istemp))
+
+ /*
+ * RelationFlushRelation () below will flush relation
+ * information from the cache. We must call smgrclose to flush
+ * relation information from SMGR & FMGR, too. We assume that
+ * for temp relations smgrunlink is already called by
+ * heap_destroyr and we skip smgrclose for them. -
+ * vadim 05/22/97
+ */
+ smgrclose(reln->rd_rel->relsmgr, reln);
+
+ reln->rd_islocal = FALSE;
+
+ if (!IsBootstrapProcessingMode())
+ RelationFlushRelation(&reln, FALSE);
+
+ newlyCreatedRelns = lnext(newlyCreatedRelns);
+ pfree(l);
+ }
+
+ MemoryContextSwitchTo(oldcxt);
}
/* --------------------------------
- * RelationInitialize
+ * RelationInitialize
*
- * This initializes the relation descriptor cache.
+ * This initializes the relation descriptor cache.
* --------------------------------
*/
-#define INITRELCACHESIZE 400
+#define INITRELCACHESIZE 400
void
RelationInitialize(void)
{
- MemoryContext oldcxt;
- HASHCTL ctl;
-
- /* ----------------
- * switch to cache memory context
- * ----------------
- */
- if (!CacheCxt)
- CacheCxt = CreateGlobalMemory("Cache");
-
- oldcxt = MemoryContextSwitchTo((MemoryContext)CacheCxt);
-
- /* ----------------
- * create global caches
- * ----------------
- */
- memset(&ctl,0, (int) sizeof(ctl));
- ctl.keysize = sizeof(NameData);
- ctl.datasize = sizeof(Relation);
- RelationNameCache = hash_create(INITRELCACHESIZE, &ctl, HASH_ELEM);
-
- ctl.keysize = sizeof(Oid);
- ctl.hash = tag_hash;
- RelationIdCache = hash_create(INITRELCACHESIZE, &ctl,
- HASH_ELEM | HASH_FUNCTION);
-
- /* ----------------
- * initialize the cache with pre-made relation descriptors
- * for some of the more important system relations. These
- * relations should always be in the cache.
- * ----------------
- */
- formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class);
- formrdesc(AttributeRelationName, Natts_pg_attribute, Desc_pg_attribute);
- formrdesc(ProcedureRelationName, Natts_pg_proc, Desc_pg_proc);
- formrdesc(TypeRelationName, Natts_pg_type, Desc_pg_type);
- formrdesc(VariableRelationName, Natts_pg_variable, Desc_pg_variable);
- formrdesc(LogRelationName, Natts_pg_log, Desc_pg_log);
- formrdesc(TimeRelationName, Natts_pg_time, Desc_pg_time);
-
- /*
- * If this isn't initdb time, then we want to initialize some index
- * relation descriptors, as well. The descriptors are for pg_attnumind
- * (to make building relation descriptors fast) and possibly others,
- * as they're added.
- */
-
- if (!IsBootstrapProcessingMode())
- init_irels();
-
- MemoryContextSwitchTo(oldcxt);
+ MemoryContext oldcxt;
+ HASHCTL ctl;
+
+ /* ----------------
+ * switch to cache memory context
+ * ----------------
+ */
+ if (!CacheCxt)
+ CacheCxt = CreateGlobalMemory("Cache");
+
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+
+ /* ----------------
+ * create global caches
+ * ----------------
+ */
+ memset(&ctl, 0, (int) sizeof(ctl));
+ ctl.keysize = sizeof(NameData);
+ ctl.datasize = sizeof(Relation);
+ RelationNameCache = hash_create(INITRELCACHESIZE, &ctl, HASH_ELEM);
+
+ ctl.keysize = sizeof(Oid);
+ ctl.hash = tag_hash;
+ RelationIdCache = hash_create(INITRELCACHESIZE, &ctl,
+ HASH_ELEM | HASH_FUNCTION);
+
+ /* ----------------
+ * initialize the cache with pre-made relation descriptors
+ * for some of the more important system relations. These
+ * relations should always be in the cache.
+ * ----------------
+ */
+ formrdesc(RelationRelationName, Natts_pg_class, Desc_pg_class);
+ formrdesc(AttributeRelationName, Natts_pg_attribute, Desc_pg_attribute);
+ formrdesc(ProcedureRelationName, Natts_pg_proc, Desc_pg_proc);
+ formrdesc(TypeRelationName, Natts_pg_type, Desc_pg_type);
+ formrdesc(VariableRelationName, Natts_pg_variable, Desc_pg_variable);
+ formrdesc(LogRelationName, Natts_pg_log, Desc_pg_log);
+ formrdesc(TimeRelationName, Natts_pg_time, Desc_pg_time);
+
+ /*
+ * If this isn't initdb time, then we want to initialize some index
+ * relation descriptors, as well. The descriptors are for
+ * pg_attnumind (to make building relation descriptors fast) and
+ * possibly others, as they're added.
+ */
+
+ if (!IsBootstrapProcessingMode())
+ init_irels();
+
+ MemoryContextSwitchTo(oldcxt);
}
static void
-AttrDefaultFetch (Relation relation)
+AttrDefaultFetch(Relation relation)
{
- AttrDefault *attrdef = relation->rd_att->constr->defval;
- int ndef = relation->rd_att->constr->num_defval;
- Relation adrel;
- Relation irel;
- ScanKeyData skey;
- HeapTuple tuple;
- Form_pg_attrdef adform;
- IndexScanDesc sd;
- RetrieveIndexResult indexRes;
- Buffer buffer;
- ItemPointer iptr;
- struct varlena *val;
- bool isnull;
- int found;
- int i;
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relation->rd_id));
-
- adrel = heap_openr(AttrDefaultRelationName);
- irel = index_openr(AttrDefaultIndex);
- sd = index_beginscan(irel, false, 1, &skey);
- tuple = (HeapTuple)NULL;
-
- for (found = 0; ; )
- {
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (!indexRes)
- break;
-
- iptr = &indexRes->heap_iptr;
- tuple = heap_fetch(adrel, NowTimeQual, iptr, &buffer);
- pfree(indexRes);
- if (!HeapTupleIsValid(tuple))
- continue;
- found++;
- adform = (Form_pg_attrdef) GETSTRUCT(tuple);
- for (i = 0; i < ndef; i++)
- {
- if ( adform->adnum != attrdef[i].adnum )
- continue;
- if ( attrdef[i].adsrc != NULL )
- elog (WARN, "AttrDefaultFetch: second record found for attr %.*s in rel %.*s",
- NAMEDATALEN, relation->rd_att->attrs[adform->adnum - 1]->attname.data,
- NAMEDATALEN, relation->rd_rel->relname.data);
-
- val = (struct varlena*) fastgetattr (tuple,
- Anum_pg_attrdef_adbin,
- adrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "AttrDefaultFetch: adbin IS NULL for attr %.*s in rel %.*s",
- NAMEDATALEN, relation->rd_att->attrs[adform->adnum - 1]->attname.data,
- NAMEDATALEN, relation->rd_rel->relname.data);
- attrdef[i].adbin = textout (val);
- val = (struct varlena*) fastgetattr (tuple,
- Anum_pg_attrdef_adsrc,
- adrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "AttrDefaultFetch: adsrc IS NULL for attr %.*s in rel %.*s",
- NAMEDATALEN, relation->rd_att->attrs[adform->adnum - 1]->attname.data,
- NAMEDATALEN, relation->rd_rel->relname.data);
- attrdef[i].adsrc = textout (val);
- break;
- }
-
- if ( i >= ndef )
- elog (WARN, "AttrDefaultFetch: unexpected record found for attr %d in rel %.*s",
- adform->adnum,
- NAMEDATALEN, relation->rd_rel->relname.data);
- ReleaseBuffer(buffer);
- }
-
- if ( found < ndef )
- elog (WARN, "AttrDefaultFetch: %d record not found for rel %.*s",
- ndef - found,
- NAMEDATALEN, relation->rd_rel->relname.data);
-
- index_endscan (sd);
- pfree (sd);
- index_close (irel);
- heap_close (adrel);
-
+ AttrDefault *attrdef = relation->rd_att->constr->defval;
+ int ndef = relation->rd_att->constr->num_defval;
+ Relation adrel;
+ Relation irel;
+ ScanKeyData skey;
+ HeapTuple tuple;
+ Form_pg_attrdef adform;
+ IndexScanDesc sd;
+ RetrieveIndexResult indexRes;
+ Buffer buffer;
+ ItemPointer iptr;
+ struct varlena *val;
+ bool isnull;
+ int found;
+ int i;
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relation->rd_id));
+
+ adrel = heap_openr(AttrDefaultRelationName);
+ irel = index_openr(AttrDefaultIndex);
+ sd = index_beginscan(irel, false, 1, &skey);
+ tuple = (HeapTuple) NULL;
+
+ for (found = 0;;)
+ {
+ indexRes = index_getnext(sd, ForwardScanDirection);
+ if (!indexRes)
+ break;
+
+ iptr = &indexRes->heap_iptr;
+ tuple = heap_fetch(adrel, NowTimeQual, iptr, &buffer);
+ pfree(indexRes);
+ if (!HeapTupleIsValid(tuple))
+ continue;
+ found++;
+ adform = (Form_pg_attrdef) GETSTRUCT(tuple);
+ for (i = 0; i < ndef; i++)
+ {
+ if (adform->adnum != attrdef[i].adnum)
+ continue;
+ if (attrdef[i].adsrc != NULL)
+ elog(WARN, "AttrDefaultFetch: second record found for attr %.*s in rel %.*s",
+ NAMEDATALEN, relation->rd_att->attrs[adform->adnum - 1]->attname.data,
+ NAMEDATALEN, relation->rd_rel->relname.data);
+
+ val = (struct varlena *) fastgetattr(tuple,
+ Anum_pg_attrdef_adbin,
+ adrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "AttrDefaultFetch: adbin IS NULL for attr %.*s in rel %.*s",
+ NAMEDATALEN, relation->rd_att->attrs[adform->adnum - 1]->attname.data,
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ attrdef[i].adbin = textout(val);
+ val = (struct varlena *) fastgetattr(tuple,
+ Anum_pg_attrdef_adsrc,
+ adrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "AttrDefaultFetch: adsrc IS NULL for attr %.*s in rel %.*s",
+ NAMEDATALEN, relation->rd_att->attrs[adform->adnum - 1]->attname.data,
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ attrdef[i].adsrc = textout(val);
+ break;
+ }
+
+ if (i >= ndef)
+ elog(WARN, "AttrDefaultFetch: unexpected record found for attr %d in rel %.*s",
+ adform->adnum,
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ ReleaseBuffer(buffer);
+ }
+
+ if (found < ndef)
+ elog(WARN, "AttrDefaultFetch: %d record not found for rel %.*s",
+ ndef - found,
+ NAMEDATALEN, relation->rd_rel->relname.data);
+
+ index_endscan(sd);
+ pfree(sd);
+ index_close(irel);
+ heap_close(adrel);
+
}
static void
-RelCheckFetch (Relation relation)
+RelCheckFetch(Relation relation)
{
- ConstrCheck *check = relation->rd_att->constr->check;
- int ncheck = relation->rd_att->constr->num_check;
- Relation rcrel;
- Relation irel;
- ScanKeyData skey;
- HeapTuple tuple;
- IndexScanDesc sd;
- RetrieveIndexResult indexRes;
- Buffer buffer;
- ItemPointer iptr;
- Name rcname;
- struct varlena *val;
- bool isnull;
- int found;
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relation->rd_id));
-
- rcrel = heap_openr(RelCheckRelationName);
- irel = index_openr(RelCheckIndex);
- sd = index_beginscan(irel, false, 1, &skey);
- tuple = (HeapTuple)NULL;
-
- for (found = 0; ; )
- {
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (!indexRes)
- break;
-
- iptr = &indexRes->heap_iptr;
- tuple = heap_fetch(rcrel, NowTimeQual, iptr, &buffer);
- pfree(indexRes);
- if (!HeapTupleIsValid(tuple))
- continue;
- if ( found == ncheck )
- elog (WARN, "RelCheckFetch: unexpected record found for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
-
- rcname = (Name) fastgetattr (tuple,
- Anum_pg_relcheck_rcname,
- rcrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "RelCheckFetch: rcname IS NULL for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
- check[found].ccname = nameout (rcname);
- val = (struct varlena*) fastgetattr (tuple,
- Anum_pg_relcheck_rcbin,
- rcrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "RelCheckFetch: rcbin IS NULL for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
- check[found].ccbin = textout (val);
- val = (struct varlena*) fastgetattr (tuple,
- Anum_pg_relcheck_rcsrc,
- rcrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "RelCheckFetch: rcsrc IS NULL for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
- check[found].ccsrc = textout (val);
- found++;
-
- ReleaseBuffer(buffer);
- }
-
- if ( found < ncheck )
- elog (WARN, "RelCheckFetch: %d record not found for rel %.*s",
- ncheck - found,
- NAMEDATALEN, relation->rd_rel->relname.data);
-
- index_endscan (sd);
- pfree (sd);
- index_close (irel);
- heap_close (rcrel);
-
+ ConstrCheck *check = relation->rd_att->constr->check;
+ int ncheck = relation->rd_att->constr->num_check;
+ Relation rcrel;
+ Relation irel;
+ ScanKeyData skey;
+ HeapTuple tuple;
+ IndexScanDesc sd;
+ RetrieveIndexResult indexRes;
+ Buffer buffer;
+ ItemPointer iptr;
+ Name rcname;
+ struct varlena *val;
+ bool isnull;
+ int found;
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relation->rd_id));
+
+ rcrel = heap_openr(RelCheckRelationName);
+ irel = index_openr(RelCheckIndex);
+ sd = index_beginscan(irel, false, 1, &skey);
+ tuple = (HeapTuple) NULL;
+
+ for (found = 0;;)
+ {
+ indexRes = index_getnext(sd, ForwardScanDirection);
+ if (!indexRes)
+ break;
+
+ iptr = &indexRes->heap_iptr;
+ tuple = heap_fetch(rcrel, NowTimeQual, iptr, &buffer);
+ pfree(indexRes);
+ if (!HeapTupleIsValid(tuple))
+ continue;
+ if (found == ncheck)
+ elog(WARN, "RelCheckFetch: unexpected record found for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+
+ rcname = (Name) fastgetattr(tuple,
+ Anum_pg_relcheck_rcname,
+ rcrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "RelCheckFetch: rcname IS NULL for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ check[found].ccname = nameout(rcname);
+ val = (struct varlena *) fastgetattr(tuple,
+ Anum_pg_relcheck_rcbin,
+ rcrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "RelCheckFetch: rcbin IS NULL for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ check[found].ccbin = textout(val);
+ val = (struct varlena *) fastgetattr(tuple,
+ Anum_pg_relcheck_rcsrc,
+ rcrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "RelCheckFetch: rcsrc IS NULL for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ check[found].ccsrc = textout(val);
+ found++;
+
+ ReleaseBuffer(buffer);
+ }
+
+ if (found < ncheck)
+ elog(WARN, "RelCheckFetch: %d record not found for rel %.*s",
+ ncheck - found,
+ NAMEDATALEN, relation->rd_rel->relname.data);
+
+ index_endscan(sd);
+ pfree(sd);
+ index_close(irel);
+ heap_close(rcrel);
+
}
/*
- * init_irels(), write_irels() -- handle special-case initialization of
- * index relation descriptors.
+ * init_irels(), write_irels() -- handle special-case initialization of
+ * index relation descriptors.
*
- * In late 1992, we started regularly having databases with more than
- * a thousand classes in them. With this number of classes, it became
- * critical to do indexed lookups on the system catalogs.
+ * In late 1992, we started regularly having databases with more than
+ * a thousand classes in them. With this number of classes, it became
+ * critical to do indexed lookups on the system catalogs.
*
- * Bootstrapping these lookups is very hard. We want to be able to
- * use an index on pg_attribute, for example, but in order to do so,
- * we must have read pg_attribute for the attributes in the index,
- * which implies that we need to use the index.
+ * Bootstrapping these lookups is very hard. We want to be able to
+ * use an index on pg_attribute, for example, but in order to do so,
+ * we must have read pg_attribute for the attributes in the index,
+ * which implies that we need to use the index.
*
- * In order to get around the problem, we do the following:
+ * In order to get around the problem, we do the following:
*
- * + When the database system is initialized (at initdb time), we
- * don't use indices on pg_attribute. We do sequential scans.
+ * + When the database system is initialized (at initdb time), we
+ * don't use indices on pg_attribute. We do sequential scans.
*
- * + When the backend is started up in normal mode, we load an image
- * of the appropriate relation descriptors, in internal format,
- * from an initialization file in the data/base/... directory.
+ * + When the backend is started up in normal mode, we load an image
+ * of the appropriate relation descriptors, in internal format,
+ * from an initialization file in the data/base/... directory.
*
- * + If the initialization file isn't there, then we create the
- * relation descriptor using sequential scans and write it to
- * the initialization file for use by subsequent backends.
+ * + If the initialization file isn't there, then we create the
+ * relation descriptor using sequential scans and write it to
+ * the initialization file for use by subsequent backends.
*
- * This is complicated and interferes with system changes, but
- * performance is so bad that we're willing to pay the tax.
+ * This is complicated and interferes with system changes, but
+ * performance is so bad that we're willing to pay the tax.
*/
/* pg_attnumind, pg_classnameind, pg_classoidind */
@@ -1833,268 +1902,288 @@ RelCheckFetch (Relation relation)
static void
init_irels(void)
{
- Size len;
- int nread;
- File fd;
- Relation irel[Num_indices_bootstrap];
- Relation ird;
- Form_pg_am am;
- Form_pg_class relform;
- IndexStrategy strat;
- RegProcedure *support;
- int i;
- int relno;
-
- if ((fd = FileNameOpenFile(INIT_FILENAME, O_RDONLY, 0600)) < 0) {
- write_irels();
- return;
- }
-
- FileSeek(fd, 0L, SEEK_SET);
-
- for (relno = 0; relno < Num_indices_bootstrap; relno++) {
- /* first read the relation descriptor length*/
- if ((nread = FileRead(fd, (char*)&len, sizeof(int))) != sizeof(int)) {
- write_irels();
- return;
- }
-
- ird = irel[relno] = (Relation) palloc(len);
- memset(ird, 0, len);
-
- /* then, read the Relation structure */
- if ((nread = FileRead(fd, (char*)ird, len)) != len) {
- write_irels();
- return;
- }
-
- /* the file descriptor is not yet opened */
- ird->rd_fd = -1;
-
- /* lock info is not initialized */
- ird->lockInfo = (char *) NULL;
-
- /* next, read the access method tuple form */
- if ((nread = FileRead(fd, (char*)&len, sizeof(int))) != sizeof(int)) {
- write_irels();
- return;
- }
-
- am = (Form_pg_am) palloc(len);
- if ((nread = FileRead(fd, (char*)am, len)) != len) {
- write_irels();
- return;
- }
-
- ird->rd_am = am;
-
- /* next read the relation tuple form */
- if ((nread = FileRead(fd, (char*)&len, sizeof(int))) != sizeof(int)) {
- write_irels();
- return;
- }
-
- relform = (Form_pg_class) palloc(len);
- if ((nread = FileRead(fd, (char*)relform, len)) != len) {
- write_irels();
- return;
- }
-
- ird->rd_rel = relform;
-
- /* initialize attribute tuple forms */
- ird->rd_att = CreateTemplateTupleDesc(relform->relnatts);
-
- /* next read all the attribute tuple form data entries */
- len = ATTRIBUTE_TUPLE_SIZE;
- for (i = 0; i < relform->relnatts; i++) {
- if ((nread = FileRead(fd, (char*)&len, sizeof(int))) != sizeof(int)) {
- write_irels();
- return;
- }
-
- ird->rd_att->attrs[i] = (AttributeTupleForm) palloc(len);
-
- if ((nread = FileRead(fd, (char*)ird->rd_att->attrs[i], len)) != len) {
+ Size len;
+ int nread;
+ File fd;
+ Relation irel[Num_indices_bootstrap];
+ Relation ird;
+ Form_pg_am am;
+ Form_pg_class relform;
+ IndexStrategy strat;
+ RegProcedure *support;
+ int i;
+ int relno;
+
+ if ((fd = FileNameOpenFile(INIT_FILENAME, O_RDONLY, 0600)) < 0)
+ {
write_irels();
return;
- }
- }
-
- /* next, read the index strategy map */
- if ((nread = FileRead(fd, (char*)&len, sizeof(int))) != sizeof(int)) {
- write_irels();
- return;
- }
-
- strat = (IndexStrategy) palloc(len);
- if ((nread = FileRead(fd, (char*)strat, len)) != len) {
- write_irels();
- return;
}
-
- /* oh, for god's sake... */
+
+ FileSeek(fd, 0L, SEEK_SET);
+
+ for (relno = 0; relno < Num_indices_bootstrap; relno++)
+ {
+ /* first read the relation descriptor length */
+ if ((nread = FileRead(fd, (char *) &len, sizeof(int))) != sizeof(int))
+ {
+ write_irels();
+ return;
+ }
+
+ ird = irel[relno] = (Relation) palloc(len);
+ memset(ird, 0, len);
+
+ /* then, read the Relation structure */
+ if ((nread = FileRead(fd, (char *) ird, len)) != len)
+ {
+ write_irels();
+ return;
+ }
+
+ /* the file descriptor is not yet opened */
+ ird->rd_fd = -1;
+
+ /* lock info is not initialized */
+ ird->lockInfo = (char *) NULL;
+
+ /* next, read the access method tuple form */
+ if ((nread = FileRead(fd, (char *) &len, sizeof(int))) != sizeof(int))
+ {
+ write_irels();
+ return;
+ }
+
+ am = (Form_pg_am) palloc(len);
+ if ((nread = FileRead(fd, (char *) am, len)) != len)
+ {
+ write_irels();
+ return;
+ }
+
+ ird->rd_am = am;
+
+ /* next read the relation tuple form */
+ if ((nread = FileRead(fd, (char *) &len, sizeof(int))) != sizeof(int))
+ {
+ write_irels();
+ return;
+ }
+
+ relform = (Form_pg_class) palloc(len);
+ if ((nread = FileRead(fd, (char *) relform, len)) != len)
+ {
+ write_irels();
+ return;
+ }
+
+ ird->rd_rel = relform;
+
+ /* initialize attribute tuple forms */
+ ird->rd_att = CreateTemplateTupleDesc(relform->relnatts);
+
+ /* next read all the attribute tuple form data entries */
+ len = ATTRIBUTE_TUPLE_SIZE;
+ for (i = 0; i < relform->relnatts; i++)
+ {
+ if ((nread = FileRead(fd, (char *) &len, sizeof(int))) != sizeof(int))
+ {
+ write_irels();
+ return;
+ }
+
+ ird->rd_att->attrs[i] = (AttributeTupleForm) palloc(len);
+
+ if ((nread = FileRead(fd, (char *) ird->rd_att->attrs[i], len)) != len)
+ {
+ write_irels();
+ return;
+ }
+ }
+
+ /* next, read the index strategy map */
+ if ((nread = FileRead(fd, (char *) &len, sizeof(int))) != sizeof(int))
+ {
+ write_irels();
+ return;
+ }
+
+ strat = (IndexStrategy) palloc(len);
+ if ((nread = FileRead(fd, (char *) strat, len)) != len)
+ {
+ write_irels();
+ return;
+ }
+
+ /* oh, for god's sake... */
#define SMD(i) strat[0].strategyMapData[i].entry[0]
-
- /* have to reinit the function pointers in the strategy maps */
- for (i = 0; i < am->amstrategies; i++)
- fmgr_info(SMD(i).sk_procedure,
- &(SMD(i).sk_func), &(SMD(i).sk_nargs));
-
-
- /* use a real field called rd_istrat instead of the
- bogosity of hanging invisible fields off the end of a structure
- - jolly */
- ird->rd_istrat = strat;
-
- /* finally, read the vector of support procedures */
- if ((nread = FileRead(fd, (char*)&len, sizeof(int))) != sizeof(int)) {
- write_irels();
- return;
- }
-
- support = (RegProcedure *) palloc(len);
- if ((nread = FileRead(fd, (char*)support, len)) != len) {
- write_irels();
- return;
- }
-
- /*
- p += sizeof(IndexStrategy);
- *((RegProcedure **) p) = support;
- */
- ird->rd_support = support;
-
- RelationCacheInsert(ird);
- }
+ /* have to reinit the function pointers in the strategy maps */
+ for (i = 0; i < am->amstrategies; i++)
+ fmgr_info(SMD(i).sk_procedure,
+ &(SMD(i).sk_func), &(SMD(i).sk_nargs));
+
+
+ /*
+ * use a real field called rd_istrat instead of the bogosity of
+ * hanging invisible fields off the end of a structure - jolly
+ */
+ ird->rd_istrat = strat;
+
+ /* finally, read the vector of support procedures */
+ if ((nread = FileRead(fd, (char *) &len, sizeof(int))) != sizeof(int))
+ {
+ write_irels();
+ return;
+ }
+
+ support = (RegProcedure *) palloc(len);
+ if ((nread = FileRead(fd, (char *) support, len)) != len)
+ {
+ write_irels();
+ return;
+ }
+
+ /*
+ * p += sizeof(IndexStrategy); ((RegProcedure **) p) = support;
+ */
+
+ ird->rd_support = support;
+
+ RelationCacheInsert(ird);
+ }
}
static void
write_irels(void)
{
- int len;
- int nwritten;
- File fd;
- Relation irel[Num_indices_bootstrap];
- Relation ird;
- Form_pg_am am;
- Form_pg_class relform;
- IndexStrategy strat;
- RegProcedure *support;
- ProcessingMode oldmode;
- int i;
- int relno;
- RelationBuildDescInfo bi;
-
- fd = FileNameOpenFile(INIT_FILENAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
- if (fd < 0)
- elog(FATAL, "cannot create init file %s", INIT_FILENAME);
-
- FileSeek(fd, 0L, SEEK_SET);
-
- /*
- * Build a relation descriptor for pg_attnumind without resort to the
- * descriptor cache. In order to do this, we set ProcessingMode
- * to Bootstrap. The effect of this is to disable indexed relation
- * searches -- a necessary step, since we're trying to instantiate
- * the index relation descriptors here.
- */
-
- oldmode = GetProcessingMode();
- SetProcessingMode(BootstrapProcessing);
-
- bi.infotype = INFO_RELNAME;
- bi.i.info_name = AttributeNumIndex;
- irel[0] = RelationBuildDesc(bi);
- irel[0]->rd_isnailed = true;
-
- bi.i.info_name = ClassNameIndex;
- irel[1] = RelationBuildDesc(bi);
- irel[1]->rd_isnailed = true;
-
- bi.i.info_name = ClassOidIndex;
- irel[2] = RelationBuildDesc(bi);
- irel[2]->rd_isnailed = true;
-
- SetProcessingMode(oldmode);
-
- /* nail the descriptor in the cache */
- for (relno = 0; relno < Num_indices_bootstrap; relno++) {
- ird = irel[relno];
-
- /* save the volatile fields in the relation descriptor */
- am = ird->rd_am;
- ird->rd_am = (Form_pg_am) NULL;
- relform = ird->rd_rel;
- ird->rd_rel = (Form_pg_class) NULL;
- strat = ird->rd_istrat;
- support = ird->rd_support;
-
- /* first write the relation descriptor , excluding strategy and support */
- len = sizeof(RelationData);
-
- /* first, write the relation descriptor length */
- if ((nwritten = FileWrite(fd, (char*) &len, sizeof(int)))
- != sizeof(int))
- elog(FATAL, "cannot write init file -- descriptor length");
-
- /* next, write out the Relation structure */
- if ((nwritten = FileWrite(fd, (char*) ird, len)) != len)
- elog(FATAL, "cannot write init file -- reldesc");
-
- /* next, write the access method tuple form */
- len = sizeof(FormData_pg_am);
- if ((nwritten = FileWrite(fd, (char*) &len, sizeof(int)))
- != sizeof(int))
- elog(FATAL, "cannot write init file -- am tuple form length");
-
- if ((nwritten = FileWrite(fd, (char*) am, len)) != len)
- elog(FATAL, "cannot write init file -- am tuple form");
-
- /* next write the relation tuple form */
- len = sizeof(FormData_pg_class);
- if ((nwritten = FileWrite(fd, (char*) &len, sizeof(int)))
- != sizeof(int))
- elog(FATAL, "cannot write init file -- relation tuple form length");
-
- if ((nwritten = FileWrite(fd, (char*) relform, len)) != len)
- elog(FATAL, "cannot write init file -- relation tuple form");
-
- /* next, do all the attribute tuple form data entries */
- len = ATTRIBUTE_TUPLE_SIZE;
- for (i = 0; i < relform->relnatts; i++) {
- if ((nwritten = FileWrite(fd, (char*) &len, sizeof(int)))
- != sizeof(int))
- elog(FATAL, "cannot write init file -- length of attdesc %d", i);
- if ((nwritten = FileWrite(fd, (char*) ird->rd_att->attrs[i], len))
- != len)
- elog(FATAL, "cannot write init file -- attdesc %d", i);
+ int len;
+ int nwritten;
+ File fd;
+ Relation irel[Num_indices_bootstrap];
+ Relation ird;
+ Form_pg_am am;
+ Form_pg_class relform;
+ IndexStrategy strat;
+ RegProcedure *support;
+ ProcessingMode oldmode;
+ int i;
+ int relno;
+ RelationBuildDescInfo bi;
+
+ fd = FileNameOpenFile(INIT_FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (fd < 0)
+ elog(FATAL, "cannot create init file %s", INIT_FILENAME);
+
+ FileSeek(fd, 0L, SEEK_SET);
+
+ /*
+ * Build a relation descriptor for pg_attnumind without resort to the
+ * descriptor cache. In order to do this, we set ProcessingMode to
+ * Bootstrap. The effect of this is to disable indexed relation
+ * searches -- a necessary step, since we're trying to instantiate the
+ * index relation descriptors here.
+ */
+
+ oldmode = GetProcessingMode();
+ SetProcessingMode(BootstrapProcessing);
+
+ bi.infotype = INFO_RELNAME;
+ bi.i.info_name = AttributeNumIndex;
+ irel[0] = RelationBuildDesc(bi);
+ irel[0]->rd_isnailed = true;
+
+ bi.i.info_name = ClassNameIndex;
+ irel[1] = RelationBuildDesc(bi);
+ irel[1]->rd_isnailed = true;
+
+ bi.i.info_name = ClassOidIndex;
+ irel[2] = RelationBuildDesc(bi);
+ irel[2]->rd_isnailed = true;
+
+ SetProcessingMode(oldmode);
+
+ /* nail the descriptor in the cache */
+ for (relno = 0; relno < Num_indices_bootstrap; relno++)
+ {
+ ird = irel[relno];
+
+ /* save the volatile fields in the relation descriptor */
+ am = ird->rd_am;
+ ird->rd_am = (Form_pg_am) NULL;
+ relform = ird->rd_rel;
+ ird->rd_rel = (Form_pg_class) NULL;
+ strat = ird->rd_istrat;
+ support = ird->rd_support;
+
+ /*
+ * first write the relation descriptor , excluding strategy and
+ * support
+ */
+ len = sizeof(RelationData);
+
+ /* first, write the relation descriptor length */
+ if ((nwritten = FileWrite(fd, (char *) &len, sizeof(int)))
+ != sizeof(int))
+ elog(FATAL, "cannot write init file -- descriptor length");
+
+ /* next, write out the Relation structure */
+ if ((nwritten = FileWrite(fd, (char *) ird, len)) != len)
+ elog(FATAL, "cannot write init file -- reldesc");
+
+ /* next, write the access method tuple form */
+ len = sizeof(FormData_pg_am);
+ if ((nwritten = FileWrite(fd, (char *) &len, sizeof(int)))
+ != sizeof(int))
+ elog(FATAL, "cannot write init file -- am tuple form length");
+
+ if ((nwritten = FileWrite(fd, (char *) am, len)) != len)
+ elog(FATAL, "cannot write init file -- am tuple form");
+
+ /* next write the relation tuple form */
+ len = sizeof(FormData_pg_class);
+ if ((nwritten = FileWrite(fd, (char *) &len, sizeof(int)))
+ != sizeof(int))
+ elog(FATAL, "cannot write init file -- relation tuple form length");
+
+ if ((nwritten = FileWrite(fd, (char *) relform, len)) != len)
+ elog(FATAL, "cannot write init file -- relation tuple form");
+
+ /* next, do all the attribute tuple form data entries */
+ len = ATTRIBUTE_TUPLE_SIZE;
+ for (i = 0; i < relform->relnatts; i++)
+ {
+ if ((nwritten = FileWrite(fd, (char *) &len, sizeof(int)))
+ != sizeof(int))
+ elog(FATAL, "cannot write init file -- length of attdesc %d", i);
+ if ((nwritten = FileWrite(fd, (char *) ird->rd_att->attrs[i], len))
+ != len)
+ elog(FATAL, "cannot write init file -- attdesc %d", i);
+ }
+
+ /* next, write the index strategy map */
+ len = AttributeNumberGetIndexStrategySize(relform->relnatts,
+ am->amstrategies);
+ if ((nwritten = FileWrite(fd, (char *) &len, sizeof(int)))
+ != sizeof(int))
+ elog(FATAL, "cannot write init file -- strategy map length");
+
+ if ((nwritten = FileWrite(fd, (char *) strat, len)) != len)
+ elog(FATAL, "cannot write init file -- strategy map");
+
+ /* finally, write the vector of support procedures */
+ len = relform->relnatts * (am->amsupport * sizeof(RegProcedure));
+ if ((nwritten = FileWrite(fd, (char *) &len, sizeof(int)))
+ != sizeof(int))
+ elog(FATAL, "cannot write init file -- support vector length");
+
+ if ((nwritten = FileWrite(fd, (char *) support, len)) != len)
+ elog(FATAL, "cannot write init file -- support vector");
+
+ /* restore volatile fields */
+ ird->rd_am = am;
+ ird->rd_rel = relform;
}
-
- /* next, write the index strategy map */
- len = AttributeNumberGetIndexStrategySize(relform->relnatts,
- am->amstrategies);
- if ((nwritten = FileWrite(fd, (char*) &len, sizeof(int)))
- != sizeof(int))
- elog(FATAL, "cannot write init file -- strategy map length");
-
- if ((nwritten = FileWrite(fd, (char*) strat, len)) != len)
- elog(FATAL, "cannot write init file -- strategy map");
-
- /* finally, write the vector of support procedures */
- len = relform->relnatts * (am->amsupport * sizeof(RegProcedure));
- if ((nwritten = FileWrite(fd, (char*) &len, sizeof(int)))
- != sizeof(int))
- elog(FATAL, "cannot write init file -- support vector length");
-
- if ((nwritten = FileWrite(fd, (char*) support, len)) != len)
- elog(FATAL, "cannot write init file -- support vector");
-
- /* restore volatile fields */
- ird->rd_am = am;
- ird->rd_rel = relform;
- }
-
- FileClose(fd);
+
+ FileClose(fd);
}
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
index 460e8d40af0..5f6c22b95fc 100644
--- a/src/backend/utils/cache/syscache.c
+++ b/src/backend/utils/cache/syscache.c
@@ -1,37 +1,37 @@
/*-------------------------------------------------------------------------
*
* syscache.c--
- * System cache management routines
+ * System cache management routines
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.4 1996/11/06 10:31:29 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.5 1997/09/07 04:53:10 momjian Exp $
*
* NOTES
- * These routines allow the parser/planner/executor to perform
- * rapid lookups on the contents of the system catalogs.
+ * These routines allow the parser/planner/executor to perform
+ * rapid lookups on the contents of the system catalogs.
*
- * see catalog/syscache.h for a list of the cache id's
+ * see catalog/syscache.h for a list of the cache id's
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-
+
#include "access/heapam.h"
#include "access/htup.h"
#include "catalog/catname.h"
#include "utils/catcache.h"
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-
+
/* ----------------
- * hardwired attribute information comes from system catalog files.
+ * hardwired attribute information comes from system catalog files.
* ----------------
*/
#include "catalog/pg_am.h"
@@ -51,592 +51,625 @@
#include "catalog/pg_user.h"
#include "storage/large_object.h"
#include "catalog/pg_listener.h"
-
-extern bool AMI_OVERRIDE; /* XXX style */
-
+
+extern bool AMI_OVERRIDE; /* XXX style */
+
#include "utils/syscache.h"
#include "catalog/indexing.h"
-
-typedef HeapTuple (*ScanFunc)();
+
+typedef HeapTuple(*ScanFunc) ();
/* ----------------
- * Warning: cacheinfo[] below is changed, then be sure and
- * update the magic constants in syscache.h!
+ * Warning: cacheinfo[] below is changed, then be sure and
+ * update the magic constants in syscache.h!
* ----------------
*/
static struct cachedesc cacheinfo[] = {
- { AccessMethodOperatorRelationName, /* AMOPOPID */
- 3,
- { Anum_pg_amop_amopclaid,
- Anum_pg_amop_amopopr,
- Anum_pg_amop_amopid,
- 0 },
- sizeof(FormData_pg_amop),
- NULL,
- (ScanFunc) NULL },
- { AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
- 3,
- { Anum_pg_amop_amopid,
- Anum_pg_amop_amopclaid,
- Anum_pg_amop_amopstrategy,
- 0 },
- sizeof(FormData_pg_amop),
- NULL,
- (ScanFunc) NULL },
- { AttributeRelationName, /* ATTNAME */
- 2,
- { Anum_pg_attribute_attrelid,
- Anum_pg_attribute_attname,
- 0,
- 0 },
- ATTRIBUTE_TUPLE_SIZE,
- AttributeNameIndex,
- (ScanFunc) AttributeNameIndexScan },
- { AttributeRelationName, /* ATTNUM */
- 2,
- { Anum_pg_attribute_attrelid,
- Anum_pg_attribute_attnum,
- 0,
- 0 },
- ATTRIBUTE_TUPLE_SIZE,
- AttributeNumIndex,
- (ScanFunc) AttributeNumIndexScan },
- { IndexRelationName, /* INDEXRELID */
- 1,
- { Anum_pg_index_indexrelid,
- 0,
- 0,
- 0 },
- offsetof(FormData_pg_index, indpred),
- NULL,
- NULL },
- { LanguageRelationName, /* LANNAME */
- 1,
- { Anum_pg_language_lanname,
- 0,
- 0,
- 0 },
- offsetof(FormData_pg_language, lancompiler),
- NULL,
- NULL },
- { OperatorRelationName, /* OPRNAME */
- 4,
- { Anum_pg_operator_oprname,
- Anum_pg_operator_oprleft,
- Anum_pg_operator_oprright,
- Anum_pg_operator_oprkind },
- sizeof(FormData_pg_operator),
- NULL,
- NULL },
- { OperatorRelationName, /* OPROID */
- 1,
- { ObjectIdAttributeNumber,
- 0,
- 0,
- 0 },
- sizeof(FormData_pg_operator),
- NULL,
- (ScanFunc) NULL },
- { ProcedureRelationName, /* PRONAME */
- 3,
- { Anum_pg_proc_proname,
- Anum_pg_proc_pronargs,
- Anum_pg_proc_proargtypes,
- 0 },
- offsetof(FormData_pg_proc, prosrc),
- ProcedureNameIndex,
- (ScanFunc) ProcedureNameIndexScan },
- { ProcedureRelationName, /* PROOID */
- 1,
- { ObjectIdAttributeNumber,
- 0,
- 0,
- 0 },
- offsetof(FormData_pg_proc, prosrc),
- ProcedureOidIndex,
- (ScanFunc) ProcedureOidIndexScan },
- { RelationRelationName, /* RELNAME */
- 1,
- { Anum_pg_class_relname,
- 0,
- 0,
- 0 },
- CLASS_TUPLE_SIZE,
- ClassNameIndex,
- (ScanFunc) ClassNameIndexScan },
- { RelationRelationName, /* RELOID */
- 1,
- { ObjectIdAttributeNumber,
- 0,
- 0,
- 0 },
- CLASS_TUPLE_SIZE,
- ClassOidIndex,
- (ScanFunc) ClassOidIndexScan },
- { TypeRelationName, /* TYPNAME */
- 1,
- { Anum_pg_type_typname,
- 0,
- 0,
- 0 },
- offsetof(TypeTupleFormData,typalign)+sizeof(char),
- TypeNameIndex,
- TypeNameIndexScan },
- { TypeRelationName, /* TYPOID */
- 1,
- { ObjectIdAttributeNumber,
- 0,
- 0,
+ {AccessMethodOperatorRelationName, /* AMOPOPID */
+ 3,
+ {Anum_pg_amop_amopclaid,
+ Anum_pg_amop_amopopr,
+ Anum_pg_amop_amopid,
+ 0},
+ sizeof(FormData_pg_amop),
+ NULL,
+ (ScanFunc) NULL},
+ {AccessMethodOperatorRelationName, /* AMOPSTRATEGY */
+ 3,
+ {Anum_pg_amop_amopid,
+ Anum_pg_amop_amopclaid,
+ Anum_pg_amop_amopstrategy,
+ 0},
+ sizeof(FormData_pg_amop),
+ NULL,
+ (ScanFunc) NULL},
+ {AttributeRelationName, /* ATTNAME */
+ 2,
+ {Anum_pg_attribute_attrelid,
+ Anum_pg_attribute_attname,
+ 0,
+ 0},
+ ATTRIBUTE_TUPLE_SIZE,
+ AttributeNameIndex,
+ (ScanFunc) AttributeNameIndexScan},
+ {AttributeRelationName, /* ATTNUM */
+ 2,
+ {Anum_pg_attribute_attrelid,
+ Anum_pg_attribute_attnum,
+ 0,
+ 0},
+ ATTRIBUTE_TUPLE_SIZE,
+ AttributeNumIndex,
+ (ScanFunc) AttributeNumIndexScan},
+ {IndexRelationName, /* INDEXRELID */
+ 1,
+ {Anum_pg_index_indexrelid,
+ 0,
+ 0,
+ 0},
+ offsetof(FormData_pg_index, indpred),
+ NULL,
+ NULL},
+ {LanguageRelationName, /* LANNAME */
+ 1,
+ {Anum_pg_language_lanname,
+ 0,
+ 0,
+ 0},
+ offsetof(FormData_pg_language, lancompiler),
+ NULL,
+ NULL},
+ {OperatorRelationName, /* OPRNAME */
+ 4,
+ {Anum_pg_operator_oprname,
+ Anum_pg_operator_oprleft,
+ Anum_pg_operator_oprright,
+ Anum_pg_operator_oprkind},
+ sizeof(FormData_pg_operator),
+ NULL,
+ NULL},
+ {OperatorRelationName, /* OPROID */
+ 1,
+ {ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0},
+ sizeof(FormData_pg_operator),
+ NULL,
+ (ScanFunc) NULL},
+ {ProcedureRelationName, /* PRONAME */
+ 3,
+ {Anum_pg_proc_proname,
+ Anum_pg_proc_pronargs,
+ Anum_pg_proc_proargtypes,
+ 0},
+ offsetof(FormData_pg_proc, prosrc),
+ ProcedureNameIndex,
+ (ScanFunc) ProcedureNameIndexScan},
+ {ProcedureRelationName, /* PROOID */
+ 1,
+ {ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0},
+ offsetof(FormData_pg_proc, prosrc),
+ ProcedureOidIndex,
+ (ScanFunc) ProcedureOidIndexScan},
+ {RelationRelationName, /* RELNAME */
+ 1,
+ {Anum_pg_class_relname,
+ 0,
+ 0,
+ 0},
+ CLASS_TUPLE_SIZE,
+ ClassNameIndex,
+ (ScanFunc) ClassNameIndexScan},
+ {RelationRelationName, /* RELOID */
+ 1,
+ {ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0},
+ CLASS_TUPLE_SIZE,
+ ClassOidIndex,
+ (ScanFunc) ClassOidIndexScan},
+ {TypeRelationName, /* TYPNAME */
+ 1,
+ {Anum_pg_type_typname,
+ 0,
+ 0,
+ 0},
+ offsetof(TypeTupleFormData, typalign) + sizeof(char),
+ TypeNameIndex,
+ TypeNameIndexScan},
+ {TypeRelationName, /* TYPOID */
+ 1,
+ {ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0},
+ offsetof(TypeTupleFormData, typalign) +sizeof(char),
+ TypeOidIndex,
+ TypeOidIndexScan},
+ {AccessMethodRelationName, /* AMNAME */
+ 1,
+ {Anum_pg_am_amname,
+ 0,
+ 0,
+ 0},
+ sizeof(FormData_pg_am),
+ NULL,
+ NULL},
+ {OperatorClassRelationName, /* CLANAME */
+ 1,
+ {Anum_pg_opclass_opcname,
+ 0,
+ 0,
+ 0},
+ sizeof(FormData_pg_opclass),
+ NULL,
+ NULL},
+ {IndexRelationName, /* INDRELIDKEY */
+ 2,
+ {Anum_pg_index_indrelid,
+ Anum_pg_index_indkey,
+ 0,
+ 0},
+ offsetof(FormData_pg_index, indpred),
+ NULL,
+ (ScanFunc) NULL},
+ {InheritsRelationName, /* INHRELID */
+ 2,
+ {Anum_pg_inherits_inhrel,
+ Anum_pg_inherits_inhseqno,
+ 0,
0},
- offsetof(TypeTupleFormData,typalign)+sizeof(char),
- TypeOidIndex,
- TypeOidIndexScan },
- { AccessMethodRelationName, /* AMNAME */
- 1,
- { Anum_pg_am_amname,
- 0,
- 0,
+ sizeof(FormData_pg_inherits),
+ NULL,
+ (ScanFunc) NULL},
+ {RewriteRelationName, /* RULOID */
+ 1,
+ {ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0},
+ offsetof(FormData_pg_rewrite, ev_qual),
+ NULL,
+ (ScanFunc) NULL},
+ {AggregateRelationName, /* AGGNAME */
+ 2,
+ {Anum_pg_aggregate_aggname,
+ Anum_pg_aggregate_aggbasetype,
+ 0,
0},
- sizeof(FormData_pg_am),
- NULL,
- NULL },
- { OperatorClassRelationName, /* CLANAME */
- 1,
- { Anum_pg_opclass_opcname,
- 0,
- 0,
+ offsetof(FormData_pg_aggregate, agginitval1),
+ NULL,
+ (ScanFunc) NULL},
+ {ListenerRelationName, /* LISTENREL */
+ 2,
+ {Anum_pg_listener_relname,
+ Anum_pg_listener_pid,
+ 0,
0},
- sizeof(FormData_pg_opclass),
- NULL,
- NULL },
- { IndexRelationName, /* INDRELIDKEY */
- 2,
- { Anum_pg_index_indrelid,
- Anum_pg_index_indkey,
- 0,
+ sizeof(FormData_pg_listener),
+ NULL,
+ (ScanFunc) NULL},
+ {UserRelationName, /* USENAME */
+ 1,
+ {Anum_pg_user_usename,
+ 0,
+ 0,
0},
- offsetof(FormData_pg_index, indpred),
- NULL,
- (ScanFunc) NULL },
- { InheritsRelationName, /* INHRELID */
- 2,
- { Anum_pg_inherits_inhrel,
- Anum_pg_inherits_inhseqno,
- 0,
+ sizeof(FormData_pg_user),
+ NULL,
+ (ScanFunc) NULL},
+ {UserRelationName, /* USESYSID */
+ 1,
+ {Anum_pg_user_usesysid,
+ 0,
+ 0,
+ 0},
+ sizeof(FormData_pg_user),
+ NULL,
+ (ScanFunc) NULL},
+ {GroupRelationName, /* GRONAME */
+ 1,
+ {Anum_pg_group_groname,
+ 0,
+ 0,
+ 0},
+ offsetof(FormData_pg_group, grolist[0]),
+ NULL,
+ (ScanFunc) NULL},
+ {GroupRelationName, /* GROSYSID */
+ 1,
+ {Anum_pg_group_grosysid,
+ 0,
+ 0,
0},
- sizeof(FormData_pg_inherits),
- NULL,
- (ScanFunc) NULL },
- { RewriteRelationName, /* RULOID */
- 1,
- { ObjectIdAttributeNumber,
- 0,
- 0,
- 0 },
- offsetof(FormData_pg_rewrite, ev_qual),
- NULL,
- (ScanFunc) NULL },
- { AggregateRelationName, /*AGGNAME*/
- 2,
- { Anum_pg_aggregate_aggname,
- Anum_pg_aggregate_aggbasetype,
- 0,
- 0 },
- offsetof(FormData_pg_aggregate, agginitval1),
- NULL,
- (ScanFunc) NULL },
- { ListenerRelationName, /* LISTENREL */
- 2,
- { Anum_pg_listener_relname,
- Anum_pg_listener_pid,
- 0,
- 0 },
- sizeof(FormData_pg_listener),
- NULL,
- (ScanFunc) NULL },
- { UserRelationName, /* USENAME */
- 1,
- { Anum_pg_user_usename,
- 0,
- 0,
- 0 },
- sizeof(FormData_pg_user),
- NULL,
- (ScanFunc) NULL },
- { UserRelationName, /* USESYSID */
- 1,
- { Anum_pg_user_usesysid,
- 0,
- 0,
- 0 },
- sizeof(FormData_pg_user),
- NULL,
- (ScanFunc) NULL },
- { GroupRelationName, /* GRONAME */
- 1,
- { Anum_pg_group_groname,
- 0,
- 0,
- 0 },
- offsetof(FormData_pg_group, grolist[0]),
- NULL,
- (ScanFunc) NULL },
- { GroupRelationName, /* GROSYSID */
- 1,
- { Anum_pg_group_grosysid,
- 0,
- 0,
- 0 },
- offsetof(FormData_pg_group, grolist[0]),
- NULL,
- (ScanFunc) NULL },
- { RewriteRelationName, /* REWRITENAME */
- 1,
- { Anum_pg_rewrite_rulename,
- 0,
- 0,
- 0 },
- offsetof(FormData_pg_rewrite, ev_qual),
- NULL,
- (ScanFunc) NULL },
- { ProcedureRelationName, /* PROSRC */
- 1,
- { Anum_pg_proc_prosrc,
- 0,
- 0,
- 0 },
- offsetof(FormData_pg_proc, prosrc),
- ProcedureSrcIndex,
- (ScanFunc) ProcedureSrcIndexScan },
- { OperatorClassRelationName, /* CLADEFTYPE */
- 1,
- { Anum_pg_opclass_opcdeftype,
- 0,
- 0,
- 0 },
- sizeof(FormData_pg_opclass),
- NULL,
- (ScanFunc) NULL }
+ offsetof(FormData_pg_group, grolist[0]),
+ NULL,
+ (ScanFunc) NULL},
+ {RewriteRelationName, /* REWRITENAME */
+ 1,
+ {Anum_pg_rewrite_rulename,
+ 0,
+ 0,
+ 0},
+ offsetof(FormData_pg_rewrite, ev_qual),
+ NULL,
+ (ScanFunc) NULL},
+ {ProcedureRelationName, /* PROSRC */
+ 1,
+ {Anum_pg_proc_prosrc,
+ 0,
+ 0,
+ 0},
+ offsetof(FormData_pg_proc, prosrc),
+ ProcedureSrcIndex,
+ (ScanFunc) ProcedureSrcIndexScan},
+ {OperatorClassRelationName, /* CLADEFTYPE */
+ 1,
+ {Anum_pg_opclass_opcdeftype,
+ 0,
+ 0,
+ 0},
+ sizeof(FormData_pg_opclass),
+ NULL,
+ (ScanFunc) NULL}
};
-
-static struct catcache *SysCache[lengthof(cacheinfo)];
-static int32 SysCacheSize = lengthof(cacheinfo);
-
-
+
+static struct catcache *SysCache[
+ lengthof(cacheinfo)];
+static int32 SysCacheSize = lengthof(cacheinfo);
+
+
/*
* zerocaches--
*
- * Make sure the SysCache structure is zero'd.
+ * Make sure the SysCache structure is zero'd.
*/
void
zerocaches()
{
- memset((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
+ memset((char *) SysCache, 0, SysCacheSize * sizeof(struct catcache *));
}
/*
* Note:
- * This function was written because the initialized catalog caches
- * are used to determine which caches may contain tuples which need
- * to be invalidated in other backends.
+ * This function was written because the initialized catalog caches
+ * are used to determine which caches may contain tuples which need
+ * to be invalidated in other backends.
*/
void
InitCatalogCache()
{
- int cacheId; /* XXX type */
-
- if (!AMI_OVERRIDE) {
- for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1) {
-
- Assert(!PointerIsValid((Pointer)SysCache[cacheId]));
-
- SysCache[cacheId] =
- InitSysCache(cacheinfo[cacheId].name,
- cacheinfo[cacheId].indname,
- cacheId,
- cacheinfo[cacheId].nkeys,
- cacheinfo[cacheId].key,
- cacheinfo[cacheId].iScanFunc);
- if (!PointerIsValid((char *)SysCache[cacheId])) {
- elog(WARN,
- "InitCatalogCache: Can't init cache %.16s(%d)",
- cacheinfo[cacheId].name,
- cacheId);
- }
-
+ int cacheId; /* XXX type */
+
+ if (!AMI_OVERRIDE)
+ {
+ for (cacheId = 0; cacheId < SysCacheSize; cacheId += 1)
+ {
+
+ Assert(!PointerIsValid((Pointer) SysCache[cacheId]));
+
+ SysCache[cacheId] =
+ InitSysCache(cacheinfo[cacheId].name,
+ cacheinfo[cacheId].indname,
+ cacheId,
+ cacheinfo[cacheId].nkeys,
+ cacheinfo[cacheId].key,
+ cacheinfo[cacheId].iScanFunc);
+ if (!PointerIsValid((char *) SysCache[cacheId]))
+ {
+ elog(WARN,
+ "InitCatalogCache: Can't init cache %.16s(%d)",
+ cacheinfo[cacheId].name,
+ cacheId);
+ }
+
+ }
}
- }
}
/*
* SearchSysCacheTuple--
*
- * A layer on top of SearchSysCache that does the initialization and
- * key-setting for you.
+ * A layer on top of SearchSysCache that does the initialization and
+ * key-setting for you.
*
* Returns the tuple if one is found, NULL if not.
*
* XXX The tuple that is returned is NOT supposed to be pfree'd!
*/
HeapTuple
-SearchSysCacheTuple(int cacheId, /* cache selection code */
- Datum key1,
- Datum key2,
- Datum key3,
- Datum key4)
+SearchSysCacheTuple(int cacheId, /* cache selection code */
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
{
- register HeapTuple tp;
-
- if (cacheId < 0 || cacheId >= SysCacheSize) {
- elog(WARN, "SearchSysCacheTuple: Bad cache id %d", cacheId);
- return((HeapTuple) NULL);
- }
-
- if (!AMI_OVERRIDE) {
- Assert(PointerIsValid(SysCache[cacheId]));
- } else {
- if (!PointerIsValid(SysCache[cacheId])) {
- SysCache[cacheId] =
- InitSysCache(cacheinfo[cacheId].name,
- cacheinfo[cacheId].indname,
- cacheId,
- cacheinfo[cacheId].nkeys,
- cacheinfo[cacheId].key,
- cacheinfo[cacheId].iScanFunc);
- if (!PointerIsValid(SysCache[cacheId])) {
- elog(WARN,
- "InitCatalogCache: Can't init cache %.16s(%d)",
- cacheinfo[cacheId].name,
- cacheId);
- }
-
+ register HeapTuple tp;
+
+ if (cacheId < 0 || cacheId >= SysCacheSize)
+ {
+ elog(WARN, "SearchSysCacheTuple: Bad cache id %d", cacheId);
+ return ((HeapTuple) NULL);
+ }
+
+ if (!AMI_OVERRIDE)
+ {
+ Assert(PointerIsValid(SysCache[cacheId]));
+ }
+ else
+ {
+ if (!PointerIsValid(SysCache[cacheId]))
+ {
+ SysCache[cacheId] =
+ InitSysCache(cacheinfo[cacheId].name,
+ cacheinfo[cacheId].indname,
+ cacheId,
+ cacheinfo[cacheId].nkeys,
+ cacheinfo[cacheId].key,
+ cacheinfo[cacheId].iScanFunc);
+ if (!PointerIsValid(SysCache[cacheId]))
+ {
+ elog(WARN,
+ "InitCatalogCache: Can't init cache %.16s(%d)",
+ cacheinfo[cacheId].name,
+ cacheId);
+ }
+
+ }
}
- }
-
- tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
- if (!HeapTupleIsValid(tp)) {
+
+ tp = SearchSysCache(SysCache[cacheId], key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tp))
+ {
#ifdef CACHEDEBUG
- elog(DEBUG,
- "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
- (*cacheinfo[cacheId].name)->data,
- cacheId, key1, key2, key3, key4);
+ elog(DEBUG,
+ "SearchSysCacheTuple: Search %s(%d) %d %d %d %d failed",
+ (*cacheinfo[cacheId].name)->data,
+ cacheId, key1, key2, key3, key4);
#endif
- return((HeapTuple) NULL);
- }
- return(tp);
+ return ((HeapTuple) NULL);
+ }
+ return (tp);
}
/*
* SearchSysCacheStruct--
- * Fills 's' with the information retrieved by calling SearchSysCache()
- * with arguments key1...key4. Retrieves only the portion of the tuple
- * which is not variable-length.
+ * Fills 's' with the information retrieved by calling SearchSysCache()
+ * with arguments key1...key4. Retrieves only the portion of the tuple
+ * which is not variable-length.
*
* NOTE: we are assuming that non-variable-length fields in the system
- * catalogs will always be defined!
+ * catalogs will always be defined!
*
* Returns 1L if a tuple was found, 0L if not.
*/
int32
SearchSysCacheStruct(int cacheId, /* cache selection code */
- char *returnStruct, /* (preallocated!) */
- Datum key1,
- Datum key2,
- Datum key3,
- Datum key4)
+ char *returnStruct, /* (preallocated!) */
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
{
- HeapTuple tp;
-
- if (!PointerIsValid(returnStruct)) {
- elog(WARN, "SearchSysCacheStruct: No receiving struct");
- return(0);
- }
- tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
- if (!HeapTupleIsValid(tp))
- return(0);
- memmove(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
- return(1);
+ HeapTuple tp;
+
+ if (!PointerIsValid(returnStruct))
+ {
+ elog(WARN, "SearchSysCacheStruct: No receiving struct");
+ return (0);
+ }
+ tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
+ if (!HeapTupleIsValid(tp))
+ return (0);
+ memmove(returnStruct, (char *) GETSTRUCT(tp), cacheinfo[cacheId].size);
+ return (1);
}
/*
* SearchSysCacheGetAttribute--
- * Returns the attribute corresponding to 'attributeNumber' for
- * a given cached tuple.
+ * Returns the attribute corresponding to 'attributeNumber' for
+ * a given cached tuple.
*
* XXX This re-opens a relation, so this is slower.
*
* [callers all assume this returns a (struct varlena *). -ay 10/94]
*/
-void *
+void *
SearchSysCacheGetAttribute(int cacheId,
- AttrNumber attributeNumber,
- Datum key1,
- Datum key2,
- Datum key3,
- Datum key4)
+ AttrNumber attributeNumber,
+ Datum key1,
+ Datum key2,
+ Datum key3,
+ Datum key4)
{
- HeapTuple tp;
- char *cacheName;
- Relation relation;
- int32 attributeLength, attributeByValue;
- bool isNull;
- char *attributeValue;
- void *returnValue;
-
- tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
- cacheName = cacheinfo[cacheId].name;
-
- if (!HeapTupleIsValid(tp)) {
+ HeapTuple tp;
+ char *cacheName;
+ Relation relation;
+ int32 attributeLength,
+ attributeByValue;
+ bool isNull;
+ char *attributeValue;
+ void *returnValue;
+
+ tp = SearchSysCacheTuple(cacheId, key1, key2, key3, key4);
+ cacheName = cacheinfo[cacheId].name;
+
+ if (!HeapTupleIsValid(tp))
+ {
#ifdef CACHEDEBUG
- elog(DEBUG,
- "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
- cacheName, cacheId);
-#endif /* defined(CACHEDEBUG) */
- return(NULL);
- }
-
- relation = heap_openr(cacheName);
-
- if (attributeNumber < 0 &&
- attributeNumber > FirstLowInvalidHeapAttributeNumber) {
- attributeLength = heap_sysattrlen(attributeNumber);
- attributeByValue = heap_sysattrbyval(attributeNumber);
- } else if (attributeNumber > 0 &&
- attributeNumber <= relation->rd_rel->relnatts) {
- attributeLength =
- relation->rd_att->attrs[attributeNumber-1]->attlen;
- attributeByValue =
- relation->rd_att->attrs[attributeNumber-1]->attbyval;
- } else {
- elog(WARN,
- "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
- attributeNumber, cacheName, cacheId);
- return(NULL);
- }
-
- attributeValue = heap_getattr(tp,
- (Buffer) 0,
- attributeNumber,
- RelationGetTupleDescriptor(relation),
- &isNull);
-
- if (isNull) {
- /*
- * Used to be an elog(DEBUG, ...) here and a claim that it should
- * be a FATAL error, I don't think either is warranted -mer 6/9/92
- */
- return(NULL);
- }
-
- if (attributeByValue) {
- returnValue = (void *)attributeValue;
- } else {
- char *tmp;
- int size = (attributeLength < 0)
- ? VARSIZE((struct varlena *) attributeValue) /* variable length */
- : attributeLength; /* fixed length */
-
- tmp = (char *) palloc(size);
- memmove(tmp, attributeValue, size);
- returnValue = (void *)tmp;
- }
-
- heap_close(relation);
- return(returnValue);
+ elog(DEBUG,
+ "SearchSysCacheGetAttribute: Lookup in %s(%d) failed",
+ cacheName, cacheId);
+#endif /* defined(CACHEDEBUG) */
+ return (NULL);
+ }
+
+ relation = heap_openr(cacheName);
+
+ if (attributeNumber < 0 &&
+ attributeNumber > FirstLowInvalidHeapAttributeNumber)
+ {
+ attributeLength = heap_sysattrlen(attributeNumber);
+ attributeByValue = heap_sysattrbyval(attributeNumber);
+ }
+ else if (attributeNumber > 0 &&
+ attributeNumber <= relation->rd_rel->relnatts)
+ {
+ attributeLength =
+ relation->rd_att->attrs[attributeNumber - 1]->attlen;
+ attributeByValue =
+ relation->rd_att->attrs[attributeNumber - 1]->attbyval;
+ }
+ else
+ {
+ elog(WARN,
+ "SearchSysCacheGetAttribute: Bad attr # %d in %s(%d)",
+ attributeNumber, cacheName, cacheId);
+ return (NULL);
+ }
+
+ attributeValue = heap_getattr(tp,
+ (Buffer) 0,
+ attributeNumber,
+ RelationGetTupleDescriptor(relation),
+ &isNull);
+
+ if (isNull)
+ {
+
+ /*
+ * Used to be an elog(DEBUG, ...) here and a claim that it should
+ * be a FATAL error, I don't think either is warranted -mer 6/9/92
+ */
+ return (NULL);
+ }
+
+ if (attributeByValue)
+ {
+ returnValue = (void *) attributeValue;
+ }
+ else
+ {
+ char *tmp;
+ int size = (attributeLength < 0)
+ ? VARSIZE((struct varlena *) attributeValue) /* variable length */
+ : attributeLength; /* fixed length */
+
+ tmp = (char *) palloc(size);
+ memmove(tmp, attributeValue, size);
+ returnValue = (void *) tmp;
+ }
+
+ heap_close(relation);
+ return (returnValue);
}
/*
* TypeDefaultRetrieve--
*
- * Given a type OID, return the typdefault field associated with that
- * type. The typdefault is returned as the car of a dotted pair which
- * is passed to TypeDefaultRetrieve by the calling routine.
+ * Given a type OID, return the typdefault field associated with that
+ * type. The typdefault is returned as the car of a dotted pair which
+ * is passed to TypeDefaultRetrieve by the calling routine.
*
* Returns a fixnum for types which are passed by value and a ppreserve'd
* vectori for types which are not.
*
* [identical to get_typdefault, expecting a (struct varlena *) as ret val.
- * some day, either of the functions should be removed -ay 10/94]
+ * some day, either of the functions should be removed -ay 10/94]
*/
-void *
+void *
TypeDefaultRetrieve(Oid typId)
{
- HeapTuple typeTuple;
- TypeTupleForm type;
- int32 typByVal, typLen;
- struct varlena *typDefault;
- int32 dataSize;
- void *returnValue;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(typId),
- 0,0,0);
-
- if (!HeapTupleIsValid(typeTuple)) {
-#ifdef CACHEDEBUG
- elog(DEBUG, "TypeDefaultRetrieve: Lookup in %s(%d) failed",
- (*cacheinfo[TYPOID].name)->data, TYPOID);
-#endif /* defined(CACHEDEBUG) */
- return(NULL);
- }
-
- type = (TypeTupleForm) GETSTRUCT(typeTuple);
- typByVal = type->typbyval;
- typLen = type->typlen;
-
- typDefault = (struct varlena *)
- SearchSysCacheGetAttribute(TYPOID,
- Anum_pg_type_typdefault,
- ObjectIdGetDatum(typId),
- 0,0,0);
-
- if (typDefault == (struct varlena *)NULL) {
+ HeapTuple typeTuple;
+ TypeTupleForm type;
+ int32 typByVal,
+ typLen;
+ struct varlena *typDefault;
+ int32 dataSize;
+ void *returnValue;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(typId),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(typeTuple))
+ {
#ifdef CACHEDEBUG
- elog(DEBUG, "TypeDefaultRetrieve: No extractable typdefault",
- (*cacheinfo[TYPOID].name)->data, TYPOID);
-#endif /* defined(CACHEDEBUG) */
- return (NULL);
-
- }
-
- dataSize = VARSIZE(typDefault) - VARHDRSZ;
-
- if (typByVal) {
- int8 i8;
- int16 i16;
- int32 i32;
-
- if (dataSize == typLen) {
- switch (typLen) {
- case sizeof(int8):
- memmove((char *) &i8, VARDATA(typDefault), sizeof(int8));
- i32 = i8;
- break;
- case sizeof(int16):
- memmove((char *) &i16, VARDATA(typDefault), sizeof(int16));
- i32 = i16;
- break;
- case sizeof(int32):
- memmove((char *) &i32, VARDATA(typDefault), sizeof(int32));
- break;
- }
- returnValue = (void *)i32;
- } else {
- returnValue = NULL;
+ elog(DEBUG, "TypeDefaultRetrieve: Lookup in %s(%d) failed",
+ (*cacheinfo[TYPOID].name)->data, TYPOID);
+#endif /* defined(CACHEDEBUG) */
+ return (NULL);
}
- } else {
- if ((typLen < 0 && dataSize < 0) || dataSize != typLen)
- returnValue = NULL;
- else {
- returnValue = (void *)palloc(VARSIZE(typDefault));
- memmove((char *) returnValue,
- (char *) typDefault,
- (int) VARSIZE(typDefault));
+
+ type = (TypeTupleForm) GETSTRUCT(typeTuple);
+ typByVal = type->typbyval;
+ typLen = type->typlen;
+
+ typDefault = (struct varlena *)
+ SearchSysCacheGetAttribute(TYPOID,
+ Anum_pg_type_typdefault,
+ ObjectIdGetDatum(typId),
+ 0, 0, 0);
+
+ if (typDefault == (struct varlena *) NULL)
+ {
+#ifdef CACHEDEBUG
+ elog(DEBUG, "TypeDefaultRetrieve: No extractable typdefault",
+ (*cacheinfo[TYPOID].name)->data, TYPOID);
+#endif /* defined(CACHEDEBUG) */
+ return (NULL);
+
}
- }
-
- return(returnValue);
-}
+ dataSize = VARSIZE(typDefault) - VARHDRSZ;
+ if (typByVal)
+ {
+ int8 i8;
+ int16 i16;
+ int32 i32;
+
+ if (dataSize == typLen)
+ {
+ switch (typLen)
+ {
+ case sizeof(int8):
+ memmove((char *) &i8, VARDATA(typDefault), sizeof(int8));
+ i32 = i8;
+ break;
+ case sizeof(int16):
+ memmove((char *) &i16, VARDATA(typDefault), sizeof(int16));
+ i32 = i16;
+ break;
+ case sizeof(int32):
+ memmove((char *) &i32, VARDATA(typDefault), sizeof(int32));
+ break;
+ }
+ returnValue = (void *) i32;
+ }
+ else
+ {
+ returnValue = NULL;
+ }
+ }
+ else
+ {
+ if ((typLen < 0 && dataSize < 0) || dataSize != typLen)
+ returnValue = NULL;
+ else
+ {
+ returnValue = (void *) palloc(VARSIZE(typDefault));
+ memmove((char *) returnValue,
+ (char *) typDefault,
+ (int) VARSIZE(typDefault));
+ }
+ }
+
+ return (returnValue);
+}
diff --git a/src/backend/utils/error/assert.c b/src/backend/utils/error/assert.c
index 4fb99ced1b9..2c46dde02b8 100644
--- a/src/backend/utils/error/assert.c
+++ b/src/backend/utils/error/assert.c
@@ -1,67 +1,71 @@
/*-------------------------------------------------------------------------
*
* assert.c--
- * Assert code.
+ * Assert code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/assert.c,v 1.4 1997/04/17 20:38:26 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/assert.c,v 1.5 1997/09/07 04:53:11 momjian Exp $
*
* NOTE
- * This should eventually work with elog(), dlog(), etc.
+ * This should eventually work with elog(), dlog(), etc.
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
-#include "postgres.h" /* where the declaration goes */
+#include "postgres.h" /* where the declaration goes */
#include "utils/module.h"
#include "utils/exc.h"
int
-ExceptionalCondition(char* conditionName,
- Exception *exceptionP,
- char* detail,
- char* fileName,
- int lineNumber)
+ExceptionalCondition(char *conditionName,
+ Exception * exceptionP,
+ char *detail,
+ char *fileName,
+ int lineNumber)
{
- extern char* ExcFileName; /* XXX */
- extern Index ExcLineNumber; /* XXX */
-
- ExcFileName = fileName;
- ExcLineNumber = lineNumber;
-
- if (!PointerIsValid(conditionName)
- || !PointerIsValid(fileName)
- || !PointerIsValid(exceptionP)) {
- fprintf(stderr, "ExceptionalCondition: bad arguments\n");
-
- ExcAbort(exceptionP,
- (ExcDetail)detail,
- (ExcData)NULL,
- (ExcMessage)NULL);
- } else {
- fprintf(stderr,
- "%s(\"%s:%s\", File: \"%s\", Line: %d)\n",
+ extern char *ExcFileName;/* XXX */
+ extern Index ExcLineNumber; /* XXX */
+
+ ExcFileName = fileName;
+ ExcLineNumber = lineNumber;
+
+ if (!PointerIsValid(conditionName)
+ || !PointerIsValid(fileName)
+ || !PointerIsValid(exceptionP))
+ {
+ fprintf(stderr, "ExceptionalCondition: bad arguments\n");
+
+ ExcAbort(exceptionP,
+ (ExcDetail) detail,
+ (ExcData) NULL,
+ (ExcMessage) NULL);
+ }
+ else
+ {
+ fprintf(stderr,
+ "%s(\"%s:%s\", File: \"%s\", Line: %d)\n",
exceptionP->message, conditionName, detail == NULL ? "" : detail,
- fileName, lineNumber);
- }
+ fileName, lineNumber);
+ }
#ifdef ABORT_ON_ASSERT
- abort();
+ abort();
#endif
- /*
- * XXX Depending on the Exception and tracing conditions, you will
- * XXX want to stop here immediately and maybe dump core.
- * XXX This may be especially true for Assert(), etc.
- */
-
- /* TraceDump(); dump the trace stack */
-
- /* XXX FIXME: detail is lost */
- ExcRaise(exceptionP, (ExcDetail)0, (ExcData)NULL, conditionName);
- return(0);
+
+ /*
+ * XXX Depending on the Exception and tracing conditions, you will XXX
+ * want to stop here immediately and maybe dump core. XXX This may be
+ * especially true for Assert(), etc.
+ */
+
+ /* TraceDump(); dump the trace stack */
+
+ /* XXX FIXME: detail is lost */
+ ExcRaise(exceptionP, (ExcDetail) 0, (ExcData) NULL, conditionName);
+ return (0);
}
diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c
index fae4c1adeef..e4cdc6d595b 100644
--- a/src/backend/utils/error/elog.c
+++ b/src/backend/utils/error/elog.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* elog.c--
- * error logger
+ * error logger
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.17 1997/08/12 22:54:44 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/elog.c,v 1.18 1997/09/07 04:53:15 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,7 @@
#include <fcntl.h>
#ifndef O_RDONLY
#include <sys/file.h>
-#endif /* O_RDONLY */
+#endif /* O_RDONLY */
#include <sys/types.h>
#include <stdarg.h>
#include <errno.h>
@@ -29,204 +29,236 @@
#include "libpq/libpq.h"
#include "storage/proc.h"
-static int Debugfile = -1;
-static int Err_file = -1;
-static int ElogDebugIndentLevel = 0;
+static int Debugfile = -1;
+static int Err_file = -1;
+static int ElogDebugIndentLevel = 0;
-extern char OutputFileName[];
+extern char OutputFileName[];
/*
* elog --
- * Old error logging function.
+ * Old error logging function.
*/
void
-elog(int lev, const char *fmt, ... )
+elog(int lev, const char *fmt,...)
{
- va_list ap;
- char buf[ELOG_MAXLEN], line[ELOG_MAXLEN];
- register char *bp;
- register const char *cp;
- extern int errno, sys_nerr;
+ va_list ap;
+ char buf[ELOG_MAXLEN],
+ line[ELOG_MAXLEN];
+ register char *bp;
+ register const char *cp;
+ extern int errno,
+ sys_nerr;
+
#ifndef PG_STANDALONE
- extern FILE *Pfout;
-#endif /* !PG_STANDALONE */
+ extern FILE *Pfout;
+
+#endif /* !PG_STANDALONE */
#ifdef ELOG_TIMESTAMPS
- time_t tim;
+ time_t tim;
+
#endif
- int len;
- int i = 0;
-
- va_start(ap, fmt);
- if (lev == DEBUG && Debugfile < 0) {
- return;
- }
- switch (lev) {
- case NOIND:
- i = ElogDebugIndentLevel-1;
- if (i < 0) i = 0;
- if (i > 30) i = i%30;
- cp = "DEBUG:";
- break;
- case DEBUG:
- i = ElogDebugIndentLevel;
- if (i < 0) i = 0;
- if (i > 30) i = i%30;
- cp = "DEBUG:";
- break;
- case NOTICE:
- cp = "NOTICE:";
- break;
- case WARN:
- cp = "WARN:";
- break;
- default:
- sprintf(line, "FATAL %d:", lev);
- cp = line;
- }
+ int len;
+ int i = 0;
+
+ va_start(ap, fmt);
+ if (lev == DEBUG && Debugfile < 0)
+ {
+ return;
+ }
+ switch (lev)
+ {
+ case NOIND:
+ i = ElogDebugIndentLevel - 1;
+ if (i < 0)
+ i = 0;
+ if (i > 30)
+ i = i % 30;
+ cp = "DEBUG:";
+ break;
+ case DEBUG:
+ i = ElogDebugIndentLevel;
+ if (i < 0)
+ i = 0;
+ if (i > 30)
+ i = i % 30;
+ cp = "DEBUG:";
+ break;
+ case NOTICE:
+ cp = "NOTICE:";
+ break;
+ case WARN:
+ cp = "WARN:";
+ break;
+ default:
+ sprintf(line, "FATAL %d:", lev);
+ cp = line;
+ }
#ifdef ELOG_TIMESTAMPS
- time(&tim);
- strcat(strcpy(buf, cp), ctime(&tim)+4);
- bp = buf+strlen(buf)-6;
- *bp++ = ':';
+ time(&tim);
+ strcat(strcpy(buf, cp), ctime(&tim) + 4);
+ bp = buf + strlen(buf) - 6;
+ *bp++ = ':';
#else
- strcpy(buf,cp);
- bp = buf+strlen(buf);
+ strcpy(buf, cp);
+ bp = buf + strlen(buf);
#endif
- while (i-- >0) *bp++ = ' ';
- for (cp = fmt; *cp; cp++)
- if (*cp == '%' && *(cp+1) == 'm') {
- if (errno < sys_nerr && errno >= 0)
- strcpy(bp, strerror(errno));
- else
- sprintf(bp, "error %d", errno);
- bp += strlen(bp);
- cp++;
- } else
- *bp++ = *cp;
- *bp = '\0';
- vsprintf(line, buf, ap);
- va_end(ap);
- len = strlen(strcat(line, "\n"));
- if (Debugfile > -1)
- write(Debugfile, line, len);
- if (lev == DEBUG || lev == NOIND)
- return;
-
- /*
- * If there's an error log file other than our channel to the
- * front-end program, write to it first. This is important
- * because there's a bug in the socket code on ultrix. If the
- * front end has gone away (so the channel to it has been closed
- * at the other end), then writing here can cause this backend
- * to exit without warning -- that is, write() does an exit().
- * In this case, our only hope of finding out what's going on
- * is if Err_file was set to some disk log. This is a major pain.
- */
-
- if (Err_file > -1 && Debugfile != Err_file) {
- if (write(Err_file, line, len) < 0) {
- write(open("/dev/console", O_WRONLY, 0666), line, len);
- fflush(stdout);
- fflush(stderr);
- exitpg(lev);
- }
- fsync(Err_file);
- }
-
-#ifndef PG_STANDALONE
- /* Send IPC message to the front-end program */
- if (Pfout != NULL && lev > DEBUG) {
- /* notices are not exactly errors, handle it differently */
- if (lev == NOTICE)
- pq_putnchar("N", 1);
- else
- pq_putnchar("E", 1);
- /* pq_putint(-101, 4);*/ /* should be query id */
- pq_putstr(line);
- pq_flush();
- }
-#endif /* !PG_STANDALONE */
-
- if (lev == WARN) {
- extern int InWarn;
- ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
- if (!InWarn) {
- kill(getpid(), 1); /* abort to traffic cop */
- pause();
- }
- /*
- * The pause(3) is just to avoid race conditions where the
- * thread of control on an MP system gets past here (i.e.,
- * the signal is not received instantaneously).
- */
- }
-
- if (lev == FATAL) {
+ while (i-- > 0)
+ *bp++ = ' ';
+ for (cp = fmt; *cp; cp++)
+ if (*cp == '%' && *(cp + 1) == 'm')
+ {
+ if (errno < sys_nerr && errno >= 0)
+ strcpy(bp, strerror(errno));
+ else
+ sprintf(bp, "error %d", errno);
+ bp += strlen(bp);
+ cp++;
+ }
+ else
+ *bp++ = *cp;
+ *bp = '\0';
+ vsprintf(line, buf, ap);
+ va_end(ap);
+ len = strlen(strcat(line, "\n"));
+ if (Debugfile > -1)
+ write(Debugfile, line, len);
+ if (lev == DEBUG || lev == NOIND)
+ return;
+
/*
- * Assume that if we have detected the failure we can
- * exit with a normal exit status. This will prevent
- * the postmaster from cleaning up when it's not needed.
+ * If there's an error log file other than our channel to the
+ * front-end program, write to it first. This is important because
+ * there's a bug in the socket code on ultrix. If the front end has
+ * gone away (so the channel to it has been closed at the other end),
+ * then writing here can cause this backend to exit without warning --
+ * that is, write() does an exit(). In this case, our only hope of
+ * finding out what's going on is if Err_file was set to some disk
+ * log. This is a major pain.
*/
- fflush(stdout);
- fflush(stderr);
- ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
- ProcReleaseLocks(); /* get rid of real locks we hold */
- exitpg(0);
- }
-
- if (lev > FATAL) {
- fflush(stdout);
- fflush(stderr);
- exitpg(lev);
- }
+
+ if (Err_file > -1 && Debugfile != Err_file)
+ {
+ if (write(Err_file, line, len) < 0)
+ {
+ write(open("/dev/console", O_WRONLY, 0666), line, len);
+ fflush(stdout);
+ fflush(stderr);
+ exitpg(lev);
+ }
+ fsync(Err_file);
+ }
+
+#ifndef PG_STANDALONE
+ /* Send IPC message to the front-end program */
+ if (Pfout != NULL && lev > DEBUG)
+ {
+ /* notices are not exactly errors, handle it differently */
+ if (lev == NOTICE)
+ pq_putnchar("N", 1);
+ else
+ pq_putnchar("E", 1);
+ /* pq_putint(-101, 4); *//* should be query id */
+ pq_putstr(line);
+ pq_flush();
+ }
+#endif /* !PG_STANDALONE */
+
+ if (lev == WARN)
+ {
+ extern int InWarn;
+
+ ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
+ if (!InWarn)
+ {
+ kill(getpid(), 1); /* abort to traffic cop */
+ pause();
+ }
+
+ /*
+ * The pause(3) is just to avoid race conditions where the thread
+ * of control on an MP system gets past here (i.e., the signal is
+ * not received instantaneously).
+ */
+ }
+
+ if (lev == FATAL)
+ {
+
+ /*
+ * Assume that if we have detected the failure we can exit with a
+ * normal exit status. This will prevent the postmaster from
+ * cleaning up when it's not needed.
+ */
+ fflush(stdout);
+ fflush(stderr);
+ ProcReleaseSpins(NULL); /* get rid of spinlocks we hold */
+ ProcReleaseLocks(); /* get rid of real locks we hold */
+ exitpg(0);
+ }
+
+ if (lev > FATAL)
+ {
+ fflush(stdout);
+ fflush(stderr);
+ exitpg(lev);
+ }
}
#ifndef PG_STANDALONE
int
DebugFileOpen(void)
{
- int fd, istty;
-
- Err_file = Debugfile = -1;
- ElogDebugIndentLevel = 0;
-
- if (OutputFileName[0]) {
- OutputFileName[MAXPGPATH-1] = '\0';
- if ((fd = open(OutputFileName, O_CREAT|O_APPEND|O_WRONLY,
- 0666)) < 0)
- elog(FATAL, "DebugFileOpen: open of %s: %m",
- OutputFileName);
- istty = isatty(fd);
- close(fd);
- /* If the file is a tty and we're running under the
- * postmaster, try to send stdout there as well (if it
- * isn't a tty then stderr will block out stdout, so we
- * may as well let stdout go wherever it was going before).
+ int fd,
+ istty;
+
+ Err_file = Debugfile = -1;
+ ElogDebugIndentLevel = 0;
+
+ if (OutputFileName[0])
+ {
+ OutputFileName[MAXPGPATH - 1] = '\0';
+ if ((fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY,
+ 0666)) < 0)
+ elog(FATAL, "DebugFileOpen: open of %s: %m",
+ OutputFileName);
+ istty = isatty(fd);
+ close(fd);
+
+ /*
+ * If the file is a tty and we're running under the postmaster,
+ * try to send stdout there as well (if it isn't a tty then stderr
+ * will block out stdout, so we may as well let stdout go wherever
+ * it was going before).
+ */
+ if (istty &&
+ IsUnderPostmaster &&
+ !freopen(OutputFileName, "a", stdout))
+ elog(FATAL, "DebugFileOpen: %s reopen as stdout: %m",
+ OutputFileName);
+ if (!freopen(OutputFileName, "a", stderr))
+ elog(FATAL, "DebugFileOpen: %s reopen as stderr: %m",
+ OutputFileName);
+ Err_file = Debugfile = fileno(stderr);
+ return (Debugfile);
+ }
+
+ /*
+ * If no filename was specified, send debugging output to stderr. If
+ * stderr has been hosed, try to open a file.
*/
- if (istty &&
- IsUnderPostmaster &&
- !freopen(OutputFileName, "a", stdout))
- elog(FATAL, "DebugFileOpen: %s reopen as stdout: %m",
- OutputFileName);
- if (!freopen(OutputFileName, "a", stderr))
- elog(FATAL, "DebugFileOpen: %s reopen as stderr: %m",
- OutputFileName);
- Err_file = Debugfile = fileno(stderr);
- return(Debugfile);
- }
- /* If no filename was specified, send debugging output to stderr.
- * If stderr has been hosed, try to open a file.
- */
- fd = fileno(stderr);
- if (fcntl(fd, F_GETFD, 0) < 0) {
- sprintf(OutputFileName, "%s/pg.errors.%d",
- DataDir, (int)getpid());
- fd = open(OutputFileName, O_CREAT|O_APPEND|O_WRONLY, 0666);
- }
- if (fd < 0)
- elog(FATAL, "DebugFileOpen: could not open debugging file");
-
- Err_file = Debugfile = fd;
- return(Debugfile);
+ fd = fileno(stderr);
+ if (fcntl(fd, F_GETFD, 0) < 0)
+ {
+ sprintf(OutputFileName, "%s/pg.errors.%d",
+ DataDir, (int) getpid());
+ fd = open(OutputFileName, O_CREAT | O_APPEND | O_WRONLY, 0666);
+ }
+ if (fd < 0)
+ elog(FATAL, "DebugFileOpen: could not open debugging file");
+
+ Err_file = Debugfile = fd;
+ return (Debugfile);
}
+
#endif
diff --git a/src/backend/utils/error/exc.c b/src/backend/utils/error/exc.c
index 3366996fad1..fd169b94a18 100644
--- a/src/backend/utils/error/exc.c
+++ b/src/backend/utils/error/exc.c
@@ -1,21 +1,21 @@
/*-------------------------------------------------------------------------
*
* exc.c--
- * POSTGRES exception handling code.
+ * POSTGRES exception handling code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/Attic/exc.c,v 1.15 1997/08/19 21:35:17 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/Attic/exc.c,v 1.16 1997/09/07 04:53:16 momjian Exp $
*
* NOTE
- * XXX this code needs improvement--check for state violations and
- * XXX reset after handling an exception.
+ * XXX this code needs improvement--check for state violations and
+ * XXX reset after handling an exception.
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* XXX use own I/O routines */
+#include <stdio.h> /* XXX use own I/O routines */
#include <errno.h>
#include <string.h>
@@ -24,24 +24,26 @@
#include "utils/exc.h"
#include "storage/ipc.h"
-static void ExcUnCaught(Exception *excP, ExcDetail detail, ExcData data,
+static void
+ExcUnCaught(Exception * excP, ExcDetail detail, ExcData data,
ExcMessage message);
-static void ExcPrint(Exception *excP, ExcDetail detail, ExcData data,
- ExcMessage message);
+static void
+ExcPrint(Exception * excP, ExcDetail detail, ExcData data,
+ ExcMessage message);
/*
* Global Variables
*/
-static bool ExceptionHandlingEnabled = false;
+static bool ExceptionHandlingEnabled = false;
-char* ExcFileName = NULL;
+char *ExcFileName = NULL;
Index ExcLineNumber = 0;
-ExcFrame *ExcCurFrameP = NULL;
+ExcFrame *ExcCurFrameP = NULL;
-static ExcProc *ExcUnCaughtP = NULL;
+static ExcProc *ExcUnCaughtP = NULL;
-extern char* ProgramName;
+extern char *ProgramName;
/*
* Exported Functions
@@ -49,148 +51,157 @@ extern char* ProgramName;
/*
* EnableExceptionHandling --
- * Enables/disables the exception handling system.
+ * Enables/disables the exception handling system.
*
* Note:
- * This must be called before any exceptions occur. I.e., call this first!
- * This routine will not return if an error is detected.
- * This does not follow the usual Enable... protocol.
- * This should be merged more closely with the error logging and tracing
- * packages.
+ * This must be called before any exceptions occur. I.e., call this first!
+ * This routine will not return if an error is detected.
+ * This does not follow the usual Enable... protocol.
+ * This should be merged more closely with the error logging and tracing
+ * packages.
*
* Exceptions:
- * none
+ * none
*/
/*
* Excection handling should be supported by the language, thus there should
* be no need to explicitly enable exception processing.
*
* This function should probably not be called, ever. Currently it does
- * almost nothing. If there is a need for this intialization and checking.
+ * almost nothing. If there is a need for this intialization and checking.
* then this function should be converted to the new-style Enable code and
* called by all the other module Enable functions.
*/
void
EnableExceptionHandling(bool on)
{
- if (on == ExceptionHandlingEnabled) {
- /* XXX add logging of failed state */
- exitpg(255);
- /* ExitPostgres(FatalExitStatus); */
- }
-
- if (on) { /* initialize */
- ;
- } else { /* cleanup */
- ExcFileName = NULL;
- ExcLineNumber = 0;
- ExcCurFrameP = NULL;
- ExcUnCaughtP = NULL;
- }
-
- ExceptionHandlingEnabled = on;
+ if (on == ExceptionHandlingEnabled)
+ {
+ /* XXX add logging of failed state */
+ exitpg(255);
+ /* ExitPostgres(FatalExitStatus); */
+ }
+
+ if (on)
+ { /* initialize */
+ ;
+ }
+ else
+ { /* cleanup */
+ ExcFileName = NULL;
+ ExcLineNumber = 0;
+ ExcCurFrameP = NULL;
+ ExcUnCaughtP = NULL;
+ }
+
+ ExceptionHandlingEnabled = on;
}
static void
-ExcPrint(Exception *excP,
- ExcDetail detail,
- ExcData data,
- ExcMessage message)
+ExcPrint(Exception * excP,
+ ExcDetail detail,
+ ExcData data,
+ ExcMessage message)
{
- extern int errno;
- extern int sys_nerr;
-
+ extern int errno;
+ extern int sys_nerr;
+
#ifdef lint
- data = data;
+ data = data;
#endif
-
- fflush(stdout); /* In case stderr is buffered */
-
-#if 0
- if (ProgramName != NULL && *ProgramName != '\0')
- fprintf(stderr, "%s: ", ProgramName);
+
+ fflush(stdout); /* In case stderr is buffered */
+
+#if 0
+ if (ProgramName != NULL && *ProgramName != '\0')
+ fprintf(stderr, "%s: ", ProgramName);
#endif
-
- if (message != NULL)
- fprintf(stderr, "%s", message);
- else if (excP->message != NULL)
- fprintf(stderr, "%s", excP->message);
- else
+
+ if (message != NULL)
+ fprintf(stderr, "%s", message);
+ else if (excP->message != NULL)
+ fprintf(stderr, "%s", excP->message);
+ else
#ifdef lint
- fprintf(stderr, "UNNAMED EXCEPTION 0x%lx", excP);
+ fprintf(stderr, "UNNAMED EXCEPTION 0x%lx", excP);
#else
- fprintf(stderr, "UNNAMED EXCEPTION 0x%lx", (long)excP);
+ fprintf(stderr, "UNNAMED EXCEPTION 0x%lx", (long) excP);
#endif
-
- fprintf(stderr, " (%ld)", detail);
-
- if (errno > 0 && errno < sys_nerr)
- fprintf(stderr, " [%s]", strerror(errno));
- else if (errno != 0)
- fprintf(stderr, " [Error %d]", errno);
-
- fprintf(stderr, "\n");
-
- fflush(stderr);
+
+ fprintf(stderr, " (%ld)", detail);
+
+ if (errno > 0 && errno < sys_nerr)
+ fprintf(stderr, " [%s]", strerror(errno));
+ else if (errno != 0)
+ fprintf(stderr, " [Error %d]", errno);
+
+ fprintf(stderr, "\n");
+
+ fflush(stderr);
}
#ifdef NOT_USED
-ExcProc *
+ExcProc *
ExcGetUnCaught(void)
{
- return (ExcUnCaughtP);
+ return (ExcUnCaughtP);
}
+
#endif
#ifdef NOT_USED
-ExcProc *
-ExcSetUnCaught(ExcProc *newP)
+ExcProc *
+ExcSetUnCaught(ExcProc * newP)
{
- ExcProc *oldP = ExcUnCaughtP;
-
- ExcUnCaughtP = newP;
-
- return (oldP);
+ ExcProc *oldP = ExcUnCaughtP;
+
+ ExcUnCaughtP = newP;
+
+ return (oldP);
}
+
#endif
static void
-ExcUnCaught(Exception *excP,
- ExcDetail detail,
- ExcData data,
- ExcMessage message)
+ExcUnCaught(Exception * excP,
+ ExcDetail detail,
+ ExcData data,
+ ExcMessage message)
{
- ExcPrint(excP, detail, data, message);
-
- ExcAbort(excP, detail, data, message);
+ ExcPrint(excP, detail, data, message);
+
+ ExcAbort(excP, detail, data, message);
}
void
-ExcRaise(Exception *excP,
- ExcDetail detail,
- ExcData data,
- ExcMessage message)
+ExcRaise(Exception * excP,
+ ExcDetail detail,
+ ExcData data,
+ ExcMessage message)
{
- register ExcFrame *efp;
-
- efp = ExcCurFrameP;
- if (efp == NULL) {
- if (ExcUnCaughtP != NULL)
- (*ExcUnCaughtP)(excP, detail, data, message);
-
- ExcUnCaught(excP, detail, data, message);
- } else {
- efp->id = excP;
- efp->detail = detail;
- efp->data = data;
- efp->message = message;
-
- ExcCurFrameP = efp->link;
-
+ register ExcFrame *efp;
+
+ efp = ExcCurFrameP;
+ if (efp == NULL)
+ {
+ if (ExcUnCaughtP != NULL)
+ (*ExcUnCaughtP) (excP, detail, data, message);
+
+ ExcUnCaught(excP, detail, data, message);
+ }
+ else
+ {
+ efp->id = excP;
+ efp->detail = detail;
+ efp->data = data;
+ efp->message = message;
+
+ ExcCurFrameP = efp->link;
+
#if defined (JMP_BUF)
- longjmp(efp->context, 1);
+ longjmp(efp->context, 1);
#else
- siglongjmp(efp->context, 1);
+ siglongjmp(efp->context, 1);
#endif
- }
+ }
}
diff --git a/src/backend/utils/error/excabort.c b/src/backend/utils/error/excabort.c
index 29fd64ab7d5..3240f326496 100644
--- a/src/backend/utils/error/excabort.c
+++ b/src/backend/utils/error/excabort.c
@@ -1,31 +1,31 @@
/*-------------------------------------------------------------------------
*
* excabort.c--
- * Default exception abort code.
+ * Default exception abort code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/Attic/excabort.c,v 1.2 1996/11/03 06:53:32 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/Attic/excabort.c,v 1.3 1997/09/07 04:53:18 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "utils/exc.h" /* where function declarations go */
+#include "utils/exc.h" /* where function declarations go */
void
-ExcAbort(const Exception *excP,
- ExcDetail detail,
- ExcData data,
- ExcMessage message)
+ExcAbort(const Exception * excP,
+ ExcDetail detail,
+ ExcData data,
+ ExcMessage message)
{
#ifdef __SABER__
- saber_stop();
+ saber_stop();
#else
- /* dump core */
- abort();
+ /* dump core */
+ abort();
#endif
}
diff --git a/src/backend/utils/error/excid.c b/src/backend/utils/error/excid.c
index 410d7a56c88..ada9dabed70 100644
--- a/src/backend/utils/error/excid.c
+++ b/src/backend/utils/error/excid.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* excid.c--
- * POSTGRES known exception identifier code.
+ * POSTGRES known exception identifier code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/Attic/excid.c,v 1.2 1996/11/03 06:53:35 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/Attic/excid.c,v 1.3 1997/09/07 04:53:19 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,51 +17,51 @@
#include "utils/excid.h"
/*****************************************************************************
- * Generic Recoverable Exceptions *
+ * Generic Recoverable Exceptions *
*****************************************************************************/
/*
* FailedAssertion --
- * Indicates an Assert(...) failed.
+ * Indicates an Assert(...) failed.
*/
-Exception FailedAssertion = { "Failed Assertion" };
+Exception FailedAssertion = {"Failed Assertion"};
/*
* BadState --
- * Indicates a function call request is inconsistent with module state.
+ * Indicates a function call request is inconsistent with module state.
*/
-Exception BadState = { "Bad State for Function Call" };
+Exception BadState = {"Bad State for Function Call"};
/*
* BadArg --
- * Indicates a function call argument or arguments is out-of-bounds.
+ * Indicates a function call argument or arguments is out-of-bounds.
*/
-Exception BadArg = { "Bad Argument to Function Call" };
+Exception BadArg = {"Bad Argument to Function Call"};
/*****************************************************************************
- * Specific Recoverable Exceptions *
+ * Specific Recoverable Exceptions *
*****************************************************************************/
/*
* BadAllocSize --
- * Indicates that an allocation request is of unreasonable size.
+ * Indicates that an allocation request is of unreasonable size.
*/
-Exception BadAllocSize = { "Too Large Allocation Request" };
+Exception BadAllocSize = {"Too Large Allocation Request"};
/*
* ExhaustedMemory --
- * Indicates an dynamic memory allocation failed.
+ * Indicates an dynamic memory allocation failed.
*/
-Exception ExhaustedMemory = { "Memory Allocation Failed" };
+Exception ExhaustedMemory = {"Memory Allocation Failed"};
/*
* Unimplemented --
- * Indicates a function call request requires unimplemented code.
+ * Indicates a function call request requires unimplemented code.
*/
-Exception Unimplemented = { "Unimplemented Functionality" };
+Exception Unimplemented = {"Unimplemented Functionality"};
-Exception CatalogFailure = {"Catalog failure"}; /* XXX inconsistent */
-Exception InternalError = {"Internal Error"}; /* XXX inconsistent */
-Exception SemanticError = {"Semantic Error"}; /* XXX inconsistent */
-Exception SystemError = {"System Error"}; /* XXX inconsistent */
+Exception CatalogFailure = {"Catalog failure"}; /* XXX inconsistent */
+Exception InternalError = {"Internal Error"}; /* XXX inconsistent */
+Exception SemanticError = {"Semantic Error"}; /* XXX inconsistent */
+Exception SystemError = {"System Error"}; /* XXX inconsistent */
diff --git a/src/backend/utils/error/format.c b/src/backend/utils/error/format.c
index bdbaddb402f..f996dbb8eb7 100644
--- a/src/backend/utils/error/format.c
+++ b/src/backend/utils/error/format.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* format.c--
- * a wrapper around code that does what vsprintf does.
+ * a wrapper around code that does what vsprintf does.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/error/Attic/format.c,v 1.3 1997/08/12 22:54:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/error/Attic/format.c,v 1.4 1997/09/07 04:53:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -15,26 +15,26 @@
#include <stdarg.h>
#include "c.h"
-#define FormMaxSize 1024
-#define FormMinSize (FormMaxSize / 8)
+#define FormMaxSize 1024
+#define FormMinSize (FormMaxSize / 8)
-static char FormBuf[FormMaxSize];
+static char FormBuf[FormMaxSize];
/* ----------------
- * form
+ * form
* ----------------
*/
-char *
-form(const char *fmt, ... )
+char *
+form(const char *fmt,...)
{
- va_list args;
+ va_list args;
- va_start(args, fmt);
-
- vsprintf(FormBuf, fmt, args);
+ va_start(args, fmt);
- va_end(args);
-
- return (FormBuf);
+ vsprintf(FormBuf, fmt, args);
+
+ va_end(args);
+
+ return (FormBuf);
}
diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c
index 079c9d0a173..0be7524290f 100644
--- a/src/backend/utils/fmgr/dfmgr.c
+++ b/src/backend/utils/fmgr/dfmgr.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* dfmgr.c--
- * Dynamic function manager code.
+ * Dynamic function manager code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.9 1997/09/01 08:06:17 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.10 1997/09/07 04:53:24 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -18,15 +18,15 @@
#include "postgres.h"
-#include "config.h" /* for MAXPATHLEN */
-#include "fmgr.h" /* generated by Gen_fmgrtab.sh */
+#include "config.h" /* for MAXPATHLEN */
+#include "fmgr.h" /* generated by Gen_fmgrtab.sh */
#include "utils/dynamic_loader.h"
#include "utils/elog.h"
#include "utils/builtins.h"
#include "access/heapam.h"
#include "nodes/pg_list.h"
-#include "port-protos.h" /* system specific function prototypes */
+#include "port-protos.h" /* system specific function prototypes */
#ifdef __ultrix
#include <dl.h>
#endif
@@ -39,178 +39,197 @@ static DynamicFileList *file_list = (DynamicFileList *) NULL;
static DynamicFileList *file_tail = (DynamicFileList *) NULL;
#define NOT_EQUAL(A, B) (((A).st_ino != (B).inode) \
- || ((A).st_dev != (B).device))
+ || ((A).st_dev != (B).device))
-static Oid procedureId_save = -1;
-static int pronargs_save;
+static Oid procedureId_save = -1;
+static int pronargs_save;
static func_ptr user_fn_save = (func_ptr) NULL;
static func_ptr handle_load(char *filename, char *funcname);
-func_ptr trigger_dynamic (char *filename, char *funcname);
+func_ptr trigger_dynamic(char *filename, char *funcname);
func_ptr
fmgr_dynamic(Oid procedureId, int *pronargs)
{
- HeapTuple procedureTuple;
- Form_pg_proc procedureStruct;
- char *proname;
- char *probinattr, *probinstring;
- func_ptr user_fn;
- Relation rdesc;
- bool isnull;
-
- if (procedureId == procedureId_save) {
- *pronargs = pronargs_save;
- return(user_fn_save);
- }
-
- /*
- * The procedure isn't a builtin, so we'll have to do a catalog
- * lookup to find its pg_proc entry.
- */
- procedureTuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(procedureId),
- 0,0,0);
- if (!HeapTupleIsValid(procedureTuple)) {
- elog(WARN, "fmgr: Cache lookup failed for procedure %d\n",
- procedureId);
- return((func_ptr) NULL);
- }
-
- procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
- proname = procedureStruct->proname.data;
- pronargs_save = *pronargs = procedureStruct->pronargs;
-
- /*
- * Extract the procedure info from the pg_proc tuple.
- * Since probin is varlena, do a amgetattr() on the procedure
- * tuple. To do that, we need the rdesc for the procedure
- * relation, so...
- */
-
- /* open pg_procedure */
-
- rdesc = heap_openr(ProcedureRelationName);
- if (!RelationIsValid(rdesc)) {
- elog(WARN, "fmgr: Could not open relation %s",
- ProcedureRelationName);
- return((func_ptr) NULL);
- }
- probinattr = heap_getattr(procedureTuple, (Buffer) 0,
- Anum_pg_proc_probin,
- RelationGetTupleDescriptor(rdesc), &isnull);
- if (!PointerIsValid(probinattr) /*|| isnull*/) {
- heap_close(rdesc);
- elog(WARN, "fmgr: Could not extract probin for %d from %s",
- procedureId, ProcedureRelationName);
- return((func_ptr) NULL);
- }
- probinstring = textout((struct varlena *) probinattr);
-
- user_fn = handle_load(probinstring, proname);
-
- procedureId_save = procedureId;
- user_fn_save = user_fn;
-
- return(user_fn);
+ HeapTuple procedureTuple;
+ Form_pg_proc procedureStruct;
+ char *proname;
+ char *probinattr,
+ *probinstring;
+ func_ptr user_fn;
+ Relation rdesc;
+ bool isnull;
+
+ if (procedureId == procedureId_save)
+ {
+ *pronargs = pronargs_save;
+ return (user_fn_save);
+ }
+
+ /*
+ * The procedure isn't a builtin, so we'll have to do a catalog lookup
+ * to find its pg_proc entry.
+ */
+ procedureTuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(procedureId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(procedureTuple))
+ {
+ elog(WARN, "fmgr: Cache lookup failed for procedure %d\n",
+ procedureId);
+ return ((func_ptr) NULL);
+ }
+
+ procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
+ proname = procedureStruct->proname.data;
+ pronargs_save = *pronargs = procedureStruct->pronargs;
+
+ /*
+ * Extract the procedure info from the pg_proc tuple. Since probin is
+ * varlena, do a amgetattr() on the procedure tuple. To do that, we
+ * need the rdesc for the procedure relation, so...
+ */
+
+ /* open pg_procedure */
+
+ rdesc = heap_openr(ProcedureRelationName);
+ if (!RelationIsValid(rdesc))
+ {
+ elog(WARN, "fmgr: Could not open relation %s",
+ ProcedureRelationName);
+ return ((func_ptr) NULL);
+ }
+ probinattr = heap_getattr(procedureTuple, (Buffer) 0,
+ Anum_pg_proc_probin,
+ RelationGetTupleDescriptor(rdesc), &isnull);
+ if (!PointerIsValid(probinattr) /* || isnull */ )
+ {
+ heap_close(rdesc);
+ elog(WARN, "fmgr: Could not extract probin for %d from %s",
+ procedureId, ProcedureRelationName);
+ return ((func_ptr) NULL);
+ }
+ probinstring = textout((struct varlena *) probinattr);
+
+ user_fn = handle_load(probinstring, proname);
+
+ procedureId_save = procedureId;
+ user_fn_save = user_fn;
+
+ return (user_fn);
}
-static func_ptr
+static func_ptr
handle_load(char *filename, char *funcname)
{
- DynamicFileList *file_scanner = (DynamicFileList *) NULL;
- func_ptr retval = (func_ptr) NULL;
- char *load_error;
- struct stat stat_buf;
-
- /*
- * Do this because loading files may screw up the dynamic function
- * manager otherwise.
- */
- procedureId_save = -1;
-
- /*
- * Scan the list of loaded FILES to see if the function
- * has been loaded.
- */
-
- if (filename != (char *) NULL) {
- for (file_scanner = file_list;
- file_scanner != (DynamicFileList *) NULL
- && file_scanner->filename != (char *) NULL
- && strcmp(filename, file_scanner->filename) != 0;
- file_scanner = file_scanner->next)
- ;
- if (file_scanner == (DynamicFileList *) NULL) {
- if (stat(filename, &stat_buf) == -1) {
- elog(WARN, "stat failed on file %s", filename);
- }
-
- for (file_scanner = file_list;
- file_scanner != (DynamicFileList *) NULL
- && (NOT_EQUAL(stat_buf, *file_scanner));
- file_scanner = file_scanner->next)
- ;
- /*
- * Same files - different paths (ie, symlink or link)
- */
- if (file_scanner != (DynamicFileList *) NULL)
- strcpy(file_scanner->filename, filename);
-
- }
- } else {
- file_scanner = (DynamicFileList *) NULL;
- }
-
- /*
- * File not loaded yet.
- */
-
- if (file_scanner == (DynamicFileList *) NULL) {
- if (file_list == (DynamicFileList *) NULL) {
- file_list = (DynamicFileList *)
- malloc(sizeof(DynamicFileList));
- file_scanner = file_list;
- } else {
- file_tail->next = (DynamicFileList *)
- malloc(sizeof(DynamicFileList));
- file_scanner = file_tail->next;
- }
- memset((char *) file_scanner, 0, sizeof(DynamicFileList));
-
- strcpy(file_scanner->filename, filename);
- file_scanner->device = stat_buf.st_dev;
- file_scanner->inode = stat_buf.st_ino;
- file_scanner->next = (DynamicFileList *) NULL;
-
- file_scanner->handle = pg_dlopen(filename);
- if (file_scanner->handle == (void *)NULL) {
- load_error = (char *) pg_dlerror();
- if (file_scanner == file_list) {
- file_list = (DynamicFileList *) NULL;
- } else {
- file_tail->next = (DynamicFileList *) NULL;
- }
-
- free((char *) file_scanner);
- elog(WARN, "Load of file %s failed: %s", filename, load_error);
- }
-
+ DynamicFileList *file_scanner = (DynamicFileList *) NULL;
+ func_ptr retval = (func_ptr) NULL;
+ char *load_error;
+ struct stat stat_buf;
+
+ /*
+ * Do this because loading files may screw up the dynamic function
+ * manager otherwise.
+ */
+ procedureId_save = -1;
+
/*
- * Just load the file - we are done with that so return.
+ * Scan the list of loaded FILES to see if the function has been
+ * loaded.
*/
- file_tail = file_scanner;
-
- if (funcname == (char *) NULL)
- return((func_ptr) NULL);
- }
-
- retval = (func_ptr) pg_dlsym(file_scanner->handle, funcname);
-
- if (retval == (func_ptr) NULL) {
- elog(WARN, "Can't find function %s in file %s", funcname, filename);
- }
-
- return(retval);
+
+ if (filename != (char *) NULL)
+ {
+ for (file_scanner = file_list;
+ file_scanner != (DynamicFileList *) NULL
+ && file_scanner->filename != (char *) NULL
+ && strcmp(filename, file_scanner->filename) != 0;
+ file_scanner = file_scanner->next)
+ ;
+ if (file_scanner == (DynamicFileList *) NULL)
+ {
+ if (stat(filename, &stat_buf) == -1)
+ {
+ elog(WARN, "stat failed on file %s", filename);
+ }
+
+ for (file_scanner = file_list;
+ file_scanner != (DynamicFileList *) NULL
+ && (NOT_EQUAL(stat_buf, *file_scanner));
+ file_scanner = file_scanner->next)
+ ;
+
+ /*
+ * Same files - different paths (ie, symlink or link)
+ */
+ if (file_scanner != (DynamicFileList *) NULL)
+ strcpy(file_scanner->filename, filename);
+
+ }
+ }
+ else
+ {
+ file_scanner = (DynamicFileList *) NULL;
+ }
+
+ /*
+ * File not loaded yet.
+ */
+
+ if (file_scanner == (DynamicFileList *) NULL)
+ {
+ if (file_list == (DynamicFileList *) NULL)
+ {
+ file_list = (DynamicFileList *)
+ malloc(sizeof(DynamicFileList));
+ file_scanner = file_list;
+ }
+ else
+ {
+ file_tail->next = (DynamicFileList *)
+ malloc(sizeof(DynamicFileList));
+ file_scanner = file_tail->next;
+ }
+ memset((char *) file_scanner, 0, sizeof(DynamicFileList));
+
+ strcpy(file_scanner->filename, filename);
+ file_scanner->device = stat_buf.st_dev;
+ file_scanner->inode = stat_buf.st_ino;
+ file_scanner->next = (DynamicFileList *) NULL;
+
+ file_scanner->handle = pg_dlopen(filename);
+ if (file_scanner->handle == (void *) NULL)
+ {
+ load_error = (char *) pg_dlerror();
+ if (file_scanner == file_list)
+ {
+ file_list = (DynamicFileList *) NULL;
+ }
+ else
+ {
+ file_tail->next = (DynamicFileList *) NULL;
+ }
+
+ free((char *) file_scanner);
+ elog(WARN, "Load of file %s failed: %s", filename, load_error);
+ }
+
+ /*
+ * Just load the file - we are done with that so return.
+ */
+ file_tail = file_scanner;
+
+ if (funcname == (char *) NULL)
+ return ((func_ptr) NULL);
+ }
+
+ retval = (func_ptr) pg_dlsym(file_scanner->handle, funcname);
+
+ if (retval == (func_ptr) NULL)
+ {
+ elog(WARN, "Can't find function %s in file %s", funcname, filename);
+ }
+
+ return (retval);
}
/*
@@ -218,7 +237,7 @@ handle_load(char *filename, char *funcname)
*
* If the file is already loaded:
* o Zero out that file's loaded space (so it doesn't screw up linking)
- * o Free all space associated with that file
+ * o Free all space associated with that file
* o Free that file's descriptor.
*
* Now load the file by calling handle_load with a NULL argument as the
@@ -227,49 +246,61 @@ handle_load(char *filename, char *funcname)
void
load_file(char *filename)
{
- DynamicFileList *file_scanner, *p;
- struct stat stat_buf;
-
- int done = 0;
-
- if (stat(filename, &stat_buf) == -1) {
- elog(WARN, "stat failed on file %s", filename);
- }
-
- if (file_list != (DynamicFileList *) NULL
- && !NOT_EQUAL(stat_buf, *file_list)) {
- file_scanner = file_list;
- file_list = file_list->next;
- pg_dlclose(file_scanner->handle);
- free((char *) file_scanner);
- } else if (file_list != (DynamicFileList *) NULL) {
- file_scanner = file_list;
- while (!done) {
- if (file_scanner->next == (DynamicFileList *) NULL) {
- done = 1;
- } else if (!NOT_EQUAL(stat_buf, *(file_scanner->next))) {
- done = 1;
- } else {
- file_scanner = file_scanner->next;
- }
- }
-
- if (file_scanner->next != (DynamicFileList *) NULL) {
- p = file_scanner->next;
- file_scanner->next = file_scanner->next->next;
- pg_dlclose(file_scanner->handle);
- free((char *)p);
- }
- }
- handle_load(filename, (char *) NULL);
+ DynamicFileList *file_scanner,
+ *p;
+ struct stat stat_buf;
+
+ int done = 0;
+
+ if (stat(filename, &stat_buf) == -1)
+ {
+ elog(WARN, "stat failed on file %s", filename);
+ }
+
+ if (file_list != (DynamicFileList *) NULL
+ && !NOT_EQUAL(stat_buf, *file_list))
+ {
+ file_scanner = file_list;
+ file_list = file_list->next;
+ pg_dlclose(file_scanner->handle);
+ free((char *) file_scanner);
+ }
+ else if (file_list != (DynamicFileList *) NULL)
+ {
+ file_scanner = file_list;
+ while (!done)
+ {
+ if (file_scanner->next == (DynamicFileList *) NULL)
+ {
+ done = 1;
+ }
+ else if (!NOT_EQUAL(stat_buf, *(file_scanner->next)))
+ {
+ done = 1;
+ }
+ else
+ {
+ file_scanner = file_scanner->next;
+ }
+ }
+
+ if (file_scanner->next != (DynamicFileList *) NULL)
+ {
+ p = file_scanner->next;
+ file_scanner->next = file_scanner->next->next;
+ pg_dlclose(file_scanner->handle);
+ free((char *) p);
+ }
+ }
+ handle_load(filename, (char *) NULL);
}
func_ptr
-trigger_dynamic (char *filename, char *funcname)
+trigger_dynamic(char *filename, char *funcname)
{
- func_ptr trigger_fn;
-
- trigger_fn = handle_load (filename, funcname);
-
- return (trigger_fn);
+ func_ptr trigger_fn;
+
+ trigger_fn = handle_load(filename, funcname);
+
+ return (trigger_fn);
}
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 1da0ab18773..f7d7b29d0a6 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* fmgr.c--
- * Interface routines for the table-driven function manager.
+ * Interface routines for the table-driven function manager.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.3 1997/08/19 21:35:21 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.4 1997/09/07 04:53:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,7 @@
#include "postgres.h"
/* these 2 files are generated by Gen_fmgrtab.sh; contain the declarations */
-#include "fmgr.h"
+#include "fmgr.h"
#include "utils/fmgrtab.h"
#include "nodes/pg_list.h"
@@ -29,173 +29,183 @@
#include "utils/elog.h"
-char *
+char *
fmgr_c(func_ptr user_fn,
- Oid func_id,
- int n_arguments,
- FmgrValues *values,
- bool *isNull)
+ Oid func_id,
+ int n_arguments,
+ FmgrValues * values,
+ bool * isNull)
{
- char *returnValue = (char *) NULL;
+ char *returnValue = (char *) NULL;
-
- if (user_fn == (func_ptr) NULL) {
- /*
- * a NULL func_ptr denotes untrusted function (in postgres 4.2).
- * Untrusted functions have very limited use and is clumsy. We
- * just get rid of it.
- */
- elog(WARN, "internal error: untrusted function not supported.");
- }
-
- switch (n_arguments) {
- case 0:
- returnValue = (*user_fn)();
- break;
- case 1:
- /* NullValue() uses isNull to check if args[0] is NULL */
- returnValue = (*user_fn)(values->data[0], isNull);
- break;
- case 2:
- returnValue = (*user_fn)(values->data[0], values->data[1]);
- break;
- case 3:
- returnValue = (*user_fn)(values->data[0], values->data[1],
- values->data[2]);
- break;
- case 4:
- returnValue = (*user_fn)(values->data[0], values->data[1],
- values->data[2], values->data[3]);
- break;
- case 5:
- returnValue = (*user_fn)(values->data[0], values->data[1],
- values->data[2], values->data[3],
- values->data[4]);
- break;
- case 6:
- returnValue = (*user_fn)(values->data[0], values->data[1],
- values->data[2], values->data[3],
- values->data[4], values->data[5]);
- break;
- case 7:
- returnValue = (*user_fn)(values->data[0], values->data[1],
- values->data[2], values->data[3],
- values->data[4], values->data[5],
- values->data[6]);
- break;
- case 8:
- returnValue = (*user_fn)(values->data[0], values->data[1],
- values->data[2], values->data[3],
- values->data[4], values->data[5],
- values->data[6], values->data[7]);
- break;
- case 9:
- /*
- * XXX Note that functions with >8 arguments can only be
- * called from inside the system, not from the user level,
- * since the catalogs only store 8 argument types for user
- * type-checking!
- */
- returnValue = (*user_fn)(values->data[0], values->data[1],
- values->data[2], values->data[3],
- values->data[4], values->data[5],
- values->data[6], values->data[7],
- values->data[8]);
- break;
- default:
- elog(WARN, "fmgr_c: function %d: too many arguments (%d > %d)",
- func_id, n_arguments, MAXFMGRARGS);
- break;
- }
- return(returnValue);
+
+ if (user_fn == (func_ptr) NULL)
+ {
+
+ /*
+ * a NULL func_ptr denotes untrusted function (in postgres 4.2).
+ * Untrusted functions have very limited use and is clumsy. We
+ * just get rid of it.
+ */
+ elog(WARN, "internal error: untrusted function not supported.");
+ }
+
+ switch (n_arguments)
+ {
+ case 0:
+ returnValue = (*user_fn) ();
+ break;
+ case 1:
+ /* NullValue() uses isNull to check if args[0] is NULL */
+ returnValue = (*user_fn) (values->data[0], isNull);
+ break;
+ case 2:
+ returnValue = (*user_fn) (values->data[0], values->data[1]);
+ break;
+ case 3:
+ returnValue = (*user_fn) (values->data[0], values->data[1],
+ values->data[2]);
+ break;
+ case 4:
+ returnValue = (*user_fn) (values->data[0], values->data[1],
+ values->data[2], values->data[3]);
+ break;
+ case 5:
+ returnValue = (*user_fn) (values->data[0], values->data[1],
+ values->data[2], values->data[3],
+ values->data[4]);
+ break;
+ case 6:
+ returnValue = (*user_fn) (values->data[0], values->data[1],
+ values->data[2], values->data[3],
+ values->data[4], values->data[5]);
+ break;
+ case 7:
+ returnValue = (*user_fn) (values->data[0], values->data[1],
+ values->data[2], values->data[3],
+ values->data[4], values->data[5],
+ values->data[6]);
+ break;
+ case 8:
+ returnValue = (*user_fn) (values->data[0], values->data[1],
+ values->data[2], values->data[3],
+ values->data[4], values->data[5],
+ values->data[6], values->data[7]);
+ break;
+ case 9:
+
+ /*
+ * XXX Note that functions with >8 arguments can only be called
+ * from inside the system, not from the user level, since the
+ * catalogs only store 8 argument types for user type-checking!
+ */
+ returnValue = (*user_fn) (values->data[0], values->data[1],
+ values->data[2], values->data[3],
+ values->data[4], values->data[5],
+ values->data[6], values->data[7],
+ values->data[8]);
+ break;
+ default:
+ elog(WARN, "fmgr_c: function %d: too many arguments (%d > %d)",
+ func_id, n_arguments, MAXFMGRARGS);
+ break;
+ }
+ return (returnValue);
}
void
-fmgr_info(Oid procedureId, func_ptr *function, int *nargs)
+fmgr_info(Oid procedureId, func_ptr * function, int *nargs)
{
- func_ptr user_fn = NULL;
- FmgrCall *fcp;
- HeapTuple procedureTuple;
- FormData_pg_proc *procedureStruct;
- Oid language;
-
- if (!(fcp = fmgr_isbuiltin(procedureId))) {
- procedureTuple = SearchSysCacheTuple(PROOID,
- ObjectIdGetDatum(procedureId),
- 0,0,0);
- if (!HeapTupleIsValid(procedureTuple)) {
- elog(WARN, "fmgr_info: function %d: cache lookup failed\n",
- procedureId);
+ func_ptr user_fn = NULL;
+ FmgrCall *fcp;
+ HeapTuple procedureTuple;
+ FormData_pg_proc *procedureStruct;
+ Oid language;
+
+ if (!(fcp = fmgr_isbuiltin(procedureId)))
+ {
+ procedureTuple = SearchSysCacheTuple(PROOID,
+ ObjectIdGetDatum(procedureId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(procedureTuple))
+ {
+ elog(WARN, "fmgr_info: function %d: cache lookup failed\n",
+ procedureId);
+ }
+ procedureStruct = (FormData_pg_proc *)
+ GETSTRUCT(procedureTuple);
+ if (!procedureStruct->proistrusted)
+ {
+ *function = (func_ptr) NULL;
+ *nargs = procedureStruct->pronargs;
+ return;
+ }
+ language = procedureStruct->prolang;
+ switch (language)
+ {
+ case INTERNALlanguageId:
+ user_fn = fmgr_lookupByName(procedureStruct->proname.data);
+ if (!user_fn)
+ elog(WARN, "fmgr_info: function %s: not in internal table",
+ procedureStruct->proname.data);
+ break;
+ case ClanguageId:
+ user_fn = fmgr_dynamic(procedureId, nargs);
+ break;
+ case SQLlanguageId:
+ user_fn = (func_ptr) NULL;
+ *nargs = procedureStruct->pronargs;
+ break;
+ default:
+ elog(WARN, "fmgr_info: function %d: unknown language %d",
+ procedureId, language);
+ }
}
- procedureStruct = (FormData_pg_proc *)
- GETSTRUCT(procedureTuple);
- if (!procedureStruct->proistrusted) {
- *function = (func_ptr) NULL;
- *nargs = procedureStruct->pronargs;
- return;
+ else
+ {
+ user_fn = fcp->func;
+ *nargs = fcp->nargs;
}
- language = procedureStruct->prolang;
- switch (language) {
- case INTERNALlanguageId:
- user_fn = fmgr_lookupByName(procedureStruct->proname.data);
- if (!user_fn)
- elog(WARN, "fmgr_info: function %s: not in internal table",
- procedureStruct->proname.data);
- break;
- case ClanguageId:
- user_fn = fmgr_dynamic(procedureId, nargs);
- break;
- case SQLlanguageId:
- user_fn = (func_ptr) NULL;
- *nargs = procedureStruct->pronargs;
- break;
- default:
- elog(WARN, "fmgr_info: function %d: unknown language %d",
- procedureId, language);
- }
- } else {
- user_fn = fcp->func;
- *nargs = fcp->nargs;
- }
- *function = user_fn;
+ *function = user_fn;
}
/*
- * fmgr - return the value of a function call
+ * fmgr - return the value of a function call
*
- * If the function is a system routine, it's compiled in, so call
- * it directly.
+ * If the function is a system routine, it's compiled in, so call
+ * it directly.
*
- * Otherwise pass it to the the appropriate 'language' function caller.
+ * Otherwise pass it to the the appropriate 'language' function caller.
*
- * Returns the return value of the invoked function if succesful,
- * 0 if unsuccessful.
+ * Returns the return value of the invoked function if succesful,
+ * 0 if unsuccessful.
*/
-char *
-fmgr(Oid procedureId, ... )
+char *
+fmgr(Oid procedureId,...)
{
- va_list pvar;
- register i;
- int pronargs;
- FmgrValues values;
- func_ptr user_fn;
- bool isNull = false;
-
- va_start(pvar, procedureId);
-
- fmgr_info(procedureId, &user_fn, &pronargs);
-
- if (pronargs > MAXFMGRARGS) {
- elog(WARN, "fmgr: function %d: too many arguments (%d > %d)",
- procedureId, pronargs, MAXFMGRARGS);
- }
- for (i = 0; i < pronargs; ++i)
- values.data[i] = va_arg(pvar, char *);
- va_end(pvar);
-
- /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */
- return(fmgr_c(user_fn, procedureId, pronargs, &values,
- &isNull));
+ va_list pvar;
+ register i;
+ int pronargs;
+ FmgrValues values;
+ func_ptr user_fn;
+ bool isNull = false;
+
+ va_start(pvar, procedureId);
+
+ fmgr_info(procedureId, &user_fn, &pronargs);
+
+ if (pronargs > MAXFMGRARGS)
+ {
+ elog(WARN, "fmgr: function %d: too many arguments (%d > %d)",
+ procedureId, pronargs, MAXFMGRARGS);
+ }
+ for (i = 0; i < pronargs; ++i)
+ values.data[i] = va_arg(pvar, char *);
+ va_end(pvar);
+
+ /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */
+ return (fmgr_c(user_fn, procedureId, pronargs, &values,
+ &isNull));
}
/*
@@ -204,33 +214,35 @@ fmgr(Oid procedureId, ... )
* if you have all of this information you're likely to just jump through
* the pointer, but it's available for use with macros in fmgr.h if you
* want this routine to do sanity-checking for you.
- *
+ *
* func_ptr, func_id, n_arguments, args...
*/
#ifdef NOT_USED
-char *
-fmgr_ptr(func_ptr user_fn, Oid func_id, ...)
+char *
+fmgr_ptr(func_ptr user_fn, Oid func_id,...)
{
- va_list pvar;
- register i;
- int n_arguments;
- FmgrValues values;
- bool isNull = false;
-
- va_start(pvar, func_id);
- n_arguments = va_arg(pvar, int);
- if (n_arguments > MAXFMGRARGS) {
- elog(WARN, "fmgr_ptr: function %d: too many arguments (%d > %d)",
- func_id, n_arguments, MAXFMGRARGS);
- }
- for (i = 0; i < n_arguments; ++i)
- values.data[i] = va_arg(pvar, char *);
- va_end(pvar);
-
- /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */
- return(fmgr_c(user_fn, func_id, n_arguments, &values,
- &isNull));
+ va_list pvar;
+ register i;
+ int n_arguments;
+ FmgrValues values;
+ bool isNull = false;
+
+ va_start(pvar, func_id);
+ n_arguments = va_arg(pvar, int);
+ if (n_arguments > MAXFMGRARGS)
+ {
+ elog(WARN, "fmgr_ptr: function %d: too many arguments (%d > %d)",
+ func_id, n_arguments, MAXFMGRARGS);
+ }
+ for (i = 0; i < n_arguments; ++i)
+ values.data[i] = va_arg(pvar, char *);
+ va_end(pvar);
+
+ /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */
+ return (fmgr_c(user_fn, func_id, n_arguments, &values,
+ &isNull));
}
+
#endif
/*
@@ -238,19 +250,19 @@ fmgr_ptr(func_ptr user_fn, Oid func_id, ...)
* function pointer field to FuncIndexInfo, it will be replace by calls
* to fmgr_c().
*/
-char *
-fmgr_array_args(Oid procedureId, int nargs, char *args[], bool *isNull)
+char *
+fmgr_array_args(Oid procedureId, int nargs, char *args[], bool * isNull)
{
- func_ptr user_fn;
- int true_arguments;
-
- fmgr_info(procedureId, &user_fn, &true_arguments);
-
- /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */
- return
- (fmgr_c(user_fn,
- procedureId,
- true_arguments,
- (FmgrValues*)args,
- isNull));
+ func_ptr user_fn;
+ int true_arguments;
+
+ fmgr_info(procedureId, &user_fn, &true_arguments);
+
+ /* XXX see WAY_COOL_ORTHOGONAL_FUNCTIONS */
+ return
+ (fmgr_c(user_fn,
+ procedureId,
+ true_arguments,
+ (FmgrValues *) args,
+ isNull));
}
diff --git a/src/backend/utils/hash/dynahash.c b/src/backend/utils/hash/dynahash.c
index db209e1c338..736ca39d09f 100644
--- a/src/backend/utils/hash/dynahash.c
+++ b/src/backend/utils/hash/dynahash.c
@@ -1,18 +1,18 @@
/*-------------------------------------------------------------------------
*
* dynahash.c--
- * dynamic hashing
+ * dynamic hashing
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.7 1997/08/12 22:54:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/hash/dynahash.c,v 1.8 1997/09/07 04:53:33 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
- *
+ *
* Dynamic hashing, after CACM April 1988 pp 446-457, by Per-Ake Larson.
* Coded into C, with minor code improvements, and with hsearch(3) interface,
* by [email protected], Jul 26, 1988: 13:16;
@@ -35,27 +35,27 @@
* concatenation property, in probably unnecessary code 'optimisation'.
*
* Modified [email protected] February 1990
- * added multiple table interface
+ * added multiple table interface
* Modified by [email protected] April 1990
- * changed ctl structure for shared memory
+ * changed ctl structure for shared memory
*/
-# include <stdio.h>
-# include <sys/types.h>
-# include <string.h>
-# include "postgres.h"
-# include "utils/dynahash.h"
-# include "utils/hsearch.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include "postgres.h"
+#include "utils/dynahash.h"
+#include "utils/hsearch.h"
#ifndef FRONTEND
-# include "utils/mcxt.h"
-#endif /* !FRONTEND */
-# include "utils/palloc.h"
+#include "utils/mcxt.h"
+#endif /* !FRONTEND */
+#include "utils/palloc.h"
/*
* Fast arithmetic, relying on powers of 2,
* and on pre-processor concatenation property
*/
-# define MOD(x,y) ((x) & ((y)-1))
+#define MOD(x,y) ((x) & ((y)-1))
/*
* external routines
@@ -64,14 +64,14 @@
/*
* Private function prototypes
*/
-static long *DynaHashAlloc(unsigned int size);
-static void DynaHashFree(Pointer ptr);
-static uint32 call_hash(HTAB *hashp, char *k, int len);
-static SEG_OFFSET seg_alloc(HTAB *hashp);
-static int bucket_alloc(HTAB *hashp);
-static int dir_realloc(HTAB *hashp);
+static long *DynaHashAlloc(unsigned int size);
+static void DynaHashFree(Pointer ptr);
+static uint32 call_hash(HTAB * hashp, char *k, int len);
+static SEG_OFFSET seg_alloc(HTAB * hashp);
+static int bucket_alloc(HTAB * hashp);
+static int dir_realloc(HTAB * hashp);
-typedef long * ((*dhalloc_ptr)());
+typedef long *((*dhalloc_ptr) ());
#ifndef FRONTEND
/* ----------------
@@ -82,54 +82,54 @@ typedef long * ((*dhalloc_ptr)());
* garbage collector is going to corrupt them. -wei
*
* ??? the "cache" memory context is intended to store only
- * system cache information. The user of the hashing
- * routines should specify which context to use or we
- * should create a separate memory context for these
- * hash routines. For now I have modified this code to
- * do the latter -cim 1/19/91
+ * system cache information. The user of the hashing
+ * routines should specify which context to use or we
+ * should create a separate memory context for these
+ * hash routines. For now I have modified this code to
+ * do the latter -cim 1/19/91
* ----------------
*/
-GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
+GlobalMemory DynaHashCxt = (GlobalMemory) NULL;
-static long *
+static long *
DynaHashAlloc(unsigned int size)
{
- if (! DynaHashCxt)
- DynaHashCxt = CreateGlobalMemory("DynaHash");
+ if (!DynaHashCxt)
+ DynaHashCxt = CreateGlobalMemory("DynaHash");
- return (long *)
- MemoryContextAlloc((MemoryContext)DynaHashCxt, size);
+ return (long *)
+ MemoryContextAlloc((MemoryContext) DynaHashCxt, size);
}
static void
DynaHashFree(Pointer ptr)
{
- MemoryContextFree((MemoryContext)DynaHashCxt, ptr);
+ MemoryContextFree((MemoryContext) DynaHashCxt, ptr);
}
-#define MEM_ALLOC DynaHashAlloc
-#define MEM_FREE DynaHashFree
+#define MEM_ALLOC DynaHashAlloc
+#define MEM_FREE DynaHashFree
-#else /* FRONTEND */
+#else /* FRONTEND */
-#define MEM_ALLOC palloc
-#define MEM_FREE pfree
+#define MEM_ALLOC palloc
+#define MEM_FREE pfree
-#endif /* FRONTEND */
+#endif /* FRONTEND */
/* ----------------
* Internal routines
* ----------------
*/
-static int expand_table(HTAB *hashp);
-static int hdefault(HTAB *hashp);
-static int init_htab(HTAB *hashp, int nelem);
+static int expand_table(HTAB * hashp);
+static int hdefault(HTAB * hashp);
+static int init_htab(HTAB * hashp, int nelem);
/*
* pointer access macros. Shared memory implementation cannot
- * store pointers in the hash table data structures because
+ * store pointers in the hash table data structures because
* pointer values will be different in different address spaces.
* these macros convert offsets to pointers and pointers to offsets.
* Shared memory need not be contiguous, but all addresses must be
@@ -145,282 +145,318 @@ static int init_htab(HTAB *hashp, int nelem);
#define MAKE_HASHOFFSET(hp,ptr)\
( ((unsigned long) ptr) - ((unsigned long) (hp)->segbase) )
-# if HASH_STATISTICS
-static long hash_accesses, hash_collisions, hash_expansions;
-# endif
+#if HASH_STATISTICS
+static long hash_accesses,
+ hash_collisions,
+ hash_expansions;
+
+#endif
/************************** CREATE ROUTINES **********************/
-HTAB *
-hash_create(int nelem, HASHCTL *info, int flags)
+HTAB *
+hash_create(int nelem, HASHCTL * info, int flags)
{
- register HHDR * hctl;
- HTAB * hashp;
-
-
- hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
- memset(hashp, 0, sizeof(HTAB));
-
- if ( flags & HASH_FUNCTION ) {
- hashp->hash = info->hash;
- } else {
- /* default */
- hashp->hash = string_hash;
- }
-
- if ( flags & HASH_SHARED_MEM ) {
- /* ctl structure is preallocated for shared memory tables */
-
- hashp->hctl = (HHDR *) info->hctl;
- hashp->segbase = (char *) info->segbase;
- hashp->alloc = info->alloc;
- hashp->dir = (SEG_OFFSET *)info->dir;
-
- /* hash table already exists, we're just attaching to it */
- if (flags & HASH_ATTACH) {
- return(hashp);
+ register HHDR *hctl;
+ HTAB *hashp;
+
+
+ hashp = (HTAB *) MEM_ALLOC((unsigned long) sizeof(HTAB));
+ memset(hashp, 0, sizeof(HTAB));
+
+ if (flags & HASH_FUNCTION)
+ {
+ hashp->hash = info->hash;
+ }
+ else
+ {
+ /* default */
+ hashp->hash = string_hash;
+ }
+
+ if (flags & HASH_SHARED_MEM)
+ {
+ /* ctl structure is preallocated for shared memory tables */
+
+ hashp->hctl = (HHDR *) info->hctl;
+ hashp->segbase = (char *) info->segbase;
+ hashp->alloc = info->alloc;
+ hashp->dir = (SEG_OFFSET *) info->dir;
+
+ /* hash table already exists, we're just attaching to it */
+ if (flags & HASH_ATTACH)
+ {
+ return (hashp);
+ }
+
+ }
+ else
+ {
+ /* setup hash table defaults */
+
+ hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
+ hashp->dir = NULL;
+ hashp->segbase = NULL;
+
}
-
- } else {
- /* setup hash table defaults */
-
- hashp->alloc = (dhalloc_ptr) MEM_ALLOC;
- hashp->dir = NULL;
- hashp->segbase = NULL;
-
- }
-
- if (! hashp->hctl) {
- hashp->hctl = (HHDR *) hashp->alloc((unsigned long)sizeof(HHDR));
- if (! hashp->hctl) {
- return(0);
+
+ if (!hashp->hctl)
+ {
+ hashp->hctl = (HHDR *) hashp->alloc((unsigned long) sizeof(HHDR));
+ if (!hashp->hctl)
+ {
+ return (0);
+ }
}
- }
-
- if ( !hdefault(hashp) ) return(0);
- hctl = hashp->hctl;
+
+ if (!hdefault(hashp))
+ return (0);
+ hctl = hashp->hctl;
#ifdef HASH_STATISTICS
- hctl->accesses = hctl->collisions = 0;
+ hctl->accesses = hctl->collisions = 0;
#endif
-
- if ( flags & HASH_BUCKET ) {
- hctl->bsize = info->bsize;
- hctl->bshift = my_log2(info->bsize);
- }
- if ( flags & HASH_SEGMENT ) {
- hctl->ssize = info->ssize;
- hctl->sshift = my_log2(info->ssize);
- }
- if ( flags & HASH_FFACTOR ) {
- hctl->ffactor = info->ffactor;
- }
-
- /*
- * SHM hash tables have fixed maximum size (allocate
- * a maximal sized directory).
- */
- if ( flags & HASH_DIRSIZE ) {
- hctl->max_dsize = my_log2(info->max_size);
- hctl->dsize = my_log2(info->dsize);
- }
- /* hash table now allocates space for key and data
- * but you have to say how much space to allocate
- */
- if ( flags & HASH_ELEM ) {
- hctl->keysize = info->keysize;
- hctl->datasize = info->datasize;
- }
- if ( flags & HASH_ALLOC ) {
- hashp->alloc = info->alloc;
- }
-
- if ( init_htab (hashp, nelem ) ) {
- hash_destroy(hashp);
- return(0);
- }
- return(hashp);
+
+ if (flags & HASH_BUCKET)
+ {
+ hctl->bsize = info->bsize;
+ hctl->bshift = my_log2(info->bsize);
+ }
+ if (flags & HASH_SEGMENT)
+ {
+ hctl->ssize = info->ssize;
+ hctl->sshift = my_log2(info->ssize);
+ }
+ if (flags & HASH_FFACTOR)
+ {
+ hctl->ffactor = info->ffactor;
+ }
+
+ /*
+ * SHM hash tables have fixed maximum size (allocate a maximal sized
+ * directory).
+ */
+ if (flags & HASH_DIRSIZE)
+ {
+ hctl->max_dsize = my_log2(info->max_size);
+ hctl->dsize = my_log2(info->dsize);
+ }
+
+ /*
+ * hash table now allocates space for key and data but you have to say
+ * how much space to allocate
+ */
+ if (flags & HASH_ELEM)
+ {
+ hctl->keysize = info->keysize;
+ hctl->datasize = info->datasize;
+ }
+ if (flags & HASH_ALLOC)
+ {
+ hashp->alloc = info->alloc;
+ }
+
+ if (init_htab(hashp, nelem))
+ {
+ hash_destroy(hashp);
+ return (0);
+ }
+ return (hashp);
}
/*
- Allocate and initialize an HTAB structure
+ Allocate and initialize an HTAB structure
*/
static int
-hdefault(HTAB *hashp)
+hdefault(HTAB * hashp)
{
- HHDR *hctl;
-
- memset(hashp->hctl, 0, sizeof(HHDR));
-
- hctl = hashp->hctl;
- hctl->bsize = DEF_BUCKET_SIZE;
- hctl->bshift = DEF_BUCKET_SHIFT;
- hctl->ssize = DEF_SEGSIZE;
- hctl->sshift = DEF_SEGSIZE_SHIFT;
- hctl->dsize = DEF_DIRSIZE;
- hctl->ffactor = DEF_FFACTOR;
- hctl->nkeys = 0;
- hctl->nsegs = 0;
-
- /* I added these MS. */
-
- /* default memory allocation for hash buckets */
- hctl->keysize = sizeof(char *);
- hctl->datasize = sizeof(char *);
-
- /* table has no fixed maximum size */
- hctl->max_dsize = NO_MAX_DSIZE;
-
- /* garbage collection for HASH_REMOVE */
- hctl->freeBucketIndex = INVALID_INDEX;
-
- return(1);
+ HHDR *hctl;
+
+ memset(hashp->hctl, 0, sizeof(HHDR));
+
+ hctl = hashp->hctl;
+ hctl->bsize = DEF_BUCKET_SIZE;
+ hctl->bshift = DEF_BUCKET_SHIFT;
+ hctl->ssize = DEF_SEGSIZE;
+ hctl->sshift = DEF_SEGSIZE_SHIFT;
+ hctl->dsize = DEF_DIRSIZE;
+ hctl->ffactor = DEF_FFACTOR;
+ hctl->nkeys = 0;
+ hctl->nsegs = 0;
+
+ /* I added these MS. */
+
+ /* default memory allocation for hash buckets */
+ hctl->keysize = sizeof(char *);
+ hctl->datasize = sizeof(char *);
+
+ /* table has no fixed maximum size */
+ hctl->max_dsize = NO_MAX_DSIZE;
+
+ /* garbage collection for HASH_REMOVE */
+ hctl->freeBucketIndex = INVALID_INDEX;
+
+ return (1);
}
static int
-init_htab (HTAB *hashp, int nelem)
+init_htab(HTAB * hashp, int nelem)
{
- register SEG_OFFSET *segp;
- register int nbuckets;
- register int nsegs;
- int l2;
- HHDR *hctl;
-
- hctl = hashp->hctl;
- /*
- * Divide number of elements by the fill factor and determine a desired
- * number of buckets. Allocate space for the next greater power of
- * two number of buckets
- */
- nelem = (nelem - 1) / hctl->ffactor + 1;
-
- l2 = my_log2(nelem);
- nbuckets = 1 << l2;
-
- hctl->max_bucket = hctl->low_mask = nbuckets - 1;
- hctl->high_mask = (nbuckets << 1) - 1;
-
- nsegs = (nbuckets - 1) / hctl->ssize + 1;
- nsegs = 1 << my_log2(nsegs);
-
- if ( nsegs > hctl->dsize ) {
- hctl->dsize = nsegs;
- }
-
- /* Use two low order bits of points ???? */
- /*
- if ( !(hctl->mem = bit_alloc ( nbuckets )) ) return(-1);
- if ( !(hctl->mod = bit_alloc ( nbuckets )) ) return(-1);
- */
-
- /* allocate a directory */
- if (!(hashp->dir)) {
- hashp->dir =
- (SEG_OFFSET *)hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
- if (! hashp->dir)
- return(-1);
- }
-
- /* Allocate initial segments */
- for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++ ) {
- *segp = seg_alloc(hashp);
- if ( *segp == (SEG_OFFSET)0 ) {
- hash_destroy(hashp);
- return (0);
+ register SEG_OFFSET *segp;
+ register int nbuckets;
+ register int nsegs;
+ int l2;
+ HHDR *hctl;
+
+ hctl = hashp->hctl;
+
+ /*
+ * Divide number of elements by the fill factor and determine a
+ * desired number of buckets. Allocate space for the next greater
+ * power of two number of buckets
+ */
+ nelem = (nelem - 1) / hctl->ffactor + 1;
+
+ l2 = my_log2(nelem);
+ nbuckets = 1 << l2;
+
+ hctl->max_bucket = hctl->low_mask = nbuckets - 1;
+ hctl->high_mask = (nbuckets << 1) - 1;
+
+ nsegs = (nbuckets - 1) / hctl->ssize + 1;
+ nsegs = 1 << my_log2(nsegs);
+
+ if (nsegs > hctl->dsize)
+ {
+ hctl->dsize = nsegs;
+ }
+
+ /* Use two low order bits of points ???? */
+
+ /*
+ * if ( !(hctl->mem = bit_alloc ( nbuckets )) ) return(-1); if (
+ * !(hctl->mod = bit_alloc ( nbuckets )) ) return(-1);
+ */
+
+ /* allocate a directory */
+ if (!(hashp->dir))
+ {
+ hashp->dir =
+ (SEG_OFFSET *) hashp->alloc(hctl->dsize * sizeof(SEG_OFFSET));
+ if (!hashp->dir)
+ return (-1);
+ }
+
+ /* Allocate initial segments */
+ for (segp = hashp->dir; hctl->nsegs < nsegs; hctl->nsegs++, segp++)
+ {
+ *segp = seg_alloc(hashp);
+ if (*segp == (SEG_OFFSET) 0)
+ {
+ hash_destroy(hashp);
+ return (0);
+ }
}
- }
-
-# if HASH_DEBUG
- fprintf(stderr, "%s\n%s%x\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
- "init_htab:",
- "TABLE POINTER ", hashp,
- "BUCKET SIZE ", hctl->bsize,
- "BUCKET SHIFT ", hctl->bshift,
- "DIRECTORY SIZE ", hctl->dsize,
- "SEGMENT SIZE ", hctl->ssize,
- "SEGMENT SHIFT ", hctl->sshift,
- "FILL FACTOR ", hctl->ffactor,
- "MAX BUCKET ", hctl->max_bucket,
- "HIGH MASK ", hctl->high_mask,
- "LOW MASK ", hctl->low_mask,
- "NSEGS ", hctl->nsegs,
- "NKEYS ", hctl->nkeys );
-# endif
- return (0);
+
+#if HASH_DEBUG
+ fprintf(stderr, "%s\n%s%x\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
+ "init_htab:",
+ "TABLE POINTER ", hashp,
+ "BUCKET SIZE ", hctl->bsize,
+ "BUCKET SHIFT ", hctl->bshift,
+ "DIRECTORY SIZE ", hctl->dsize,
+ "SEGMENT SIZE ", hctl->ssize,
+ "SEGMENT SHIFT ", hctl->sshift,
+ "FILL FACTOR ", hctl->ffactor,
+ "MAX BUCKET ", hctl->max_bucket,
+ "HIGH MASK ", hctl->high_mask,
+ "LOW MASK ", hctl->low_mask,
+ "NSEGS ", hctl->nsegs,
+ "NKEYS ", hctl->nkeys);
+#endif
+ return (0);
}
/********************** DESTROY ROUTINES ************************/
void
-hash_destroy (HTAB *hashp)
+hash_destroy(HTAB * hashp)
{
- /* cannot destroy a shared memory hash table */
- Assert(! hashp->segbase);
-
- if (hashp != NULL) {
- register SEG_OFFSET segNum;
- SEGMENT segp;
- int nsegs = hashp->hctl->nsegs;
- int j;
- BUCKET_INDEX *elp,p,q;
- ELEMENT *curr;
-
- for (segNum = 0; nsegs > 0; nsegs--, segNum++) {
-
- segp = GET_SEG(hashp,segNum);
- for (j = 0, elp = segp; j < hashp->hctl->ssize; j++, elp++) {
- for ( p = *elp; p != INVALID_INDEX; p = q ){
- curr = GET_BUCKET(hashp,p);
- q = curr->next;
- MEM_FREE((char *) curr);
+ /* cannot destroy a shared memory hash table */
+ Assert(!hashp->segbase);
+
+ if (hashp != NULL)
+ {
+ register SEG_OFFSET segNum;
+ SEGMENT segp;
+ int nsegs = hashp->hctl->nsegs;
+ int j;
+ BUCKET_INDEX *elp,
+ p,
+ q;
+ ELEMENT *curr;
+
+ for (segNum = 0; nsegs > 0; nsegs--, segNum++)
+ {
+
+ segp = GET_SEG(hashp, segNum);
+ for (j = 0, elp = segp; j < hashp->hctl->ssize; j++, elp++)
+ {
+ for (p = *elp; p != INVALID_INDEX; p = q)
+ {
+ curr = GET_BUCKET(hashp, p);
+ q = curr->next;
+ MEM_FREE((char *) curr);
+ }
+ }
+ free((char *) segp);
}
- }
- free((char *)segp);
+ MEM_FREE((char *) hashp->dir);
+ MEM_FREE((char *) hashp->hctl);
+ hash_stats("destroy", hashp);
+ MEM_FREE((char *) hashp);
}
- MEM_FREE( (char *) hashp->dir);
- MEM_FREE( (char *) hashp->hctl);
- hash_stats("destroy",hashp);
- MEM_FREE( (char *) hashp);
- }
}
void
-hash_stats(char *where, HTAB *hashp)
+hash_stats(char *where, HTAB * hashp)
{
-# if HASH_STATISTICS
-
- fprintf(stderr,"%s: this HTAB -- accesses %ld collisions %ld\n",
- where,hashp->hctl->accesses,hashp->hctl->collisions);
-
- fprintf(stderr,"hash_stats: keys %ld keysize %ld maxp %d segmentcount %d\n",
- hashp->hctl->nkeys, hashp->hctl->keysize,
- hashp->hctl->max_bucket, hashp->hctl->nsegs);
- fprintf(stderr,"%s: total accesses %ld total collisions %ld\n",
- where, hash_accesses, hash_collisions);
- fprintf(stderr,"hash_stats: total expansions %ld\n",
- hash_expansions);
-
-# endif
-
+#if HASH_STATISTICS
+
+ fprintf(stderr, "%s: this HTAB -- accesses %ld collisions %ld\n",
+ where, hashp->hctl->accesses, hashp->hctl->collisions);
+
+ fprintf(stderr, "hash_stats: keys %ld keysize %ld maxp %d segmentcount %d\n",
+ hashp->hctl->nkeys, hashp->hctl->keysize,
+ hashp->hctl->max_bucket, hashp->hctl->nsegs);
+ fprintf(stderr, "%s: total accesses %ld total collisions %ld\n",
+ where, hash_accesses, hash_collisions);
+ fprintf(stderr, "hash_stats: total expansions %ld\n",
+ hash_expansions);
+
+#endif
+
}
/*******************************SEARCH ROUTINES *****************************/
-static uint32
-call_hash(HTAB *hashp, char *k, int len)
+static uint32
+call_hash(HTAB * hashp, char *k, int len)
{
- long hash_val, bucket;
- HHDR *hctl;
-
- hctl = hashp->hctl;
- hash_val = hashp->hash(k, len);
-
- bucket = hash_val & hctl->high_mask;
- if ( bucket > hctl->max_bucket ) {
- bucket = bucket & hctl->low_mask;
- }
-
- return(bucket);
+ long hash_val,
+ bucket;
+ HHDR *hctl;
+
+ hctl = hashp->hctl;
+ hash_val = hashp->hash(k, len);
+
+ bucket = hash_val & hctl->high_mask;
+ if (bucket > hctl->max_bucket)
+ {
+ bucket = bucket & hctl->low_mask;
+ }
+
+ return (bucket);
}
/*
@@ -429,430 +465,462 @@ call_hash(HTAB *hashp, char *k, int len)
* action is one of HASH_FIND/HASH_ENTER/HASH_REMOVE
*
* RETURNS: NULL if table is corrupted, a pointer to the element
- * found/removed/entered if applicable, TRUE otherwise.
- * foundPtr is TRUE if we found an element in the table
- * (FALSE if we entered one).
+ * found/removed/entered if applicable, TRUE otherwise.
+ * foundPtr is TRUE if we found an element in the table
+ * (FALSE if we entered one).
*/
-long *
-hash_search(HTAB *hashp,
- char *keyPtr,
- HASHACTION action, /*
- * HASH_FIND / HASH_ENTER / HASH_REMOVE
- * HASH_FIND_SAVE / HASH_REMOVE_SAVED
- */
- bool *foundPtr)
+long *
+hash_search(HTAB * hashp,
+ char *keyPtr,
+ HASHACTION action, /* HASH_FIND / HASH_ENTER / HASH_REMOVE
+ * HASH_FIND_SAVE / HASH_REMOVE_SAVED */
+ bool * foundPtr)
{
- uint32 bucket;
- long segment_num;
- long segment_ndx;
- SEGMENT segp;
- register ELEMENT *curr;
- HHDR *hctl;
- BUCKET_INDEX currIndex;
- BUCKET_INDEX *prevIndexPtr;
- char * destAddr;
- static struct State {
- ELEMENT *currElem;
- BUCKET_INDEX currIndex;
- BUCKET_INDEX *prevIndex;
- } saveState;
-
- Assert((hashp && keyPtr));
- Assert((action == HASH_FIND) || (action == HASH_REMOVE) || (action == HASH_ENTER) || (action == HASH_FIND_SAVE) || (action == HASH_REMOVE_SAVED));
-
- hctl = hashp->hctl;
-
-# if HASH_STATISTICS
- hash_accesses++;
- hashp->hctl->accesses++;
-# endif
- if (action == HASH_REMOVE_SAVED)
- {
- curr = saveState.currElem;
- currIndex = saveState.currIndex;
- prevIndexPtr = saveState.prevIndex;
- /*
- * Try to catch subsequent errors
- */
- Assert(saveState.currElem && !(saveState.currElem = 0));
+ uint32 bucket;
+ long segment_num;
+ long segment_ndx;
+ SEGMENT segp;
+ register ELEMENT *curr;
+ HHDR *hctl;
+ BUCKET_INDEX currIndex;
+ BUCKET_INDEX *prevIndexPtr;
+ char *destAddr;
+ static struct State
+ {
+ ELEMENT *currElem;
+ BUCKET_INDEX currIndex;
+ BUCKET_INDEX *prevIndex;
+ } saveState;
+
+ Assert((hashp && keyPtr));
+ Assert((action == HASH_FIND) || (action == HASH_REMOVE) || (action == HASH_ENTER) || (action == HASH_FIND_SAVE) || (action == HASH_REMOVE_SAVED));
+
+ hctl = hashp->hctl;
+
+#if HASH_STATISTICS
+ hash_accesses++;
+ hashp->hctl->accesses++;
+#endif
+ if (action == HASH_REMOVE_SAVED)
+ {
+ curr = saveState.currElem;
+ currIndex = saveState.currIndex;
+ prevIndexPtr = saveState.prevIndex;
+
+ /*
+ * Try to catch subsequent errors
+ */
+ Assert(saveState.currElem && !(saveState.currElem = 0));
}
- else
- {
- bucket = call_hash(hashp, keyPtr, hctl->keysize);
- segment_num = bucket >> hctl->sshift;
- segment_ndx = bucket & ( hctl->ssize - 1 );
-
- segp = GET_SEG(hashp,segment_num);
-
- Assert(segp);
-
- prevIndexPtr = &segp[segment_ndx];
- currIndex = *prevIndexPtr;
- /*
- * Follow collision chain
- */
- for (curr = NULL;currIndex != INVALID_INDEX;) {
- /* coerce bucket index into a pointer */
- curr = GET_BUCKET(hashp,currIndex);
-
- if (! memcmp((char *)&(curr->key), keyPtr, hctl->keysize)) {
- break;
- }
- prevIndexPtr = &(curr->next);
+ else
+ {
+ bucket = call_hash(hashp, keyPtr, hctl->keysize);
+ segment_num = bucket >> hctl->sshift;
+ segment_ndx = bucket & (hctl->ssize - 1);
+
+ segp = GET_SEG(hashp, segment_num);
+
+ Assert(segp);
+
+ prevIndexPtr = &segp[segment_ndx];
currIndex = *prevIndexPtr;
-# if HASH_STATISTICS
- hash_collisions++;
- hashp->hctl->collisions++;
-# endif
- }
- }
-
- /*
- * if we found an entry or if we weren't trying
- * to insert, we're done now.
- */
- *foundPtr = (bool) (currIndex != INVALID_INDEX);
- switch (action) {
- case HASH_ENTER:
- if (currIndex != INVALID_INDEX)
- return(&(curr->key));
- break;
- case HASH_REMOVE:
- case HASH_REMOVE_SAVED:
- if (currIndex != INVALID_INDEX) {
- Assert(hctl->nkeys > 0);
- hctl->nkeys--;
-
- /* add the bucket to the freelist for this table. */
- *prevIndexPtr = curr->next;
- curr->next = hctl->freeBucketIndex;
- hctl->freeBucketIndex = currIndex;
-
- /* better hope the caller is synchronizing access to
- * this element, because someone else is going to reuse
- * it the next time something is added to the table
- */
- return (&(curr->key));
+
+ /*
+ * Follow collision chain
+ */
+ for (curr = NULL; currIndex != INVALID_INDEX;)
+ {
+ /* coerce bucket index into a pointer */
+ curr = GET_BUCKET(hashp, currIndex);
+
+ if (!memcmp((char *) &(curr->key), keyPtr, hctl->keysize))
+ {
+ break;
+ }
+ prevIndexPtr = &(curr->next);
+ currIndex = *prevIndexPtr;
+#if HASH_STATISTICS
+ hash_collisions++;
+ hashp->hctl->collisions++;
+#endif
+ }
}
- return((long *) TRUE);
- case HASH_FIND:
- if (currIndex != INVALID_INDEX)
- return(&(curr->key));
- return((long *)TRUE);
- case HASH_FIND_SAVE:
- if (currIndex != INVALID_INDEX)
- {
- saveState.currElem = curr;
- saveState.prevIndex = prevIndexPtr;
- saveState.currIndex = currIndex;
- return(&(curr->key));
- }
- return((long *)TRUE);
- default:
- /* can't get here */
- return (NULL);
- }
-
- /*
- If we got here, then we didn't find the element and
- we have to insert it into the hash table
- */
- Assert(currIndex == INVALID_INDEX);
-
- /* get the next free bucket */
- currIndex = hctl->freeBucketIndex;
- if (currIndex == INVALID_INDEX) {
-
- /* no free elements. allocate another chunk of buckets */
- if (! bucket_alloc(hashp)) {
- return(NULL);
+
+ /*
+ * if we found an entry or if we weren't trying to insert, we're done
+ * now.
+ */
+ *foundPtr = (bool) (currIndex != INVALID_INDEX);
+ switch (action)
+ {
+ case HASH_ENTER:
+ if (currIndex != INVALID_INDEX)
+ return (&(curr->key));
+ break;
+ case HASH_REMOVE:
+ case HASH_REMOVE_SAVED:
+ if (currIndex != INVALID_INDEX)
+ {
+ Assert(hctl->nkeys > 0);
+ hctl->nkeys--;
+
+ /* add the bucket to the freelist for this table. */
+ *prevIndexPtr = curr->next;
+ curr->next = hctl->freeBucketIndex;
+ hctl->freeBucketIndex = currIndex;
+
+ /*
+ * better hope the caller is synchronizing access to this
+ * element, because someone else is going to reuse it the next
+ * time something is added to the table
+ */
+ return (&(curr->key));
+ }
+ return ((long *) TRUE);
+ case HASH_FIND:
+ if (currIndex != INVALID_INDEX)
+ return (&(curr->key));
+ return ((long *) TRUE);
+ case HASH_FIND_SAVE:
+ if (currIndex != INVALID_INDEX)
+ {
+ saveState.currElem = curr;
+ saveState.prevIndex = prevIndexPtr;
+ saveState.currIndex = currIndex;
+ return (&(curr->key));
+ }
+ return ((long *) TRUE);
+ default:
+ /* can't get here */
+ return (NULL);
}
+
+ /*
+ * If we got here, then we didn't find the element and we have to
+ * insert it into the hash table
+ */
+ Assert(currIndex == INVALID_INDEX);
+
+ /* get the next free bucket */
currIndex = hctl->freeBucketIndex;
- }
- Assert(currIndex != INVALID_INDEX);
-
- curr = GET_BUCKET(hashp,currIndex);
- hctl->freeBucketIndex = curr->next;
-
- /* link into chain */
- *prevIndexPtr = currIndex;
-
- /* copy key and data */
- destAddr = (char *) &(curr->key);
- memmove(destAddr,keyPtr,hctl->keysize);
- curr->next = INVALID_INDEX;
-
- /* let the caller initialize the data field after
- * hash_search returns.
- */
- /* memmove(destAddr,keyPtr,hctl->keysize+hctl->datasize);*/
-
- /*
- * Check if it is time to split the segment
- */
- if (++hctl->nkeys / (hctl->max_bucket+1) > hctl->ffactor) {
+ if (currIndex == INVALID_INDEX)
+ {
+
+ /* no free elements. allocate another chunk of buckets */
+ if (!bucket_alloc(hashp))
+ {
+ return (NULL);
+ }
+ currIndex = hctl->freeBucketIndex;
+ }
+ Assert(currIndex != INVALID_INDEX);
+
+ curr = GET_BUCKET(hashp, currIndex);
+ hctl->freeBucketIndex = curr->next;
+
+ /* link into chain */
+ *prevIndexPtr = currIndex;
+
+ /* copy key and data */
+ destAddr = (char *) &(curr->key);
+ memmove(destAddr, keyPtr, hctl->keysize);
+ curr->next = INVALID_INDEX;
+
/*
- fprintf(stderr,"expanding on '%s'\n",keyPtr);
- hash_stats("expanded table",hashp);
- */
- if (! expand_table(hashp))
- return(NULL);
- }
- return (&(curr->key));
+ * let the caller initialize the data field after hash_search returns.
+ */
+ /* memmove(destAddr,keyPtr,hctl->keysize+hctl->datasize); */
+
+ /*
+ * Check if it is time to split the segment
+ */
+ if (++hctl->nkeys / (hctl->max_bucket + 1) > hctl->ffactor)
+ {
+
+ /*
+ * fprintf(stderr,"expanding on '%s'\n",keyPtr);
+ * hash_stats("expanded table",hashp);
+ */
+ if (!expand_table(hashp))
+ return (NULL);
+ }
+ return (&(curr->key));
}
/*
* hash_seq -- sequentially search through hash table and return
- * all the elements one by one, return NULL on error and
- * return TRUE in the end.
+ * all the elements one by one, return NULL on error and
+ * return TRUE in the end.
*
*/
-long *
-hash_seq(HTAB *hashp)
+long *
+hash_seq(HTAB * hashp)
{
- static uint32 curBucket = 0;
- static BUCKET_INDEX curIndex;
- ELEMENT *curElem;
- long segment_num;
- long segment_ndx;
- SEGMENT segp;
- HHDR *hctl;
-
- if (hashp == NULL)
- {
- /*
- * reset static state
- */
- curBucket = 0;
- curIndex = INVALID_INDEX;
- return((long *) NULL);
+ static uint32 curBucket = 0;
+ static BUCKET_INDEX curIndex;
+ ELEMENT *curElem;
+ long segment_num;
+ long segment_ndx;
+ SEGMENT segp;
+ HHDR *hctl;
+
+ if (hashp == NULL)
+ {
+
+ /*
+ * reset static state
+ */
+ curBucket = 0;
+ curIndex = INVALID_INDEX;
+ return ((long *) NULL);
}
-
- hctl = hashp->hctl;
- while (curBucket <= hctl->max_bucket) {
- if (curIndex != INVALID_INDEX) {
- curElem = GET_BUCKET(hashp, curIndex);
- curIndex = curElem->next;
- if (curIndex == INVALID_INDEX) /* end of this bucket */
- ++curBucket;
- return(&(curElem->key));
+
+ hctl = hashp->hctl;
+ while (curBucket <= hctl->max_bucket)
+ {
+ if (curIndex != INVALID_INDEX)
+ {
+ curElem = GET_BUCKET(hashp, curIndex);
+ curIndex = curElem->next;
+ if (curIndex == INVALID_INDEX) /* end of this bucket */
+ ++curBucket;
+ return (&(curElem->key));
+ }
+
+ /*
+ * initialize the search within this bucket.
+ */
+ segment_num = curBucket >> hctl->sshift;
+ segment_ndx = curBucket & (hctl->ssize - 1);
+
+ /*
+ * first find the right segment in the table directory.
+ */
+ segp = GET_SEG(hashp, segment_num);
+ if (segp == NULL)
+ /* this is probably an error */
+ return ((long *) NULL);
+
+ /*
+ * now find the right index into the segment for the first item in
+ * this bucket's chain. if the bucket is not empty (its entry in
+ * the dir is valid), we know this must correspond to a valid
+ * element and not a freed element because it came out of the
+ * directory of valid stuff. if there are elements in the bucket
+ * chains that point to the freelist we're in big trouble.
+ */
+ curIndex = segp[segment_ndx];
+
+ if (curIndex == INVALID_INDEX) /* empty bucket */
+ ++curBucket;
}
-
- /*
- * initialize the search within this bucket.
- */
- segment_num = curBucket >> hctl->sshift;
- segment_ndx = curBucket & ( hctl->ssize - 1 );
-
- /*
- * first find the right segment in the table directory.
- */
- segp = GET_SEG(hashp, segment_num);
- if (segp == NULL)
- /* this is probably an error */
- return((long *) NULL);
-
- /*
- * now find the right index into the segment for the first
- * item in this bucket's chain. if the bucket is not empty
- * (its entry in the dir is valid), we know this must
- * correspond to a valid element and not a freed element
- * because it came out of the directory of valid stuff. if
- * there are elements in the bucket chains that point to the
- * freelist we're in big trouble.
- */
- curIndex = segp[segment_ndx];
-
- if (curIndex == INVALID_INDEX) /* empty bucket */
- ++curBucket;
- }
-
- return((long *) TRUE); /* out of buckets */
+
+ return ((long *) TRUE); /* out of buckets */
}
/********************************* UTILITIES ************************/
static int
-expand_table(HTAB *hashp)
+expand_table(HTAB * hashp)
{
- HHDR *hctl;
- SEGMENT old_seg,new_seg;
- long old_bucket, new_bucket;
- long new_segnum, new_segndx;
- long old_segnum, old_segndx;
- ELEMENT *chain;
- BUCKET_INDEX *old,*newbi;
- register BUCKET_INDEX chainIndex,nextIndex;
-
+ HHDR *hctl;
+ SEGMENT old_seg,
+ new_seg;
+ long old_bucket,
+ new_bucket;
+ long new_segnum,
+ new_segndx;
+ long old_segnum,
+ old_segndx;
+ ELEMENT *chain;
+ BUCKET_INDEX *old,
+ *newbi;
+ register BUCKET_INDEX chainIndex,
+ nextIndex;
+
#ifdef HASH_STATISTICS
- hash_expansions++;
+ hash_expansions++;
#endif
-
- hctl = hashp->hctl;
- new_bucket = ++hctl->max_bucket;
- old_bucket = (hctl->max_bucket & hctl->low_mask);
-
- new_segnum = new_bucket >> hctl->sshift;
- new_segndx = MOD ( new_bucket, hctl->ssize );
-
- if ( new_segnum >= hctl->nsegs ) {
-
- /* Allocate new segment if necessary */
- if (new_segnum >= hctl->dsize) {
- dir_realloc(hashp);
+
+ hctl = hashp->hctl;
+ new_bucket = ++hctl->max_bucket;
+ old_bucket = (hctl->max_bucket & hctl->low_mask);
+
+ new_segnum = new_bucket >> hctl->sshift;
+ new_segndx = MOD(new_bucket, hctl->ssize);
+
+ if (new_segnum >= hctl->nsegs)
+ {
+
+ /* Allocate new segment if necessary */
+ if (new_segnum >= hctl->dsize)
+ {
+ dir_realloc(hashp);
+ }
+ if (!(hashp->dir[new_segnum] = seg_alloc(hashp)))
+ {
+ return (0);
+ }
+ hctl->nsegs++;
}
- if (! (hashp->dir[new_segnum] = seg_alloc(hashp))) {
- return (0);
+
+
+ if (new_bucket > hctl->high_mask)
+ {
+ /* Starting a new doubling */
+ hctl->low_mask = hctl->high_mask;
+ hctl->high_mask = new_bucket | hctl->low_mask;
}
- hctl->nsegs++;
- }
-
-
- if ( new_bucket > hctl->high_mask ) {
- /* Starting a new doubling */
- hctl->low_mask = hctl->high_mask;
- hctl->high_mask = new_bucket | hctl->low_mask;
- }
-
- /*
- * Relocate records to the new bucket
- */
- old_segnum = old_bucket >> hctl->sshift;
- old_segndx = MOD(old_bucket, hctl->ssize);
-
- old_seg = GET_SEG(hashp,old_segnum);
- new_seg = GET_SEG(hashp,new_segnum);
-
- old = &old_seg[old_segndx];
- newbi = &new_seg[new_segndx];
- for (chainIndex = *old;
- chainIndex != INVALID_INDEX;
- chainIndex = nextIndex){
-
- chain = GET_BUCKET(hashp,chainIndex);
- nextIndex = chain->next;
- if ( call_hash(hashp,
- (char *)&(chain->key),
- hctl->keysize) == old_bucket ) {
- *old = chainIndex;
- old = &chain->next;
- } else {
- *newbi = chainIndex;
- newbi = &chain->next;
+
+ /*
+ * Relocate records to the new bucket
+ */
+ old_segnum = old_bucket >> hctl->sshift;
+ old_segndx = MOD(old_bucket, hctl->ssize);
+
+ old_seg = GET_SEG(hashp, old_segnum);
+ new_seg = GET_SEG(hashp, new_segnum);
+
+ old = &old_seg[old_segndx];
+ newbi = &new_seg[new_segndx];
+ for (chainIndex = *old;
+ chainIndex != INVALID_INDEX;
+ chainIndex = nextIndex)
+ {
+
+ chain = GET_BUCKET(hashp, chainIndex);
+ nextIndex = chain->next;
+ if (call_hash(hashp,
+ (char *) &(chain->key),
+ hctl->keysize) == old_bucket)
+ {
+ *old = chainIndex;
+ old = &chain->next;
+ }
+ else
+ {
+ *newbi = chainIndex;
+ newbi = &chain->next;
+ }
+ chain->next = INVALID_INDEX;
}
- chain->next = INVALID_INDEX;
- }
- return (1);
+ return (1);
}
static int
-dir_realloc(HTAB *hashp)
+dir_realloc(HTAB * hashp)
{
- register char *p;
- char **p_ptr;
- long old_dirsize;
- long new_dirsize;
-
-
- if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
+ register char *p;
+ char **p_ptr;
+ long old_dirsize;
+ long new_dirsize;
+
+
+ if (hashp->hctl->max_dsize != NO_MAX_DSIZE)
+ return (0);
+
+ /* Reallocate directory */
+ old_dirsize = hashp->hctl->dsize * sizeof(SEGMENT *);
+ new_dirsize = old_dirsize << 1;
+
+ p_ptr = (char **) hashp->dir;
+ p = (char *) hashp->alloc((unsigned long) new_dirsize);
+ if (p != NULL)
+ {
+ memmove(p, *p_ptr, old_dirsize);
+ memset(*p_ptr + old_dirsize, 0, new_dirsize - old_dirsize);
+ free((char *) *p_ptr);
+ *p_ptr = p;
+ hashp->hctl->dsize = new_dirsize;
+ return (1);
+ }
return (0);
-
- /* Reallocate directory */
- old_dirsize = hashp->hctl->dsize * sizeof ( SEGMENT * );
- new_dirsize = old_dirsize << 1;
-
- p_ptr = (char **) hashp->dir;
- p = (char *) hashp->alloc((unsigned long) new_dirsize );
- if (p != NULL) {
- memmove(p, *p_ptr, old_dirsize );
- memset ( *p_ptr + old_dirsize, 0, new_dirsize-old_dirsize );
- free( (char *)*p_ptr);
- *p_ptr = p;
- hashp->hctl->dsize = new_dirsize;
- return(1);
- }
- return (0);
-
+
}
-static SEG_OFFSET
+static SEG_OFFSET
seg_alloc(HTAB * hashp)
{
- SEGMENT segp;
- SEG_OFFSET segOffset;
-
-
- segp = (SEGMENT) hashp->alloc((unsigned long)
- sizeof(SEGMENT)*hashp->hctl->ssize);
-
- if (! segp) {
- return(0);
- }
-
- memset((char *)segp, 0,
- (long) sizeof(SEGMENT)*hashp->hctl->ssize);
-
- segOffset = MAKE_HASHOFFSET(hashp,segp);
- return(segOffset);
+ SEGMENT segp;
+ SEG_OFFSET segOffset;
+
+
+ segp = (SEGMENT) hashp->alloc((unsigned long)
+ sizeof(SEGMENT) * hashp->hctl->ssize);
+
+ if (!segp)
+ {
+ return (0);
+ }
+
+ memset((char *) segp, 0,
+ (long) sizeof(SEGMENT) * hashp->hctl->ssize);
+
+ segOffset = MAKE_HASHOFFSET(hashp, segp);
+ return (segOffset);
}
/*
* allocate some new buckets and link them into the free list
*/
static int
-bucket_alloc(HTAB *hashp)
+bucket_alloc(HTAB * hashp)
{
- int i;
- ELEMENT *tmpBucket;
- long bucketSize;
- BUCKET_INDEX tmpIndex,lastIndex;
-
- bucketSize =
- sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize;
-
- /* make sure its aligned correctly */
- bucketSize += sizeof(long *) - (bucketSize % sizeof(long *));
-
- /* tmpIndex is the shmem offset into the first bucket of
- * the array.
- */
- tmpBucket = (ELEMENT *)
- hashp->alloc((unsigned long) BUCKET_ALLOC_INCR*bucketSize);
-
- if (! tmpBucket) {
- return(0);
- }
-
- tmpIndex = MAKE_HASHOFFSET(hashp,tmpBucket);
-
- /* set the freebucket list to point to the first bucket */
- lastIndex = hashp->hctl->freeBucketIndex;
- hashp->hctl->freeBucketIndex = tmpIndex;
-
- /* initialize each bucket to point to the one behind it */
- for (i=0;i<(BUCKET_ALLOC_INCR-1);i++) {
- tmpBucket = GET_BUCKET(hashp,tmpIndex);
- tmpIndex += bucketSize;
- tmpBucket->next = tmpIndex;
- }
-
- /* the last bucket points to the old freelist head (which is
- * probably invalid or we wouldnt be here)
- */
- tmpBucket->next = lastIndex;
-
- return(1);
+ int i;
+ ELEMENT *tmpBucket;
+ long bucketSize;
+ BUCKET_INDEX tmpIndex,
+ lastIndex;
+
+ bucketSize =
+ sizeof(BUCKET_INDEX) + hashp->hctl->keysize + hashp->hctl->datasize;
+
+ /* make sure its aligned correctly */
+ bucketSize += sizeof(long *) - (bucketSize % sizeof(long *));
+
+ /*
+ * tmpIndex is the shmem offset into the first bucket of the array.
+ */
+ tmpBucket = (ELEMENT *)
+ hashp->alloc((unsigned long) BUCKET_ALLOC_INCR * bucketSize);
+
+ if (!tmpBucket)
+ {
+ return (0);
+ }
+
+ tmpIndex = MAKE_HASHOFFSET(hashp, tmpBucket);
+
+ /* set the freebucket list to point to the first bucket */
+ lastIndex = hashp->hctl->freeBucketIndex;
+ hashp->hctl->freeBucketIndex = tmpIndex;
+
+ /* initialize each bucket to point to the one behind it */
+ for (i = 0; i < (BUCKET_ALLOC_INCR - 1); i++)
+ {
+ tmpBucket = GET_BUCKET(hashp, tmpIndex);
+ tmpIndex += bucketSize;
+ tmpBucket->next = tmpIndex;
+ }
+
+ /*
+ * the last bucket points to the old freelist head (which is probably
+ * invalid or we wouldnt be here)
+ */
+ tmpBucket->next = lastIndex;
+
+ return (1);
}
/* calculate the log base 2 of num */
int
my_log2(long num)
{
- int i = 1;
- int limit;
-
- for ( i = 0, limit = 1; limit < num; limit = 2 * limit, i++ );
- return (i);
+ int i = 1;
+ int limit;
+
+ for (i = 0, limit = 1; limit < num; limit = 2 * limit, i++);
+ return (i);
}
diff --git a/src/backend/utils/hash/hashfn.c b/src/backend/utils/hash/hashfn.c
index 3b2f0ec19a9..f7b8f3fde6e 100644
--- a/src/backend/utils/hash/hashfn.c
+++ b/src/backend/utils/hash/hashfn.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* hashfn.c--
- *
+ *
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/hash/hashfn.c,v 1.3 1997/08/19 21:35:33 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/hash/hashfn.c,v 1.4 1997/09/07 04:53:38 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,96 +24,97 @@
long
string_hash(char *key, int keysize)
{
- int h;
- register unsigned char *k = (unsigned char *) key;
-
- h = 0;
- /*
- * Convert string to integer
- */
- while (*k)
- h = h * PRIME1 ^ (*k++ - ' ');
- h %= PRIME2;
-
- return (h);
+ int h;
+ register unsigned char *k = (unsigned char *) key;
+
+ h = 0;
+
+ /*
+ * Convert string to integer
+ */
+ while (*k)
+ h = h * PRIME1 ^ (*k++ - ' ');
+ h %= PRIME2;
+
+ return (h);
}
long
tag_hash(int *key, int keysize)
{
- register long h = 0;
-
- /*
- * Convert tag to integer; Use four byte chunks in a "jump table"
- * to go a little faster. Currently the maximum keysize is 16
- * (mar 17 1992) I have put in cases for up to 24. Bigger than
- * this will resort to the old behavior of the for loop. (see the
- * default case).
- */
- switch (keysize)
+ register long h = 0;
+
+ /*
+ * Convert tag to integer; Use four byte chunks in a "jump table" to
+ * go a little faster. Currently the maximum keysize is 16 (mar 17
+ * 1992) I have put in cases for up to 24. Bigger than this will
+ * resort to the old behavior of the for loop. (see the default case).
+ */
+ switch (keysize)
{
- case 6*sizeof(int):
- h = h * PRIME1 ^ (*key);
- key++;
- /* fall through */
-
- case 5*sizeof(int):
- h = h * PRIME1 ^ (*key);
- key++;
- /* fall through */
-
- case 4*sizeof(int):
- h = h * PRIME1 ^ (*key);
- key++;
- /* fall through */
-
- case 3*sizeof(int):
- h = h * PRIME1 ^ (*key);
- key++;
- /* fall through */
-
- case 2*sizeof(int):
- h = h * PRIME1 ^ (*key);
- key++;
- /* fall through */
-
+ case 6 * sizeof(int):
+ h = h * PRIME1 ^ (*key);
+ key++;
+ /* fall through */
+
+ case 5 * sizeof(int):
+ h = h * PRIME1 ^ (*key);
+ key++;
+ /* fall through */
+
+ case 4 * sizeof(int):
+ h = h * PRIME1 ^ (*key);
+ key++;
+ /* fall through */
+
+ case 3 * sizeof(int):
+ h = h * PRIME1 ^ (*key);
+ key++;
+ /* fall through */
+
+ case 2 * sizeof(int):
+ h = h * PRIME1 ^ (*key);
+ key++;
+ /* fall through */
+
case sizeof(int):
- h = h * PRIME1 ^ (*key);
- key++;
- break;
-
- default:
- for(; keysize > (sizeof(int)-1); keysize -= sizeof(int), key++)
h = h * PRIME1 ^ (*key);
- /*
- * now let's grab the last few bytes of the tag if the tag
- * has (size % 4) != 0 (which it sometimes will on a sun3).
- */
- if (keysize)
+ key++;
+ break;
+
+ default:
+ for (; keysize > (sizeof(int) - 1); keysize -= sizeof(int), key++)
+ h = h * PRIME1 ^ (*key);
+
+ /*
+ * now let's grab the last few bytes of the tag if the tag has
+ * (size % 4) != 0 (which it sometimes will on a sun3).
+ */
+ if (keysize)
{
- char *keytmp = (char *)key;
-
- switch (keysize)
+ char *keytmp = (char *) key;
+
+ switch (keysize)
{
case 3:
- h = h * PRIME1 ^ (*keytmp);
- keytmp++;
- /* fall through */
+ h = h * PRIME1 ^ (*keytmp);
+ keytmp++;
+ /* fall through */
case 2:
- h = h * PRIME1 ^ (*keytmp);
- keytmp++;
- /* fall through */
+ h = h * PRIME1 ^ (*keytmp);
+ keytmp++;
+ /* fall through */
case 1:
- h = h * PRIME1 ^ (*keytmp);
- break;
+ h = h * PRIME1 ^ (*keytmp);
+ break;
}
}
- break;
+ break;
}
-
- h %= PRIME2;
- return (h);
+
+ h %= PRIME2;
+ return (h);
}
/*
@@ -129,31 +130,42 @@ tag_hash(int *key, int keysize)
long
disk_hash(char *key)
{
- register int n = 0;
- register char *str = key;
- register int len = strlen(key);
- register int loop;
-
-#define HASHC n = *str++ + 65599 * n
-
- if (len > 0) {
- loop = (len + 8 - 1) >> 3;
-
- switch(len & (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);
+ register int n = 0;
+ register char *str = key;
+ register int len = strlen(key);
+ register int loop;
+
+#define HASHC n = *str++ + 65599 * n
+
+ if (len > 0)
+ {
+ loop = (len + 8 - 1) >> 3;
+
+ switch (len & (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);
}
-#endif
+#endif
diff --git a/src/backend/utils/init/enbl.c b/src/backend/utils/init/enbl.c
index 995ab9d9567..dfcf295e34c 100644
--- a/src/backend/utils/init/enbl.c
+++ b/src/backend/utils/init/enbl.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* enbl.c--
- * POSTGRES module enable and disable support code.
+ * POSTGRES module enable and disable support code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/enbl.c,v 1.1.1.1 1996/07/09 06:22:08 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/enbl.c,v 1.2 1997/09/07 04:53:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,15 +16,15 @@
/*
* BypassEnable --
- * False iff enable/disable processing is required given on and "*countP."
+ * False iff enable/disable processing is required given on and "*countP."
*
* Note:
- * As a side-effect, *countP is modified. It should be 0 initially.
+ * As a side-effect, *countP is modified. It should be 0 initially.
*
* Exceptions:
- * BadState if called with pointer to value 0 and false.
- * BadArg if "countP" is invalid pointer.
- * BadArg if on is invalid.
+ * BadState if called with pointer to value 0 and false.
+ * BadArg if "countP" is invalid pointer.
+ * BadArg if on is invalid.
*/
bool
BypassEnable(int *enableCountInOutP, bool on)
@@ -32,14 +32,15 @@ BypassEnable(int *enableCountInOutP, bool on)
AssertArg(PointerIsValid(enableCountInOutP));
AssertArg(BoolIsValid(on));
- if (on) {
+ if (on)
+ {
*enableCountInOutP += 1;
- return ((bool)(*enableCountInOutP >= 2));
+ return ((bool) (*enableCountInOutP >= 2));
}
AssertState(*enableCountInOutP >= 1);
*enableCountInOutP -= 1;
- return ((bool)(*enableCountInOutP >= 1));
+ return ((bool) (*enableCountInOutP >= 1));
}
diff --git a/src/backend/utils/init/findbe.c b/src/backend/utils/init/findbe.c
index 8718e3f91d6..5e6aa7412a6 100644
--- a/src/backend/utils/init/findbe.c
+++ b/src/backend/utils/init/findbe.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/findbe.c,v 1.5 1997/08/27 03:48:38 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/findbe.c,v 1.6 1997/09/07 04:53:45 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,213 +19,230 @@
#include <unistd.h>
#include "postgres.h"
-#include "miscadmin.h" /* for DebugLvl */
+#include "miscadmin.h" /* for DebugLvl */
-#ifndef S_IRUSR /* XXX [TRH] should be in a header */
-# define S_IRUSR S_IREAD
-# define S_IWUSR S_IWRITE
-# define S_IXUSR S_IEXEC
-# define S_IRGRP ((S_IRUSR)>>3)
-# define S_IWGRP ((S_IWUSR)>>3)
-# define S_IXGRP ((S_IXUSR)>>3)
-# define S_IROTH ((S_IRUSR)>>6)
-# define S_IWOTH ((S_IWUSR)>>6)
-# define S_IXOTH ((S_IXUSR)>>6)
+#ifndef S_IRUSR /* XXX [TRH] should be in a header */
+#define S_IRUSR S_IREAD
+#define S_IWUSR S_IWRITE
+#define S_IXUSR S_IEXEC
+#define S_IRGRP ((S_IRUSR)>>3)
+#define S_IWGRP ((S_IWUSR)>>3)
+#define S_IXGRP ((S_IXUSR)>>3)
+#define S_IROTH ((S_IRUSR)>>6)
+#define S_IWOTH ((S_IWUSR)>>6)
+#define S_IXOTH ((S_IXUSR)>>6)
#endif
/*
* ValidateBackend -- validate "path" as a POSTGRES executable file
*
* returns 0 if the file is found and no error is encountered.
- * -1 if the regular file "path" does not exist or cannot be executed.
- * -2 if the file is otherwise valid but cannot be read.
+ * -1 if the regular file "path" does not exist or cannot be executed.
+ * -2 if the file is otherwise valid but cannot be read.
*/
int
ValidateBackend(char *path)
{
- struct stat buf;
- uid_t euid;
- struct group *gp;
- struct passwd *pwp;
- int i;
- int is_r = 0;
- int is_x = 0;
- int in_grp = 0;
-
- /*
- * Ensure that the file exists and is a regular file.
- *
- * XXX if you have a broken system where stat() looks at the symlink
- * instead of the underlying file, you lose.
- */
- if (strlen(path) >= MAXPGPATH) {
- if (DebugLvl > 1)
- fprintf(stderr, "ValidateBackend: pathname \"%s\" is too long\n",
- path);
- return(-1);
- }
+ struct stat buf;
+ uid_t euid;
+ struct group *gp;
+ struct passwd *pwp;
+ int i;
+ int is_r = 0;
+ int is_x = 0;
+ int in_grp = 0;
- if (stat(path, &buf) < 0) {
- if (DebugLvl > 1)
- fprintf(stderr, "ValidateBackend: can't stat \"%s\"\n",
- path);
- return(-1);
- }
- if (!(buf.st_mode & S_IFREG)) {
- if (DebugLvl > 1)
- fprintf(stderr, "ValidateBackend: \"%s\" is not a regular file\n",
- path);
- return(-1);
- }
-
- /*
- * Ensure that we are using an authorized backend.
- *
- * XXX I'm open to suggestions here. I would like to enforce ownership
- * of backends by user "postgres" but people seem to like to run
- * as users other than "postgres"...
- */
-
- /*
- * Ensure that the file is both executable and readable (required for
- * dynamic loading).
- *
- * We use the effective uid here because the backend will not have
- * executed setuid() by the time it calls this routine.
- */
- euid = geteuid();
- if (euid == buf.st_uid) {
- is_r = buf.st_mode & S_IRUSR;
- is_x = buf.st_mode & S_IXUSR;
- if (DebugLvl > 1 && !(is_r && is_x))
- fprintf(stderr, "ValidateBackend: \"%s\" is not user read/execute\n",
- path);
- return(is_x ? (is_r ? 0 : -2) : -1);
- }
- pwp = getpwuid(euid);
- if (pwp) {
- if (pwp->pw_gid == buf.st_gid) {
- ++in_grp;
- } else if (pwp->pw_name &&
- (gp = getgrgid(buf.st_gid))) {
- for (i = 0; gp->gr_mem[i]; ++i) {
- if (!strcmp(gp->gr_mem[i], pwp->pw_name)) {
- ++in_grp;
- break;
- }
- }
+ /*
+ * Ensure that the file exists and is a regular file.
+ *
+ * XXX if you have a broken system where stat() looks at the symlink
+ * instead of the underlying file, you lose.
+ */
+ if (strlen(path) >= MAXPGPATH)
+ {
+ if (DebugLvl > 1)
+ fprintf(stderr, "ValidateBackend: pathname \"%s\" is too long\n",
+ path);
+ return (-1);
}
- if (in_grp) {
- is_r = buf.st_mode & S_IRGRP;
- is_x = buf.st_mode & S_IXGRP;
- if (DebugLvl > 1 && !(is_r && is_x))
- fprintf(stderr, "ValidateBackend: \"%s\" is not group read/execute\n",
- path);
- return(is_x ? (is_r ? 0 : -2) : -1);
+
+ if (stat(path, &buf) < 0)
+ {
+ if (DebugLvl > 1)
+ fprintf(stderr, "ValidateBackend: can't stat \"%s\"\n",
+ path);
+ return (-1);
}
- }
- is_r = buf.st_mode & S_IROTH;
- is_x = buf.st_mode & S_IXOTH;
- if (DebugLvl > 1 && !(is_r && is_x))
- fprintf(stderr, "ValidateBackend: \"%s\" is not other read/execute\n",
- path);
- return(is_x ? (is_r ? 0 : -2) : -1);
+ if (!(buf.st_mode & S_IFREG))
+ {
+ if (DebugLvl > 1)
+ fprintf(stderr, "ValidateBackend: \"%s\" is not a regular file\n",
+ path);
+ return (-1);
+ }
+
+ /*
+ * Ensure that we are using an authorized backend.
+ *
+ * XXX I'm open to suggestions here. I would like to enforce ownership
+ * of backends by user "postgres" but people seem to like to run as
+ * users other than "postgres"...
+ */
+
+ /*
+ * Ensure that the file is both executable and readable (required for
+ * dynamic loading).
+ *
+ * We use the effective uid here because the backend will not have
+ * executed setuid() by the time it calls this routine.
+ */
+ euid = geteuid();
+ if (euid == buf.st_uid)
+ {
+ is_r = buf.st_mode & S_IRUSR;
+ is_x = buf.st_mode & S_IXUSR;
+ if (DebugLvl > 1 && !(is_r && is_x))
+ fprintf(stderr, "ValidateBackend: \"%s\" is not user read/execute\n",
+ path);
+ return (is_x ? (is_r ? 0 : -2) : -1);
+ }
+ pwp = getpwuid(euid);
+ if (pwp)
+ {
+ if (pwp->pw_gid == buf.st_gid)
+ {
+ ++in_grp;
+ }
+ else if (pwp->pw_name &&
+ (gp = getgrgid(buf.st_gid)))
+ {
+ for (i = 0; gp->gr_mem[i]; ++i)
+ {
+ if (!strcmp(gp->gr_mem[i], pwp->pw_name))
+ {
+ ++in_grp;
+ break;
+ }
+ }
+ }
+ if (in_grp)
+ {
+ is_r = buf.st_mode & S_IRGRP;
+ is_x = buf.st_mode & S_IXGRP;
+ if (DebugLvl > 1 && !(is_r && is_x))
+ fprintf(stderr, "ValidateBackend: \"%s\" is not group read/execute\n",
+ path);
+ return (is_x ? (is_r ? 0 : -2) : -1);
+ }
+ }
+ is_r = buf.st_mode & S_IROTH;
+ is_x = buf.st_mode & S_IXOTH;
+ if (DebugLvl > 1 && !(is_r && is_x))
+ fprintf(stderr, "ValidateBackend: \"%s\" is not other read/execute\n",
+ path);
+ return (is_x ? (is_r ? 0 : -2) : -1);
}
/*
* FindBackend -- find an absolute path to a valid backend executable
*
* The reason we have to work so hard to find an absolute path is that
- * we need to feed the backend server the location of its actual
+ * we need to feed the backend server the location of its actual
* executable file -- otherwise, we can't do dynamic loading.
*/
int
FindBackend(char *backend, char *argv0)
{
- char buf[MAXPGPATH + 2];
- char *p;
- char *path, *startp, *endp;
- int pathlen;
-
- /*
- * for the postmaster:
- * First try: use the backend that's located in the same directory
- * as the postmaster, if it was invoked with an explicit path.
- * Presumably the user used an explicit path because it wasn't in
- * PATH, and we don't want to use incompatible executables.
- *
- * This has the neat property that it works for installed binaries,
- * old source trees (obj/support/post{master,gres}) and new marc
- * source trees (obj/post{master,gres}) because they all put the
- * two binaries in the same place.
- *
- * for the backend server:
- * First try: if we're given some kind of path, use it (making sure
- * that a relative path is made absolute before returning it).
- */
- if (argv0 && (p = strrchr(argv0, '/')) && *++p) {
- if (*argv0 == '/' || !getcwd(buf, MAXPGPATH))
- buf[0] = '\0';
- else
- strcat(buf, "/");
- strcat(buf, argv0);
- p = strrchr(buf, '/');
- strcpy(++p, "postgres");
- if (!ValidateBackend(buf)) {
- strncpy(backend, buf, MAXPGPATH);
- if (DebugLvl)
- fprintf(stderr, "FindBackend: found \"%s\" using argv[0]\n",
- backend);
- return(0);
+ char buf[MAXPGPATH + 2];
+ char *p;
+ char *path,
+ *startp,
+ *endp;
+ int pathlen;
+
+ /*
+ * for the postmaster: First try: use the backend that's located in
+ * the same directory as the postmaster, if it was invoked with an
+ * explicit path. Presumably the user used an explicit path because it
+ * wasn't in PATH, and we don't want to use incompatible executables.
+ *
+ * This has the neat property that it works for installed binaries, old
+ * source trees (obj/support/post{master,gres}) and new marc source
+ * trees (obj/post{master,gres}) because they all put the two binaries
+ * in the same place.
+ *
+ * for the backend server: First try: if we're given some kind of path,
+ * use it (making sure that a relative path is made absolute before
+ * returning it).
+ */
+ if (argv0 && (p = strrchr(argv0, '/')) && *++p)
+ {
+ if (*argv0 == '/' || !getcwd(buf, MAXPGPATH))
+ buf[0] = '\0';
+ else
+ strcat(buf, "/");
+ strcat(buf, argv0);
+ p = strrchr(buf, '/');
+ strcpy(++p, "postgres");
+ if (!ValidateBackend(buf))
+ {
+ strncpy(backend, buf, MAXPGPATH);
+ if (DebugLvl)
+ fprintf(stderr, "FindBackend: found \"%s\" using argv[0]\n",
+ backend);
+ return (0);
+ }
+ fprintf(stderr, "FindBackend: invalid backend \"%s\"\n",
+ buf);
+ return (-1);
}
- fprintf(stderr, "FindBackend: invalid backend \"%s\"\n",
- buf);
- return(-1);
- }
-
- /*
- * Second try: since no explicit path was supplied, the user must
- * have been relying on PATH. We'll use the same PATH.
- */
- if ((p = getenv("PATH")) && *p) {
- if (DebugLvl)
- fprintf(stderr, "FindBackend: searching PATH ...\n");
- pathlen = strlen(p);
- path = malloc(pathlen + 1);
- strcpy(path, p);
- for (startp = path, endp = strchr(path, ':');
- startp && *startp;
- startp = endp + 1, endp = strchr(startp, ':')) {
- if (startp == endp) /* it's a "::" */
- continue;
- if (endp)
- *endp = '\0';
- if (*startp == '/' || !getcwd(buf, MAXPGPATH))
- buf[0] = '\0';
- strcat(buf, startp);
- strcat(buf, "/postgres");
- switch (ValidateBackend(buf)) {
- case 0: /* found ok */
- strncpy(backend, buf, MAXPGPATH);
+
+ /*
+ * Second try: since no explicit path was supplied, the user must have
+ * been relying on PATH. We'll use the same PATH.
+ */
+ if ((p = getenv("PATH")) && *p)
+ {
if (DebugLvl)
- fprintf(stderr, "FindBackend: found \"%s\" using PATH\n",
- backend);
- free(path);
- return(0);
- case -1: /* wasn't even a candidate, keep looking */
- break;
- case -2: /* found but disqualified */
- fprintf(stderr, "FindBackend: could not read backend \"%s\"\n",
- buf);
+ fprintf(stderr, "FindBackend: searching PATH ...\n");
+ pathlen = strlen(p);
+ path = malloc(pathlen + 1);
+ strcpy(path, p);
+ for (startp = path, endp = strchr(path, ':');
+ startp && *startp;
+ startp = endp + 1, endp = strchr(startp, ':'))
+ {
+ if (startp == endp) /* it's a "::" */
+ continue;
+ if (endp)
+ *endp = '\0';
+ if (*startp == '/' || !getcwd(buf, MAXPGPATH))
+ buf[0] = '\0';
+ strcat(buf, startp);
+ strcat(buf, "/postgres");
+ switch (ValidateBackend(buf))
+ {
+ case 0: /* found ok */
+ strncpy(backend, buf, MAXPGPATH);
+ if (DebugLvl)
+ fprintf(stderr, "FindBackend: found \"%s\" using PATH\n",
+ backend);
+ free(path);
+ return (0);
+ case -1: /* wasn't even a candidate, keep looking */
+ break;
+ case -2: /* found but disqualified */
+ fprintf(stderr, "FindBackend: could not read backend \"%s\"\n",
+ buf);
+ free(path);
+ return (-1);
+ }
+ if (!endp) /* last one */
+ break;
+ }
free(path);
- return(-1);
- }
- if (!endp) /* last one */
- break;
}
- free(path);
- }
- fprintf(stderr, "FindBackend: could not find a backend to execute...\n");
- return(-1);
+ fprintf(stderr, "FindBackend: could not find a backend to execute...\n");
+ return (-1);
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 053bcbb8775..2ed0c83e0b2 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* globals.c--
- * global variable declarations
+ * global variable declarations
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.10 1997/08/14 16:11:21 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/globals.c,v 1.11 1997/09/07 04:53:48 momjian Exp $
*
* NOTES
- * Globals used all over the place should be declared here and not
- * in other modules.
+ * Globals used all over the place should be declared here and not
+ * in other modules.
*
*-------------------------------------------------------------------------
*/
@@ -24,7 +24,7 @@
#include <unistd.h>
#include "postgres.h"
-#include "miscadmin.h" /* where the declarations go */
+#include "miscadmin.h" /* where the declarations go */
#include <storage/backendid.h>
#include "access/heapam.h"
@@ -36,83 +36,86 @@
#include "catalog/catname.h"
-int Portfd = -1;
-int Noversion = 0;
-int Quiet = 1;
+int Portfd = -1;
+int Noversion = 0;
+int Quiet = 1;
-int MasterPid;
-char *DataDir;
- /* The PGDATA directory user says to use, or defaults to via environment
- variable. NULL if no option given and no environment variable set
+int MasterPid;
+char *DataDir;
+
+ /*
+ * The PGDATA directory user says to use, or defaults to via environment
+ * variable. NULL if no option given and no environment variable set
*/
-Relation reldesc; /* current relation descriptor */
-
-char OutputFileName[MAXPGPATH] = "";
+Relation reldesc; /* current relation descriptor */
+
+char OutputFileName[MAXPGPATH] = "";
-BackendId MyBackendId;
-BackendTag MyBackendTag;
+BackendId MyBackendId;
+BackendTag MyBackendTag;
-char *UserName = NULL;
-char *DatabaseName = NULL;
-char *DatabasePath = NULL;
+char *UserName = NULL;
+char *DatabaseName = NULL;
+char *DatabasePath = NULL;
-bool MyDatabaseIdIsInitialized = false;
-Oid MyDatabaseId = InvalidOid;
-bool TransactionInitWasProcessed = false;
+bool MyDatabaseIdIsInitialized = false;
+Oid MyDatabaseId = InvalidOid;
+bool TransactionInitWasProcessed = false;
-bool IsUnderPostmaster = false;
-bool IsPostmaster = false;
+bool IsUnderPostmaster = false;
+bool IsPostmaster = false;
-short DebugLvl = 0;
+short DebugLvl = 0;
-int DateStyle = USE_POSTGRES_DATES;
-bool EuroDates = false;
-bool HasCTZSet = false;
-bool CDayLight = false;
-int CTimeZone = 0;
-char CTZName[MAXTZLEN+1] = "";
+int DateStyle = USE_POSTGRES_DATES;
+bool EuroDates = false;
+bool HasCTZSet = false;
+bool CDayLight = false;
+int CTimeZone = 0;
+char CTZName[MAXTZLEN + 1] = "";
-char DateFormat[20] = "%d-%m-%Y"; /* mjl: sizes! or better malloc? XXX */
-char FloatFormat[20] = "%f";
+char DateFormat[20] = "%d-%m-%Y"; /* mjl: sizes! or better
+ * malloc? XXX */
+char FloatFormat[20] = "%f";
-int fsyncOff = 0;
-int SortMem = 512;
+int fsyncOff = 0;
+int SortMem = 512;
-char *IndexedCatalogNames[] = {
- AttributeRelationName,
- ProcedureRelationName,
- TypeRelationName,
- RelationRelationName,
- 0
+char *IndexedCatalogNames[] = {
+ AttributeRelationName,
+ ProcedureRelationName,
+ TypeRelationName,
+ RelationRelationName,
+ 0
};
/* ----------------
* we just do a linear search now so there's no requirement that the list
- * be ordered. The list is so small it shouldn't make much difference.
+ * be ordered. The list is so small it shouldn't make much difference.
* make sure the list is null-terminated
- * - jolly 8/19/95
- *
+ * - jolly 8/19/95
+ *
* OLD COMMENT
- * WARNING WARNING WARNING WARNING WARNING WARNING
+ * WARNING WARNING WARNING WARNING WARNING WARNING
*
- * keep SharedSystemRelationNames[] in SORTED order! A binary search
- * is done on it in catalog.c!
+ * keep SharedSystemRelationNames[] in SORTED order! A binary search
+ * is done on it in catalog.c!
*
- * XXX this is a serious hack which should be fixed -cim 1/26/90
+ * XXX this is a serious hack which should be fixed -cim 1/26/90
* ----------------
*/
-char *SharedSystemRelationNames[] = {
- DatabaseRelationName,
- DefaultsRelationName,
- DemonRelationName,
- GroupRelationName,
- HostsRelationName,
- LogRelationName,
- MagicRelationName,
- ServerRelationName,
- TimeRelationName,
- UserRelationName,
- VariableRelationName,
- 0
+char *SharedSystemRelationNames[] = {
+ DatabaseRelationName,
+ DefaultsRelationName,
+ DemonRelationName,
+ GroupRelationName,
+ HostsRelationName,
+ LogRelationName,
+ MagicRelationName,
+ ServerRelationName,
+ TimeRelationName,
+ UserRelationName,
+ VariableRelationName,
+ 0
};
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 2fe002bd914..71efb80d120 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -1,55 +1,55 @@
/*-------------------------------------------------------------------------
*
* miscinit.c--
- * miscellanious initialization support stuff
+ * miscellanious initialization support stuff
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.6 1997/08/19 21:35:44 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.7 1997/09/07 04:53:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
-#include <sys/param.h> /* for MAXPATHLEN */
+#include <sys/param.h> /* for MAXPATHLEN */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <stdio.h>
#include <unistd.h>
-#include <grp.h> /* for getgrgid */
-#include <pwd.h> /* for getpwuid */
+#include <grp.h> /* for getgrgid */
+#include <pwd.h> /* for getpwuid */
#include "postgres.h"
-#include "utils/portal.h" /* for EnablePortalManager, etc. */
-#include "utils/exc.h" /* for EnableExceptionHandling, etc. */
-#include "utils/mcxt.h" /* for EnableMemoryContext, etc. */
+#include "utils/portal.h" /* for EnablePortalManager, etc. */
+#include "utils/exc.h" /* for EnableExceptionHandling, etc. */
+#include "utils/mcxt.h" /* for EnableMemoryContext, etc. */
#include "utils/elog.h"
#include "utils/builtins.h"
-#include "miscadmin.h" /* where the declarations go */
+#include "miscadmin.h" /* where the declarations go */
#include "catalog/catname.h"
#include "catalog/pg_user.h"
#include "catalog/pg_proc.h"
#include "utils/syscache.h"
-#include "storage/fd.h" /* for O_ */
+#include "storage/fd.h" /* for O_ */
/*
* EnableAbortEnvVarName --
- * Enables system abort iff set to a non-empty string in environment.
+ * Enables system abort iff set to a non-empty string in environment.
*/
#define EnableAbortEnvVarName "POSTGRESABORT"
-extern char *getenv(const char *name); /* XXX STDLIB */
+extern char *getenv(const char *name); /* XXX STDLIB */
-/* from globals.c */
-extern char *DatabaseName;
-extern char *UserName;
-extern char *DatabasePath;
+/* from globals.c */
+extern char *DatabaseName;
+extern char *UserName;
+extern char *DatabasePath;
/*
@@ -59,282 +59,286 @@ extern char *DatabasePath;
#define USE_ENVIRONMENT
/* ----------------------------------------------------------------
- * some of the 19 ways to leave postgres
+ * some of the 19 ways to leave postgres
* ----------------------------------------------------------------
*/
/*
* ExitPostgres --
- * Exit POSTGRES with a status code.
+ * Exit POSTGRES with a status code.
*
* Note:
- * This function never returns.
- * ...
+ * This function never returns.
+ * ...
*
* Side effects:
- * ...
+ * ...
*
* Exceptions:
- * none
+ * none
*/
void
ExitPostgres(ExitStatus status)
{
#ifdef __SABER__
- saber_stop();
+ saber_stop();
#endif
- exitpg(status);
+ exitpg(status);
}
/*
* AbortPostgres --
- * Abort POSTGRES dumping core.
+ * Abort POSTGRES dumping core.
*
* Note:
- * This function never returns.
- * ...
+ * This function never returns.
+ * ...
*
* Side effects:
- * Core is dumped iff EnableAbortEnvVarName is set to a non-empty string.
- * ...
+ * Core is dumped iff EnableAbortEnvVarName is set to a non-empty string.
+ * ...
*
* Exceptions:
- * none
+ * none
*/
#ifdef NOT_USED
void
AbortPostgres()
{
- char *abortValue = getenv(EnableAbortEnvVarName);
-
+ char *abortValue = getenv(EnableAbortEnvVarName);
+
#ifdef __SABER__
- saber_stop();
+ saber_stop();
#endif
-
- if (PointerIsValid(abortValue) && abortValue[0] != '\0')
- abort();
- else
- exitpg(FatalExitStatus);
+
+ if (PointerIsValid(abortValue) && abortValue[0] != '\0')
+ abort();
+ else
+ exitpg(FatalExitStatus);
}
+
#endif
/* ----------------
- * StatusBackendExit
+ * StatusBackendExit
* ----------------
*/
void
StatusBackendExit(int status)
{
- /* someday, do some real cleanup and then call the LISP exit */
- /* someday, call StatusPostmasterExit if running without postmaster */
- exitpg(status);
+ /* someday, do some real cleanup and then call the LISP exit */
+ /* someday, call StatusPostmasterExit if running without postmaster */
+ exitpg(status);
}
/* ----------------
- * StatusPostmasterExit
+ * StatusPostmasterExit
* ----------------
*/
void
StatusPostmasterExit(int status)
{
- /* someday, do some real cleanup and then call the LISP exit */
- exitpg(status);
+ /* someday, do some real cleanup and then call the LISP exit */
+ exitpg(status);
}
/* ----------------------------------------------------------------
- * processing mode support stuff (used to be in pmod.c)
+ * processing mode support stuff (used to be in pmod.c)
* ----------------------------------------------------------------
*/
-static ProcessingMode Mode = NoProcessing;
+static ProcessingMode Mode = NoProcessing;
/*
* IsNoProcessingMode --
- * True iff processing mode is NoProcessing.
+ * True iff processing mode is NoProcessing.
*/
bool
IsNoProcessingMode()
{
- return ((bool)(Mode == NoProcessing));
+ return ((bool) (Mode == NoProcessing));
}
/*
* IsBootstrapProcessingMode --
- * True iff processing mode is BootstrapProcessing.
+ * True iff processing mode is BootstrapProcessing.
*/
bool
IsBootstrapProcessingMode()
{
- return ((bool)(Mode == BootstrapProcessing));
+ return ((bool) (Mode == BootstrapProcessing));
}
/*
* IsInitProcessingMode --
- * True iff processing mode is InitProcessing.
+ * True iff processing mode is InitProcessing.
*/
bool
IsInitProcessingMode()
{
- return ((bool)(Mode == InitProcessing));
+ return ((bool) (Mode == InitProcessing));
}
/*
* IsNormalProcessingMode --
- * True iff processing mode is NormalProcessing.
+ * True iff processing mode is NormalProcessing.
*/
bool
IsNormalProcessingMode()
{
- return ((bool)(Mode == NormalProcessing));
+ return ((bool) (Mode == NormalProcessing));
}
/*
* SetProcessingMode --
- * Sets mode of processing as specified.
+ * Sets mode of processing as specified.
*
* Exceptions:
- * BadArg if called with invalid mode.
+ * BadArg if called with invalid mode.
*
* Note:
- * Mode is NoProcessing before the first time this is called.
+ * Mode is NoProcessing before the first time this is called.
*/
void
SetProcessingMode(ProcessingMode mode)
{
- AssertArg(mode == NoProcessing || mode == BootstrapProcessing ||
- mode == InitProcessing || mode == NormalProcessing);
-
- Mode = mode;
+ AssertArg(mode == NoProcessing || mode == BootstrapProcessing ||
+ mode == InitProcessing || mode == NormalProcessing);
+
+ Mode = mode;
}
ProcessingMode
GetProcessingMode()
{
- return (Mode);
+ return (Mode);
}
/* ----------------------------------------------------------------
- * database path / name support stuff
+ * database path / name support stuff
* ----------------------------------------------------------------
*/
/*
* GetDatabasePath --
- * Returns path to database.
+ * Returns path to database.
*
*/
-char*
+char *
GetDatabasePath()
{
- return DatabasePath;
+ return DatabasePath;
}
/*
* GetDatabaseName --
- * Returns name of database.
+ * Returns name of database.
*/
-char*
+char *
GetDatabaseName()
{
- return DatabaseName;
+ return DatabaseName;
}
void
SetDatabasePath(char *path)
{
- /* use malloc since this is done before memory contexts are set up */
- if (DatabasePath)
- free(DatabasePath);
- DatabasePath = malloc(strlen(path)+1);
- strcpy(DatabasePath, path);
+ /* use malloc since this is done before memory contexts are set up */
+ if (DatabasePath)
+ free(DatabasePath);
+ DatabasePath = malloc(strlen(path) + 1);
+ strcpy(DatabasePath, path);
}
void
SetDatabaseName(char *name)
{
- if (DatabaseName)
- free (DatabaseName);
- DatabaseName = malloc(strlen(name)+1);
- strcpy(DatabaseName, name);
+ if (DatabaseName)
+ free(DatabaseName);
+ DatabaseName = malloc(strlen(name) + 1);
+ strcpy(DatabaseName, name);
}
/* ----------------
- * GetPgUserName and SetPgUserName
+ * GetPgUserName and SetPgUserName
*
- * SetPgUserName must be called before InitPostgres, since the setuid()
- * is done there.
+ * SetPgUserName must be called before InitPostgres, since the setuid()
+ * is done there.
*
- * Replace GetPgUserName() with a lower-case version
- * to allow use in new case-insensitive SQL (referenced
- * in pg_proc.h). Define GetPgUserName() as a macro - tgl 97/04/26
+ * Replace GetPgUserName() with a lower-case version
+ * to allow use in new case-insensitive SQL (referenced
+ * in pg_proc.h). Define GetPgUserName() as a macro - tgl 97/04/26
* ----------------
*/
-char*
+char *
getpgusername()
{
- return UserName;
+ return UserName;
}
void
SetPgUserName()
{
#ifndef NO_SECURITY
- char *p;
- struct passwd *pw;
-
- if (IsUnderPostmaster) {
- /* use the (possibly) authenticated name that's provided */
- if (!(p = getenv("PG_USER")))
- elog(FATAL, "SetPgUserName: PG_USER environment variable unset");
- } else {
- /* setuid() has not yet been done, see above comment */
- if (!(pw = getpwuid(geteuid())))
- elog(FATAL, "SetPgUserName: no entry in passwd file");
- p = pw->pw_name;
- }
- if (UserName)
- free(UserName);
- UserName = malloc(strlen(p)+1);
- strcpy(UserName, p);
-#endif /* NO_SECURITY */
+ char *p;
+ struct passwd *pw;
+
+ if (IsUnderPostmaster)
+ {
+ /* use the (possibly) authenticated name that's provided */
+ if (!(p = getenv("PG_USER")))
+ elog(FATAL, "SetPgUserName: PG_USER environment variable unset");
+ }
+ else
+ {
+ /* setuid() has not yet been done, see above comment */
+ if (!(pw = getpwuid(geteuid())))
+ elog(FATAL, "SetPgUserName: no entry in passwd file");
+ p = pw->pw_name;
+ }
+ if (UserName)
+ free(UserName);
+ UserName = malloc(strlen(p) + 1);
+ strcpy(UserName, p);
+#endif /* NO_SECURITY */
}
/* ----------------------------------------------------------------
- * GetUserId and SetUserId
+ * GetUserId and SetUserId
* ----------------------------------------------------------------
*/
-static Oid UserId = InvalidOid;
+static Oid UserId = InvalidOid;
Oid
GetUserId()
{
- Assert(OidIsValid(UserId));
- return(UserId);
+ Assert(OidIsValid(UserId));
+ return (UserId);
}
void
SetUserId()
{
- HeapTuple userTup;
- char *userName;
-
- Assert(!OidIsValid(UserId)); /* only once */
-
- /*
- * Don't do scans if we're bootstrapping, none of the system
- * catalogs exist yet, and they should be owned by postgres
- * anyway.
- */
- if (IsBootstrapProcessingMode()) {
- UserId = geteuid();
- return;
- }
-
- userName = GetPgUserName();
- userTup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
- 0,0,0);
- if (!HeapTupleIsValid(userTup))
- elog(FATAL, "SetUserId: user \"%s\" is not in \"%s\"",
- userName,
- UserRelationName);
- UserId = (Oid) ((Form_pg_user) GETSTRUCT(userTup))->usesysid;
+ HeapTuple userTup;
+ char *userName;
+
+ Assert(!OidIsValid(UserId));/* only once */
+
+ /*
+ * Don't do scans if we're bootstrapping, none of the system catalogs
+ * exist yet, and they should be owned by postgres anyway.
+ */
+ if (IsBootstrapProcessingMode())
+ {
+ UserId = geteuid();
+ return;
+ }
+
+ userName = GetPgUserName();
+ userTup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(userTup))
+ elog(FATAL, "SetUserId: user \"%s\" is not in \"%s\"",
+ userName,
+ UserRelationName);
+ UserId = (Oid) ((Form_pg_user) GETSTRUCT(userTup))->usesysid;
}
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index fb21e51a492..5a8a1a83d4d 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -1,28 +1,28 @@
/*-------------------------------------------------------------------------
*
* postinit.c--
- * postgres initialization utilities
+ * postgres initialization utilities
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.12 1997/08/27 03:48:39 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/init/postinit.c,v 1.13 1997/09/07 04:53:50 momjian Exp $
*
* NOTES
- * InitPostgres() is the function called from PostgresMain
- * which does all non-trival initialization, mainly by calling
- * all the other initialization functions. InitPostgres()
- * is only used within the "postgres" backend and so that routine
- * is in tcop/postgres.c InitPostgres() is needed in cinterface.a
- * because things like the bootstrap backend program need it. Hence
- * you find that in this file...
+ * InitPostgres() is the function called from PostgresMain
+ * which does all non-trival initialization, mainly by calling
+ * all the other initialization functions. InitPostgres()
+ * is only used within the "postgres" backend and so that routine
+ * is in tcop/postgres.c InitPostgres() is needed in cinterface.a
+ * because things like the bootstrap backend program need it. Hence
+ * you find that in this file...
*
- * If you feel the need to add more initialization code, it should be
- * done in InitPostgres() or someplace lower. Do not start
- * putting stuff in PostgresMain - if you do then someone
- * will have to clean it up later, and it's not going to be me!
- * -cim 10/3/90
+ * If you feel the need to add more initialization code, it should be
+ * done in InitPostgres() or someplace lower. Do not start
+ * putting stuff in PostgresMain - if you do then someone
+ * will have to clean it up later, and it's not going to be me!
+ * -cim 10/3/90
*
*-------------------------------------------------------------------------
*/
@@ -47,22 +47,22 @@
#include "access/heapam.h"
#include "access/xact.h"
#include "storage/bufmgr.h"
-#include "access/transam.h" /* XXX dependency problem */
+#include "access/transam.h" /* XXX dependency problem */
#include "utils/tqual.h"
#include "utils/syscache.h"
-#include "storage/bufpage.h" /* for page layout, for InitMyDatabaseId() */
+#include "storage/bufpage.h" /* for page layout, for InitMyDatabaseId() */
#include "storage/sinval.h"
#include "storage/sinvaladt.h"
#include "storage/lmgr.h"
-#include "miscadmin.h" /* for global decls */
-#include "utils/portal.h" /* for EnablePortalManager, etc. */
+#include "miscadmin.h" /* for global decls */
+#include "utils/portal.h" /* for EnablePortalManager, etc. */
-#include "utils/exc.h" /* for EnableExceptionHandling, etc. */
-#include "fmgr.h" /* for EnableDynamicFunctionManager, etc. */
+#include "utils/exc.h" /* for EnableExceptionHandling, etc. */
+#include "fmgr.h" /* for EnableDynamicFunctionManager, etc. */
#include "utils/elog.h"
#include "utils/palloc.h"
-#include "utils/mcxt.h" /* for EnableMemoryContext, etc. */
+#include "utils/mcxt.h" /* for EnableMemoryContext, etc. */
#include "catalog/catname.h"
#include "catalog/pg_database.h"
@@ -70,584 +70,612 @@
#include "port-protos.h"
#include "libpq/libpq-be.h"
-static void InitCommunication(void);
-static void InitMyDatabaseId(void);
-static void InitStdio(void);
-static void InitUserid(void);
+static void InitCommunication(void);
+static void InitMyDatabaseId(void);
+static void InitStdio(void);
+static void InitUserid(void);
-static IPCKey PostgresIpcKey;
+static IPCKey PostgresIpcKey;
/* ----------------------------------------------------------------
- * InitPostgres support
+ * InitPostgres support
* ----------------------------------------------------------------
*/
/* --------------------------------
- * InitMyDatabaseId() -- Find and record the OID of the database we are
- * to open.
+ * InitMyDatabaseId() -- Find and record the OID of the database we are
+ * to open.
*
- * The database's oid forms half of the unique key for the system
- * caches and lock tables. We therefore want it initialized before
- * we open any relations, since opening relations puts things in the
- * cache. To get around this problem, this code opens and scans the
- * pg_database relation by hand.
+ * The database's oid forms half of the unique key for the system
+ * caches and lock tables. We therefore want it initialized before
+ * we open any relations, since opening relations puts things in the
+ * cache. To get around this problem, this code opens and scans the
+ * pg_database relation by hand.
*
- * This algorithm relies on the fact that first attribute in the
- * pg_database relation schema is the database name. It also knows
- * about the internal format of tuples on disk and the length of
- * the datname attribute. It knows the location of the pg_database
- * file.
+ * This algorithm relies on the fact that first attribute in the
+ * pg_database relation schema is the database name. It also knows
+ * about the internal format of tuples on disk and the length of
+ * the datname attribute. It knows the location of the pg_database
+ * file.
*
- * This code is called from InitDatabase(), after we chdir() to the
- * database directory but before we open any relations.
+ * This code is called from InitDatabase(), after we chdir() to the
+ * database directory but before we open any relations.
* --------------------------------
*/
static void
InitMyDatabaseId()
{
- int dbfd;
- int fileflags;
- int nbytes;
- int max, i;
- HeapTuple tup;
- Page pg;
- PageHeader ph;
- char *dbfname;
- Form_pg_database tup_db;
-
- /*
- * At bootstrap time, we don't need to check the oid of the database
- * in use, since we're not using shared memory. This is lucky, since
- * the database may not be in the tables yet.
- */
-
- if (IsBootstrapProcessingMode()) {
- LockDisable(true);
- return;
- }
-
- dbfname = (char *) palloc(strlen(DataDir) + strlen("pg_database") + 2);
- sprintf(dbfname, "%s%cpg_database", DataDir, SEP_CHAR);
- fileflags = O_RDONLY;
-
- if ((dbfd = open(dbfname, O_RDONLY, 0)) < 0)
- elog(FATAL, "Cannot open %s", dbfname);
-
- pfree(dbfname);
-
- /* ----------------
- * read and examine every page in pg_database
- *
- * Raw I/O! Read those tuples the hard way! Yow!
- *
- * Why don't we use the access methods or move this code
- * someplace else? This is really pg_database schema dependent
- * code. Perhaps it should go in lib/catalog/pg_database?
- * -cim 10/3/90
- *
- * mao replies 4 apr 91: yeah, maybe this should be moved to
- * lib/catalog. however, we CANNOT use the access methods since
- * those use the buffer cache, which uses the relation cache, which
- * requires that the dbid be set, which is what we're trying to do
- * here.
- * ----------------
- */
- pg = (Page) palloc(BLCKSZ);
- ph = (PageHeader) pg;
-
- while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ) {
- max = PageGetMaxOffsetNumber(pg);
-
- /* look at each tuple on the page */
- for (i = 0; i <= max; i++) {
- int offset;
-
- /* if it's a freed tuple, ignore it */
- if (!(ph->pd_linp[i].lp_flags & LP_USED))
- continue;
-
- /* get a pointer to the tuple itself */
- offset = (int) ph->pd_linp[i].lp_off;
- tup = (HeapTuple) (((char *) pg) + offset);
-
- /*
- * if the tuple has been deleted (the database was destroyed),
- * skip this tuple. XXX warning, will robinson: violation of
- * transaction semantics happens right here. we should check
- * to be sure that the xact that deleted this tuple actually
- * committed. only way to do this at init time is to paw over
- * the log relation by hand, too. let's be optimistic.
- *
- * XXX This is an evil type cast. tup->t_xmax is char[5] while
- * TransactionId is struct * { char data[5] }. It works but
- * if data is ever moved and no longer the first field this
- * will be broken!! -mer 11 Nov 1991.
- */
- if (TransactionIdIsValid((TransactionId)tup->t_xmax))
- continue;
-
- /*
- * Okay, see if this is the one we want.
- * XXX 1 july 91: mao and mer discover that tuples now squash
- * t_bits. Why is this?
- *
- * 24 july 92: mer realizes that the t_bits field is only
- * used in the event of null values. If no
- * fields are null we reduce the header size
- * by doing the squash. t_hoff tells you exactly
- * how big the header actually is. use the PC
- * means of getting at sys cat attrs.
- */
- tup_db = (Form_pg_database)GETSTRUCT(tup);
-
- if (strncmp(GetDatabaseName(),
- &(tup_db->datname.data[0]),
- 16) == 0)
- {
- MyDatabaseId = tup->t_oid;
- goto done;
- }
- }
- }
-
- done:
- close(dbfd);
- pfree(pg);
-
- if (!OidIsValid(MyDatabaseId))
- elog(FATAL,
- "Database %s does not exist in %s",
- GetDatabaseName(),
- DatabaseRelationName);
+ int dbfd;
+ int fileflags;
+ int nbytes;
+ int max,
+ i;
+ HeapTuple tup;
+ Page pg;
+ PageHeader ph;
+ char *dbfname;
+ Form_pg_database tup_db;
+
+ /*
+ * At bootstrap time, we don't need to check the oid of the database
+ * in use, since we're not using shared memory. This is lucky, since
+ * the database may not be in the tables yet.
+ */
+
+ if (IsBootstrapProcessingMode())
+ {
+ LockDisable(true);
+ return;
+ }
+
+ dbfname = (char *) palloc(strlen(DataDir) + strlen("pg_database") + 2);
+ sprintf(dbfname, "%s%cpg_database", DataDir, SEP_CHAR);
+ fileflags = O_RDONLY;
+
+ if ((dbfd = open(dbfname, O_RDONLY, 0)) < 0)
+ elog(FATAL, "Cannot open %s", dbfname);
+
+ pfree(dbfname);
+
+ /* ----------------
+ * read and examine every page in pg_database
+ *
+ * Raw I/O! Read those tuples the hard way! Yow!
+ *
+ * Why don't we use the access methods or move this code
+ * someplace else? This is really pg_database schema dependent
+ * code. Perhaps it should go in lib/catalog/pg_database?
+ * -cim 10/3/90
+ *
+ * mao replies 4 apr 91: yeah, maybe this should be moved to
+ * lib/catalog. however, we CANNOT use the access methods since
+ * those use the buffer cache, which uses the relation cache, which
+ * requires that the dbid be set, which is what we're trying to do
+ * here.
+ * ----------------
+ */
+ pg = (Page) palloc(BLCKSZ);
+ ph = (PageHeader) pg;
+
+ while ((nbytes = read(dbfd, pg, BLCKSZ)) == BLCKSZ)
+ {
+ max = PageGetMaxOffsetNumber(pg);
+
+ /* look at each tuple on the page */
+ for (i = 0; i <= max; i++)
+ {
+ int offset;
+
+ /* if it's a freed tuple, ignore it */
+ if (!(ph->pd_linp[i].lp_flags & LP_USED))
+ continue;
+
+ /* get a pointer to the tuple itself */
+ offset = (int) ph->pd_linp[i].lp_off;
+ tup = (HeapTuple) (((char *) pg) + offset);
+
+ /*
+ * if the tuple has been deleted (the database was destroyed),
+ * skip this tuple. XXX warning, will robinson: violation of
+ * transaction semantics happens right here. we should check
+ * to be sure that the xact that deleted this tuple actually
+ * committed. only way to do this at init time is to paw over
+ * the log relation by hand, too. let's be optimistic.
+ *
+ * XXX This is an evil type cast. tup->t_xmax is char[5] while
+ * TransactionId is struct * { char data[5] }. It works but
+ * if data is ever moved and no longer the first field this
+ * will be broken!! -mer 11 Nov 1991.
+ */
+ if (TransactionIdIsValid((TransactionId) tup->t_xmax))
+ continue;
+
+ /*
+ * Okay, see if this is the one we want. XXX 1 july 91: mao
+ * and mer discover that tuples now squash t_bits. Why is
+ * this?
+ *
+ * 24 july 92: mer realizes that the t_bits field is only used
+ * in the event of null values. If no fields are null we
+ * reduce the header size by doing the squash. t_hoff tells
+ * you exactly how big the header actually is. use the PC
+ * means of getting at sys cat attrs.
+ */
+ tup_db = (Form_pg_database) GETSTRUCT(tup);
+
+ if (strncmp(GetDatabaseName(),
+ &(tup_db->datname.data[0]),
+ 16) == 0)
+ {
+ MyDatabaseId = tup->t_oid;
+ goto done;
+ }
+ }
+ }
+
+done:
+ close(dbfd);
+ pfree(pg);
+
+ if (!OidIsValid(MyDatabaseId))
+ elog(FATAL,
+ "Database %s does not exist in %s",
+ GetDatabaseName(),
+ DatabaseRelationName);
}
/*
* DoChdirAndInitDatabaseNameAndPath --
- * Set current directory to the database directory for the database
- * named <name>.
- * Also set global variables DatabasePath and DatabaseName to those
- * values. Also check for proper version of database system and
- * database. Exit program via elog() if anything doesn't check out.
+ * Set current directory to the database directory for the database
+ * named <name>.
+ * Also set global variables DatabasePath and DatabaseName to those
+ * values. Also check for proper version of database system and
+ * database. Exit program via elog() if anything doesn't check out.
*
* Arguments:
- * Path and name are invalid if it invalid as a string.
- * Path is "badly formated" if it is not a string containing a path
- * to a writable directory.
- * Name is "badly formated" if it contains more than 16 characters or if
- * it is a bad file name (e.g., it contains a '/' or an 8-bit character).
+ * Path and name are invalid if it invalid as a string.
+ * Path is "badly formated" if it is not a string containing a path
+ * to a writable directory.
+ * Name is "badly formated" if it contains more than 16 characters or if
+ * it is a bad file name (e.g., it contains a '/' or an 8-bit character).
*
* Exceptions:
- * BadState if called more than once.
- * BadArg if both path and name are "badly formated" or invalid.
- * BadArg if path and name are both "inconsistent" and valid.
+ * BadState if called more than once.
+ * BadArg if both path and name are "badly formated" or invalid.
+ * BadArg if path and name are both "inconsistent" and valid.
*
- * This routine is inappropriate in bootstrap mode, since the directories
- * and version files need not exist yet if we're in bootstrap mode.
+ * This routine is inappropriate in bootstrap mode, since the directories
+ * and version files need not exist yet if we're in bootstrap mode.
*/
static void
-DoChdirAndInitDatabaseNameAndPath(char *name) {
- char *reason;
- /* Failure reason returned by some function. NULL if no failure */
- int fd;
- char errormsg[1000];
-
- if ((fd = open(DataDir, O_RDONLY,0)) == -1)
- sprintf(errormsg, "Database system does not exist. "
- "PGDATA directory '%s' not found. Normally, you "
- "create a database system by running initdb.",
- DataDir);
- else {
- char myPath[MAXPGPATH]; /* DatabasePath points here! */
-
- close(fd);
- if (strlen(DataDir) + strlen(name) + 10 > sizeof(myPath))
- sprintf(errormsg, "Internal error in postinit.c: database "
- "pathname exceeds maximum allowable length.");
- else {
- sprintf(myPath, "%s/base/%s", DataDir, name);
-
- if ((fd = open(myPath, O_RDONLY,0)) == -1)
- sprintf(errormsg,
- "Database '%s' does not exist. "
- "(We know this because the directory '%s' "
- "does not exist). You can create a database "
- "with the SQL command CREATE DATABASE. To see "
- "what databases exist, look at the subdirectories "
- "of '%s/base/'.",
- name, myPath, DataDir);
- else {
- close(fd);
- ValidatePgVersion(DataDir, &reason);
- if (reason != NULL)
- sprintf(errormsg,
- "InitPostgres could not validate that the database "
- "system version is compatible with this level of "
- "Postgres. You may need to run initdb to create "
- "a new database system. %s",
- reason);
- else {
- ValidatePgVersion(myPath, &reason);
- if (reason != NULL)
- sprintf(errormsg,
- "InitPostgres could not validate that the "
- "database version is compatible with this level "
- "of Postgres, even though the database system "
- "as a whole appears to be at a compatible level. "
- "You may need to recreate the database with SQL "
- "commands DROP DATABASE and CREATE DATABASE. "
- "%s",
- reason);
- else {
- /* The directories and PG_VERSION files are in order.*/
- int rc; /* return code from some function we call */
-
- SetDatabasePath(myPath);
- SetDatabaseName(name);
- rc = chdir(myPath);
- if (rc < 0)
- sprintf(errormsg,
- "InitPostgres unable to change "
- "current directory to '%s', errno = %s (%d).",
- myPath, strerror(errno), errno);
- else errormsg[0] = '\0';
- }
- }
- }
- }
- }
- if (errormsg[0] != '\0')
- elog(FATAL, errormsg);
- /* Above does not return */
+DoChdirAndInitDatabaseNameAndPath(char *name)
+{
+ char *reason;
+
+ /* Failure reason returned by some function. NULL if no failure */
+ int fd;
+ char errormsg[1000];
+
+ if ((fd = open(DataDir, O_RDONLY, 0)) == -1)
+ sprintf(errormsg, "Database system does not exist. "
+ "PGDATA directory '%s' not found. Normally, you "
+ "create a database system by running initdb.",
+ DataDir);
+ else
+ {
+ char myPath[MAXPGPATH]; /* DatabasePath points
+ * here! */
+
+ close(fd);
+ if (strlen(DataDir) + strlen(name) + 10 > sizeof(myPath))
+ sprintf(errormsg, "Internal error in postinit.c: database "
+ "pathname exceeds maximum allowable length.");
+ else
+ {
+ sprintf(myPath, "%s/base/%s", DataDir, name);
+
+ if ((fd = open(myPath, O_RDONLY, 0)) == -1)
+ sprintf(errormsg,
+ "Database '%s' does not exist. "
+ "(We know this because the directory '%s' "
+ "does not exist). You can create a database "
+ "with the SQL command CREATE DATABASE. To see "
+ "what databases exist, look at the subdirectories "
+ "of '%s/base/'.",
+ name, myPath, DataDir);
+ else
+ {
+ close(fd);
+ ValidatePgVersion(DataDir, &reason);
+ if (reason != NULL)
+ sprintf(errormsg,
+ "InitPostgres could not validate that the database "
+ "system version is compatible with this level of "
+ "Postgres. You may need to run initdb to create "
+ "a new database system. %s",
+ reason);
+ else
+ {
+ ValidatePgVersion(myPath, &reason);
+ if (reason != NULL)
+ sprintf(errormsg,
+ "InitPostgres could not validate that the "
+ "database version is compatible with this level "
+ "of Postgres, even though the database system "
+ "as a whole appears to be at a compatible level. "
+ "You may need to recreate the database with SQL "
+ "commands DROP DATABASE and CREATE DATABASE. "
+ "%s",
+ reason);
+ else
+ {
+
+ /*
+ * The directories and PG_VERSION files are in
+ * order.
+ */
+ int rc; /* return code from some
+ * function we call */
+
+ SetDatabasePath(myPath);
+ SetDatabaseName(name);
+ rc = chdir(myPath);
+ if (rc < 0)
+ sprintf(errormsg,
+ "InitPostgres unable to change "
+ "current directory to '%s', errno = %s (%d).",
+ myPath, strerror(errno), errno);
+ else
+ errormsg[0] = '\0';
+ }
+ }
+ }
+ }
+ }
+ if (errormsg[0] != '\0')
+ elog(FATAL, errormsg);
+ /* Above does not return */
}
/* --------------------------------
- * InitUserid
+ * InitUserid
*
- * initializes crap associated with the user id.
+ * initializes crap associated with the user id.
* --------------------------------
*/
static void
InitUserid()
{
- setuid(geteuid());
- SetUserId();
+ setuid(geteuid());
+ SetUserId();
}
/* --------------------------------
- * InitCommunication
+ * InitCommunication
*
- * This routine initializes stuff needed for ipc, locking, etc.
- * it should be called something more informative.
+ * This routine initializes stuff needed for ipc, locking, etc.
+ * it should be called something more informative.
*
* Note:
- * This does not set MyBackendId. MyBackendTag is set, however.
+ * This does not set MyBackendId. MyBackendTag is set, however.
* --------------------------------
*/
static void
InitCommunication()
{
- char *postid;
- char *postport;
- IPCKey key = 0;
-
- /* ----------------
- * try and get the backend tag from POSTID
- * ----------------
- */
- MyBackendId = -1;
-
- postid = getenv("POSTID");
- if (!PointerIsValid(postid)) {
- MyBackendTag = -1;
- } else {
- MyBackendTag = atoi(postid);
- Assert(MyBackendTag >= 0);
- }
-
- /* ----------------
- * try and get the ipc key from POSTPORT
- * ----------------
- */
- postport = getenv("POSTPORT");
-
- if (PointerIsValid(postport)) {
- SystemPortAddress address = atoi(postport);
-
- if (address == 0)
- elog(FATAL, "InitCommunication: invalid POSTPORT");
-
- if (MyBackendTag == -1)
- elog(FATAL, "InitCommunication: missing POSTID");
-
- key = SystemPortAddressCreateIPCKey(address);
-
- /*
- * Enable this if you are trying to force the backend to run as if it
- * is running under the postmaster.
- *
- * This goto forces Postgres to attach to shared memory instead of
- * using malloc'ed memory (which is the normal behavior if run
- * directly).
- *
- * To enable emulation, run the following shell commands (in addition
- * to enabling this goto)
- *
- * % setenv POSTID 1
- * % setenv POSTPORT 4321
- * % postmaster &
- * % kill -9 %1
- *
- * Upon doing this, Postmaster will have allocated the shared memory
- * resources that Postgres will attach to if you enable
- * EMULATE_UNDER_POSTMASTER.
- *
- * This comment may well age with time - it is current as of
- * 8 January 1990
- *
- * Greg
- */
-
+ char *postid;
+ char *postport;
+ IPCKey key = 0;
+
+ /* ----------------
+ * try and get the backend tag from POSTID
+ * ----------------
+ */
+ MyBackendId = -1;
+
+ postid = getenv("POSTID");
+ if (!PointerIsValid(postid))
+ {
+ MyBackendTag = -1;
+ }
+ else
+ {
+ MyBackendTag = atoi(postid);
+ Assert(MyBackendTag >= 0);
+ }
+
+ /* ----------------
+ * try and get the ipc key from POSTPORT
+ * ----------------
+ */
+ postport = getenv("POSTPORT");
+
+ if (PointerIsValid(postport))
+ {
+ SystemPortAddress address = atoi(postport);
+
+ if (address == 0)
+ elog(FATAL, "InitCommunication: invalid POSTPORT");
+
+ if (MyBackendTag == -1)
+ elog(FATAL, "InitCommunication: missing POSTID");
+
+ key = SystemPortAddressCreateIPCKey(address);
+
+ /*
+ * Enable this if you are trying to force the backend to run as if
+ * it is running under the postmaster.
+ *
+ * This goto forces Postgres to attach to shared memory instead of
+ * using malloc'ed memory (which is the normal behavior if run
+ * directly).
+ *
+ * To enable emulation, run the following shell commands (in addition
+ * to enabling this goto)
+ *
+ * % setenv POSTID 1 % setenv POSTPORT 4321 % postmaster & % kill -9
+ * %1
+ *
+ * Upon doing this, Postmaster will have allocated the shared memory
+ * resources that Postgres will attach to if you enable
+ * EMULATE_UNDER_POSTMASTER.
+ *
+ * This comment may well age with time - it is current as of 8
+ * January 1990
+ *
+ * Greg
+ */
+
#ifdef EMULATE_UNDER_POSTMASTER
-
- goto forcesharedmemory;
-
+
+ goto forcesharedmemory;
+
#endif
-
- } else if (IsUnderPostmaster) {
- elog(FATAL,
- "InitCommunication: under postmaster and POSTPORT not set");
- } else {
- /* ----------------
- * assume we're running a postgres backend by itself with
- * no front end or postmaster.
- * ----------------
- */
- if (MyBackendTag == -1) {
- MyBackendTag = 1;
- }
-
- key = PrivateIPCKey;
- }
-
- /* ----------------
- * initialize shared memory and semaphores appropriately.
- * ----------------
- */
+
+ }
+ else if (IsUnderPostmaster)
+ {
+ elog(FATAL,
+ "InitCommunication: under postmaster and POSTPORT not set");
+ }
+ else
+ {
+ /* ----------------
+ * assume we're running a postgres backend by itself with
+ * no front end or postmaster.
+ * ----------------
+ */
+ if (MyBackendTag == -1)
+ {
+ MyBackendTag = 1;
+ }
+
+ key = PrivateIPCKey;
+ }
+
+ /* ----------------
+ * initialize shared memory and semaphores appropriately.
+ * ----------------
+ */
#ifdef EMULATE_UNDER_POSTMASTER
-
- forcesharedmemory:
-
+
+forcesharedmemory:
+
#endif
-
- PostgresIpcKey = key;
- AttachSharedMemoryAndSemaphores(key);
+
+ PostgresIpcKey = key;
+ AttachSharedMemoryAndSemaphores(key);
}
/* --------------------------------
- * InitStdio
+ * InitStdio
*
- * this routine consists of a bunch of code fragments
- * that used to be randomly scattered through cinit().
- * they all seem to do stuff associated with io.
+ * this routine consists of a bunch of code fragments
+ * that used to be randomly scattered through cinit().
+ * they all seem to do stuff associated with io.
* --------------------------------
*/
static void
InitStdio()
{
- DebugFileOpen();
+ DebugFileOpen();
}
/* --------------------------------
* InitPostgres --
- * Initialize POSTGRES.
+ * Initialize POSTGRES.
*
* Note:
- * Be very careful with the order of calls in the InitPostgres function.
+ * Be very careful with the order of calls in the InitPostgres function.
* --------------------------------
*/
-bool PostgresIsInitialized = false;
-extern int NBuffers;
+bool PostgresIsInitialized = false;
+extern int NBuffers;
/*
- * this global is used by wei for testing his code, but must be declared
- * here rather than in postgres.c so that it's defined for cinterface.a
- * applications.
+ * this global is used by wei for testing his code, but must be declared
+ * here rather than in postgres.c so that it's defined for cinterface.a
+ * applications.
*/
-/*int testFlag = 0;*/
-int lockingOff = 0;
+/*int testFlag = 0;*/
+int lockingOff = 0;
/*
*/
void
-InitPostgres(char *name) /* database name */
+InitPostgres(char *name) /* database name */
{
- bool bootstrap; /* true if BootstrapProcessing */
-
- /* ----------------
- * see if we're running in BootstrapProcessing mode
- * ----------------
- */
- bootstrap = IsBootstrapProcessingMode();
-
- /* ----------------
- * turn on the exception handler. Note: we cannot use elog, Assert,
- * AssertState, etc. until after exception handling is on.
- * ----------------
- */
- EnableExceptionHandling(true);
-
- /* ----------------
- * A stupid check to make sure we don't call this more than once.
- * But things like ReinitPostgres() get around this by just diddling
- * the PostgresIsInitialized flag.
- * ----------------
- */
- AssertState(!PostgresIsInitialized);
-
- /* ----------------
- * Memory system initialization.
- * (we may call palloc after EnableMemoryContext())
- *
- * Note EnableMemoryContext() must happen before EnablePortalManager().
- * ----------------
- */
- EnableMemoryContext(true); /* initializes the "top context" */
- EnablePortalManager(true); /* memory for portal/transaction stuff */
-
- /* ----------------
- * initialize the backend local portal stack used by
- * internal PQ function calls. see src/lib/libpq/be-dumpdata.c
- * This is different from the "portal manager" so this goes here.
- * -cim 2/12/91
- * ----------------
- */
- be_portalinit();
-
- /* ----------------
- * attach to shared memory and semaphores, and initialize our
- * input/output/debugging file descriptors.
- * ----------------
- */
- InitCommunication();
- InitStdio();
-
- /*
- * initialize the local buffer manager
- */
- InitLocalBuffer();
-
- if (!TransactionFlushEnabled())
- on_exitpg(FlushBufferPool, (caddr_t) NULL);
-
- if (bootstrap) {
- SetDatabasePath(".");
- SetDatabaseName(name);
- } else {
- DoChdirAndInitDatabaseNameAndPath(name);
- }
-
- /* ********************************
- * code after this point assumes we are in the proper directory!
- * ********************************
- */
-
- /* ----------------
- * initialize the database id used for system caches and lock tables
- * ----------------
- */
- InitMyDatabaseId();
-
- smgrinit();
-
- /* ----------------
- * initialize the transaction system and the relation descriptor
- * cache. Note we have to make certain the lock manager is off while
- * we do this.
- * ----------------
- */
- AmiTransactionOverride(IsBootstrapProcessingMode());
- LockDisable(true);
-
- /*
- * Part of the initialization processing done here sets a read
- * lock on pg_log. Since locking is disabled the set doesn't have
- * intended effect of locking out writers, but this is ok, since
- * we only lock it to examine AMI transaction status, and this is
- * never written after initdb is done. -mer 15 June 1992
- */
- RelationInitialize(); /* pre-allocated reldescs created here */
- InitializeTransactionSystem(); /* pg_log,etc init/crash recovery here */
-
- LockDisable(false);
-
- /* ----------------
- * anyone knows what this does? something having to do with
- * system catalog cache invalidation in the case of multiple
- * backends, I think -cim 10/3/90
- * Sets up MyBackendId a unique backend identifier.
- * ----------------
- */
- InitSharedInvalidationState();
-
- /* ----------------
- * Set up a per backend process in shared memory. Must be done after
- * InitSharedInvalidationState() as it relies on MyBackendId being
- * initialized already. XXX -mer 11 Aug 1991
- * ----------------
- */
- InitProcess(PostgresIpcKey);
-
- if (MyBackendId > MaxBackendId || MyBackendId <= 0) {
- elog(FATAL, "cinit2: bad backend id %d (%d)",
- MyBackendTag,
- MyBackendId);
- }
-
- /* ----------------
- * initialize the access methods.
- * ----------------
- */
- initam();
-
- /* ----------------
- * initialize all the system catalog caches.
- * ----------------
- */
- zerocaches();
- InitCatalogCache();
-
- /* ----------------
- * set ourselves to the proper user id and figure out our postgres
- * user id. If we ever add security so that we check for valid
- * postgres users, we might do it here.
- * ----------------
- */
- InitUserid();
-
- /* ----------------
- * ok, all done, now let's make sure we don't do it again.
- * ----------------
- */
- PostgresIsInitialized = true;
-/* on_exitpg(DestroyLocalRelList, (caddr_t) NULL); */
-
- /* ----------------
- * Done with "InitPostgres", now change to NormalProcessing unless
- * we're in BootstrapProcessing mode.
- * ----------------
- */
- if (!bootstrap)
- SetProcessingMode(NormalProcessing);
-/* if (testFlag || lockingOff) */
- if (lockingOff)
- LockDisable(true);
-}
+ bool bootstrap; /* true if BootstrapProcessing */
+
+ /* ----------------
+ * see if we're running in BootstrapProcessing mode
+ * ----------------
+ */
+ bootstrap = IsBootstrapProcessingMode();
+
+ /* ----------------
+ * turn on the exception handler. Note: we cannot use elog, Assert,
+ * AssertState, etc. until after exception handling is on.
+ * ----------------
+ */
+ EnableExceptionHandling(true);
+
+ /* ----------------
+ * A stupid check to make sure we don't call this more than once.
+ * But things like ReinitPostgres() get around this by just diddling
+ * the PostgresIsInitialized flag.
+ * ----------------
+ */
+ AssertState(!PostgresIsInitialized);
+
+ /* ----------------
+ * Memory system initialization.
+ * (we may call palloc after EnableMemoryContext())
+ *
+ * Note EnableMemoryContext() must happen before EnablePortalManager().
+ * ----------------
+ */
+ EnableMemoryContext(true); /* initializes the "top context" */
+ EnablePortalManager(true); /* memory for portal/transaction stuff */
+
+ /* ----------------
+ * initialize the backend local portal stack used by
+ * internal PQ function calls. see src/lib/libpq/be-dumpdata.c
+ * This is different from the "portal manager" so this goes here.
+ * -cim 2/12/91
+ * ----------------
+ */
+ be_portalinit();
+
+ /* ----------------
+ * attach to shared memory and semaphores, and initialize our
+ * input/output/debugging file descriptors.
+ * ----------------
+ */
+ InitCommunication();
+ InitStdio();
+
+ /*
+ * initialize the local buffer manager
+ */
+ InitLocalBuffer();
+ if (!TransactionFlushEnabled())
+ on_exitpg(FlushBufferPool, (caddr_t) NULL);
+ if (bootstrap)
+ {
+ SetDatabasePath(".");
+ SetDatabaseName(name);
+ }
+ else
+ {
+ DoChdirAndInitDatabaseNameAndPath(name);
+ }
+
+ /*
+ * ******************************** code after this point assumes we
+ * are in the proper directory! ********************************
+ *
+ */
+
+ /* ----------------
+ * initialize the database id used for system caches and lock tables
+ * ----------------
+ */
+ InitMyDatabaseId();
+
+ smgrinit();
+
+ /* ----------------
+ * initialize the transaction system and the relation descriptor
+ * cache. Note we have to make certain the lock manager is off while
+ * we do this.
+ * ----------------
+ */
+ AmiTransactionOverride(IsBootstrapProcessingMode());
+ LockDisable(true);
+
+ /*
+ * Part of the initialization processing done here sets a read lock on
+ * pg_log. Since locking is disabled the set doesn't have intended
+ * effect of locking out writers, but this is ok, since we only lock
+ * it to examine AMI transaction status, and this is never written
+ * after initdb is done. -mer 15 June 1992
+ */
+ RelationInitialize(); /* pre-allocated reldescs created here */
+ InitializeTransactionSystem(); /* pg_log,etc init/crash recovery
+ * here */
+
+ LockDisable(false);
+
+ /* ----------------
+ * anyone knows what this does? something having to do with
+ * system catalog cache invalidation in the case of multiple
+ * backends, I think -cim 10/3/90
+ * Sets up MyBackendId a unique backend identifier.
+ * ----------------
+ */
+ InitSharedInvalidationState();
+
+ /* ----------------
+ * Set up a per backend process in shared memory. Must be done after
+ * InitSharedInvalidationState() as it relies on MyBackendId being
+ * initialized already. XXX -mer 11 Aug 1991
+ * ----------------
+ */
+ InitProcess(PostgresIpcKey);
+
+ if (MyBackendId > MaxBackendId || MyBackendId <= 0)
+ {
+ elog(FATAL, "cinit2: bad backend id %d (%d)",
+ MyBackendTag,
+ MyBackendId);
+ }
+
+ /* ----------------
+ * initialize the access methods.
+ * ----------------
+ */
+ initam();
+
+ /* ----------------
+ * initialize all the system catalog caches.
+ * ----------------
+ */
+ zerocaches();
+ InitCatalogCache();
+
+ /* ----------------
+ * set ourselves to the proper user id and figure out our postgres
+ * user id. If we ever add security so that we check for valid
+ * postgres users, we might do it here.
+ * ----------------
+ */
+ InitUserid();
+
+ /* ----------------
+ * ok, all done, now let's make sure we don't do it again.
+ * ----------------
+ */
+ PostgresIsInitialized = true;
+/* on_exitpg(DestroyLocalRelList, (caddr_t) NULL); */
+
+ /* ----------------
+ * Done with "InitPostgres", now change to NormalProcessing unless
+ * we're in BootstrapProcessing mode.
+ * ----------------
+ */
+ if (!bootstrap)
+ SetProcessingMode(NormalProcessing);
+/* if (testFlag || lockingOff) */
+ if (lockingOff)
+ LockDisable(true);
+}
diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c
index b939c2c05e1..57a9950dea3 100644
--- a/src/backend/utils/misc/superuser.c
+++ b/src/backend/utils/misc/superuser.c
@@ -2,16 +2,16 @@
*
* superuser.c--
*
- * The superuser() function. Determines if user has superuser privilege.
+ * The superuser() function. Determines if user has superuser privilege.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.2 1996/11/03 23:46:28 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.3 1997/09/07 04:53:52 momjian Exp $
*
* DESCRIPTION
- * See superuser().
+ * See superuser().
*-------------------------------------------------------------------------
*/
@@ -20,20 +20,18 @@
#include <catalog/pg_user.h>
bool
-superuser(void) {
+superuser(void)
+{
/*--------------------------------------------------------------------------
- The Postgres user running this command has Postgres superuser
- privileges.
+ The Postgres user running this command has Postgres superuser
+ privileges.
--------------------------------------------------------------------------*/
- extern char *UserName; /* defined in global.c */
+ extern char *UserName; /* defined in global.c */
- HeapTuple utup;
+ HeapTuple utup;
- utup = SearchSysCacheTuple(USENAME, PointerGetDatum(UserName),
- 0,0,0);
- Assert(utup != NULL);
- return ((Form_pg_user)GETSTRUCT(utup))->usesuper;
+ utup = SearchSysCacheTuple(USENAME, PointerGetDatum(UserName),
+ 0, 0, 0);
+ Assert(utup != NULL);
+ return ((Form_pg_user) GETSTRUCT(utup))->usesuper;
}
-
-
-
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index 8e0482de38c..c07fb1bd587 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -1,33 +1,34 @@
/*-------------------------------------------------------------------------
*
* aset.c--
- * Allocation set definitions.
+ * Allocation set definitions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.5 1997/08/19 21:35:54 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.6 1997/09/07 04:54:01 momjian Exp $
*
* NOTE
- * XXX This is a preliminary implementation which lacks fail-fast
- * XXX validity checking of arguments.
+ * XXX This is a preliminary implementation which lacks fail-fast
+ * XXX validity checking of arguments.
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include "postgres.h"
-#include "utils/excid.h" /* for ExhaustedMemory */
-#include "utils/memutils.h" /* where funnction declarations go */
+#include "utils/excid.h" /* for ExhaustedMemory */
+#include "utils/memutils.h" /* where funnction declarations go */
#ifndef HAVE_MEMMOVE
-# include <regex/utils.h>
+#include <regex/utils.h>
#else
-# include <string.h>
+#include <string.h>
#endif
-static void AllocPointerDump(AllocPointer pointer);
-static int AllocSetIterate(AllocSet set,
- void (*function)(AllocPointer pointer));
+static void AllocPointerDump(AllocPointer pointer);
+static int
+AllocSetIterate(AllocSet set,
+ void (*function) (AllocPointer pointer));
#undef AllocSetReset
#undef malloc
@@ -39,12 +40,13 @@ static int AllocSetIterate(AllocSet set,
/*
* AllocElem --
- * Allocation element.
+ * Allocation element.
*/
-typedef struct AllocElemData {
- OrderedElemData elemData; /* elem in AllocSet */
- Size size;
-} AllocElemData;
+typedef struct AllocElemData
+{
+ OrderedElemData elemData; /* elem in AllocSet */
+ Size size;
+} AllocElemData;
typedef AllocElemData *AllocElem;
@@ -55,21 +57,21 @@ typedef AllocElemData *AllocElem;
/*
* AllocPointerGetAllocElem --
- * Returns allocation (internal) elem given (external) pointer.
+ * Returns allocation (internal) elem given (external) pointer.
*/
-#define AllocPointerGetAllocElem(pointer) (&((AllocElem)(pointer))[-1])
+#define AllocPointerGetAllocElem(pointer) (&((AllocElem)(pointer))[-1])
/*
* AllocElemGetAllocPointer --
- * Returns allocation (external) pointer given (internal) elem.
+ * Returns allocation (external) pointer given (internal) elem.
*/
-#define AllocElemGetAllocPointer(alloc) ((AllocPointer)&(alloc)[1])
+#define AllocElemGetAllocPointer(alloc) ((AllocPointer)&(alloc)[1])
/*
* AllocElemIsValid --
- * True iff alloc is valid.
+ * True iff alloc is valid.
*/
-#define AllocElemIsValid(alloc) PointerIsValid(alloc)
+#define AllocElemIsValid(alloc) PointerIsValid(alloc)
/* non-export function prototypes */
static AllocPointer AllocSetGetFirst(AllocSet set);
@@ -79,242 +81,250 @@ static AllocPointer AllocPointerGetNext(AllocPointer pointer);
* Public routines
*/
-/*
- * AllocPointerIsValid(pointer)
- * AllocSetIsValid(set)
+/*
+ * AllocPointerIsValid(pointer)
+ * AllocSetIsValid(set)
*
- * .. are now macros in aset.h -cim 4/27/91
+ * .. are now macros in aset.h -cim 4/27/91
*/
/*
* AllocSetInit --
- * Initializes given allocation set.
+ * Initializes given allocation set.
*
* Note:
- * The semantics of the mode are explained above. Limit is ignored
- * for dynamic and static modes.
+ * The semantics of the mode are explained above. Limit is ignored
+ * for dynamic and static modes.
*
* Exceptions:
- * BadArg if set is invalid pointer.
- * BadArg if mode is invalid.
+ * BadArg if set is invalid pointer.
+ * BadArg if mode is invalid.
*/
void
AllocSetInit(AllocSet set, AllocMode mode, Size limit)
{
- AssertArg(PointerIsValid(set));
- AssertArg((int)DynamicAllocMode <= (int)mode);
- AssertArg((int)mode <= (int)BoundedAllocMode);
-
- /*
- * XXX mode is currently ignored and treated as DynamicAllocMode.
- * XXX limit is also ignored. This affects this whole file.
- */
-
- OrderedSetInit(&set->setData, offsetof(AllocElemData, elemData));
+ AssertArg(PointerIsValid(set));
+ AssertArg((int) DynamicAllocMode <= (int) mode);
+ AssertArg((int) mode <= (int) BoundedAllocMode);
+
+ /*
+ * XXX mode is currently ignored and treated as DynamicAllocMode. XXX
+ * limit is also ignored. This affects this whole file.
+ */
+
+ OrderedSetInit(&set->setData, offsetof(AllocElemData, elemData));
}
/*
* AllocSetReset --
- * Frees memory which is allocated in the given set.
+ * Frees memory which is allocated in the given set.
*
* Exceptions:
- * BadArg if set is invalid.
+ * BadArg if set is invalid.
*/
void
AllocSetReset(AllocSet set)
{
- AllocPointer pointer;
-
- AssertArg(AllocSetIsValid(set));
-
- while (AllocPointerIsValid(pointer = AllocSetGetFirst(set))) {
- AllocSetFree(set, pointer);
- }
+ AllocPointer pointer;
+
+ AssertArg(AllocSetIsValid(set));
+
+ while (AllocPointerIsValid(pointer = AllocSetGetFirst(set)))
+ {
+ AllocSetFree(set, pointer);
+ }
}
#ifdef NOT_USED
void
AllocSetReset_debug(char *file, int line, AllocSet set)
{
- AllocPointer pointer;
-
- AssertArg(AllocSetIsValid(set));
-
- while (AllocPointerIsValid(pointer = AllocSetGetFirst(set))) {
- AllocSetFree(set, pointer);
- }
+ AllocPointer pointer;
+
+ AssertArg(AllocSetIsValid(set));
+
+ while (AllocPointerIsValid(pointer = AllocSetGetFirst(set)))
+ {
+ AllocSetFree(set, pointer);
+ }
}
+
#endif
/*
* AllocSetContains --
- * True iff allocation set contains given allocation element.
+ * True iff allocation set contains given allocation element.
*
* Exceptions:
- * BadArg if set is invalid.
- * BadArg if pointer is invalid.
+ * BadArg if set is invalid.
+ * BadArg if pointer is invalid.
*/
bool
AllocSetContains(AllocSet set, AllocPointer pointer)
{
- AssertArg(AllocSetIsValid(set));
- AssertArg(AllocPointerIsValid(pointer));
-
- return (OrderedSetContains(&set->setData,
- &AllocPointerGetAllocElem(pointer)->elemData));
+ AssertArg(AllocSetIsValid(set));
+ AssertArg(AllocPointerIsValid(pointer));
+
+ return (OrderedSetContains(&set->setData,
+ &AllocPointerGetAllocElem(pointer)->elemData));
}
/*
* AllocSetAlloc --
- * Returns pointer to allocated memory of given size; memory is added
- * to the set.
+ * Returns pointer to allocated memory of given size; memory is added
+ * to the set.
*
* Exceptions:
- * BadArg if set is invalid.
- * MemoryExhausted if allocation fails.
+ * BadArg if set is invalid.
+ * MemoryExhausted if allocation fails.
*/
AllocPointer
AllocSetAlloc(AllocSet set, Size size)
{
- AllocElem alloc;
-
- AssertArg(AllocSetIsValid(set));
-
- /* allocate */
- alloc = (AllocElem)malloc(sizeof (*alloc) + size);
-
- if (!PointerIsValid(alloc)) {
- elog (FATAL, "palloc failure: memory exhausted");
- }
-
- /* add to allocation list */
- OrderedElemPushInto(&alloc->elemData, &set->setData);
-
- /* set size */
- alloc->size = size;
-
- return (AllocElemGetAllocPointer(alloc));
+ AllocElem alloc;
+
+ AssertArg(AllocSetIsValid(set));
+
+ /* allocate */
+ alloc = (AllocElem) malloc(sizeof(*alloc) + size);
+
+ if (!PointerIsValid(alloc))
+ {
+ elog(FATAL, "palloc failure: memory exhausted");
+ }
+
+ /* add to allocation list */
+ OrderedElemPushInto(&alloc->elemData, &set->setData);
+
+ /* set size */
+ alloc->size = size;
+
+ return (AllocElemGetAllocPointer(alloc));
}
/*
* AllocSetFree --
- * Frees allocated memory; memory is removed from the set.
+ * Frees allocated memory; memory is removed from the set.
*
* Exceptions:
- * BadArg if set is invalid.
- * BadArg if pointer is invalid.
- * BadArg if pointer is not member of set.
+ * BadArg if set is invalid.
+ * BadArg if pointer is invalid.
+ * BadArg if pointer is not member of set.
*/
void
AllocSetFree(AllocSet set, AllocPointer pointer)
{
- AllocElem alloc;
-
- /* AssertArg(AllocSetIsValid(set)); */
- /* AssertArg(AllocPointerIsValid(pointer)); */
- AssertArg(AllocSetContains(set, pointer));
-
- alloc = AllocPointerGetAllocElem(pointer);
-
- /* remove from allocation set */
- OrderedElemPop(&alloc->elemData);
-
- /* free storage */
- free(alloc);
+ AllocElem alloc;
+
+ /* AssertArg(AllocSetIsValid(set)); */
+ /* AssertArg(AllocPointerIsValid(pointer)); */
+ AssertArg(AllocSetContains(set, pointer));
+
+ alloc = AllocPointerGetAllocElem(pointer);
+
+ /* remove from allocation set */
+ OrderedElemPop(&alloc->elemData);
+
+ /* free storage */
+ free(alloc);
}
/*
* AllocSetRealloc --
- * Returns new pointer to allocated memory of given size; this memory
- * is added to the set. Memory associated with given pointer is copied
- * into the new memory, and the old memory is freed.
+ * Returns new pointer to allocated memory of given size; this memory
+ * is added to the set. Memory associated with given pointer is copied
+ * into the new memory, and the old memory is freed.
*
* Exceptions:
- * BadArg if set is invalid.
- * BadArg if pointer is invalid.
- * BadArg if pointer is not member of set.
- * MemoryExhausted if allocation fails.
+ * BadArg if set is invalid.
+ * BadArg if pointer is invalid.
+ * BadArg if pointer is not member of set.
+ * MemoryExhausted if allocation fails.
*/
AllocPointer
AllocSetRealloc(AllocSet set, AllocPointer pointer, Size size)
{
- AllocPointer newPointer;
- AllocElem alloc;
-
- /* AssertArg(AllocSetIsValid(set)); */
- /* AssertArg(AllocPointerIsValid(pointer)); */
- AssertArg(AllocSetContains(set, pointer));
-
- /*
- * Calling realloc(3) directly is not be possible (unless we use
- * our own hacked version of malloc) since we must keep the
- * allocations in the allocation set.
- */
-
- alloc = AllocPointerGetAllocElem(pointer);
-
- /* allocate new pointer */
- newPointer = AllocSetAlloc(set, size);
-
- /* fill new memory */
- memmove(newPointer, pointer, (alloc->size < size) ? alloc->size : size);
-
- /* free old pointer */
- AllocSetFree(set, pointer);
-
- return (newPointer);
+ AllocPointer newPointer;
+ AllocElem alloc;
+
+ /* AssertArg(AllocSetIsValid(set)); */
+ /* AssertArg(AllocPointerIsValid(pointer)); */
+ AssertArg(AllocSetContains(set, pointer));
+
+ /*
+ * Calling realloc(3) directly is not be possible (unless we use our
+ * own hacked version of malloc) since we must keep the allocations in
+ * the allocation set.
+ */
+
+ alloc = AllocPointerGetAllocElem(pointer);
+
+ /* allocate new pointer */
+ newPointer = AllocSetAlloc(set, size);
+
+ /* fill new memory */
+ memmove(newPointer, pointer, (alloc->size < size) ? alloc->size : size);
+
+ /* free old pointer */
+ AllocSetFree(set, pointer);
+
+ return (newPointer);
}
/*
* AllocSetIterate --
- * Returns size of set. Iterates through set elements calling function
- * (if valid) on each.
+ * Returns size of set. Iterates through set elements calling function
+ * (if valid) on each.
*
* Note:
- * This was written as an aid to debugging. It is intended for
- * debugging use only.
+ * This was written as an aid to debugging. It is intended for
+ * debugging use only.
*
* Exceptions:
- * BadArg if set is invalid.
+ * BadArg if set is invalid.
*/
static int
AllocSetIterate(AllocSet set,
- void (*function)(AllocPointer pointer))
+ void (*function) (AllocPointer pointer))
{
- int count = 0;
- AllocPointer pointer;
-
- AssertArg(AllocSetIsValid(set));
-
- for (pointer = AllocSetGetFirst(set);
- AllocPointerIsValid(pointer);
- pointer = AllocPointerGetNext(pointer)) {
-
- if (PointerIsValid(function)) {
- (*function)(pointer);
+ int count = 0;
+ AllocPointer pointer;
+
+ AssertArg(AllocSetIsValid(set));
+
+ for (pointer = AllocSetGetFirst(set);
+ AllocPointerIsValid(pointer);
+ pointer = AllocPointerGetNext(pointer))
+ {
+
+ if (PointerIsValid(function))
+ {
+ (*function) (pointer);
+ }
+ count += 1;
}
- count += 1;
- }
-
- return (count);
+
+ return (count);
}
#ifdef NOT_USED
int
AllocSetCount(AllocSet set)
{
- int count = 0;
- AllocPointer pointer;
-
- AssertArg(AllocSetIsValid(set));
-
- for (pointer = AllocSetGetFirst(set);
- AllocPointerIsValid(pointer);
- pointer = AllocPointerGetNext(pointer)) {
- count++;
- }
- return count;
+ int count = 0;
+ AllocPointer pointer;
+
+ AssertArg(AllocSetIsValid(set));
+
+ for (pointer = AllocSetGetFirst(set);
+ AllocPointerIsValid(pointer);
+ pointer = AllocPointerGetNext(pointer))
+ {
+ count++;
+ }
+ return count;
}
+
#endif
/*
@@ -323,45 +333,47 @@ AllocSetCount(AllocSet set)
/*
* AllocSetGetFirst --
- * Returns "first" allocation pointer in a set.
+ * Returns "first" allocation pointer in a set.
*
* Note:
- * Assumes set is valid.
+ * Assumes set is valid.
*/
-static AllocPointer
+static AllocPointer
AllocSetGetFirst(AllocSet set)
{
- AllocElem alloc;
-
- alloc = (AllocElem)OrderedSetGetHead(&set->setData);
-
- if (!AllocElemIsValid(alloc)) {
- return (NULL);
- }
-
- return (AllocElemGetAllocPointer(alloc));
+ AllocElem alloc;
+
+ alloc = (AllocElem) OrderedSetGetHead(&set->setData);
+
+ if (!AllocElemIsValid(alloc))
+ {
+ return (NULL);
+ }
+
+ return (AllocElemGetAllocPointer(alloc));
}
/*
* AllocPointerGetNext --
- * Returns "successor" allocation pointer.
+ * Returns "successor" allocation pointer.
*
* Note:
- * Assumes pointer is valid.
+ * Assumes pointer is valid.
*/
-static AllocPointer
+static AllocPointer
AllocPointerGetNext(AllocPointer pointer)
{
- AllocElem alloc;
-
- alloc = (AllocElem)
- OrderedElemGetSuccessor(&AllocPointerGetAllocElem(pointer)->elemData);
-
- if (!AllocElemIsValid(alloc)) {
- return (NULL);
- }
-
- return (AllocElemGetAllocPointer(alloc));
+ AllocElem alloc;
+
+ alloc = (AllocElem)
+ OrderedElemGetSuccessor(&AllocPointerGetAllocElem(pointer)->elemData);
+
+ if (!AllocElemIsValid(alloc))
+ {
+ return (NULL);
+ }
+
+ return (AllocElemGetAllocPointer(alloc));
}
@@ -371,22 +383,23 @@ AllocPointerGetNext(AllocPointer pointer)
/*
* XXX AllocPointerDump --
- * Displays allocated pointer.
+ * Displays allocated pointer.
*/
static void
AllocPointerDump(AllocPointer pointer)
{
- printf("\t%-10ld@ %0#lx\n", ((long*)pointer)[-1], (long)pointer); /* XXX */
+ printf("\t%-10ld@ %0#lx\n", ((long *) pointer)[-1], (long) pointer); /* XXX */
}
/*
* AllocSetDump --
- * Displays allocated set.
+ * Displays allocated set.
*/
void
AllocSetDump(AllocSet set)
{
- int count;
- count = AllocSetIterate(set, AllocPointerDump);
- printf("\ttotal %d allocations\n", count);
+ int count;
+
+ count = AllocSetIterate(set, AllocPointerDump);
+ printf("\ttotal %d allocations\n", count);
}
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index df2eb480817..dbd1b6e19f6 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* mcxt.c--
- * POSTGRES memory context code.
+ * POSTGRES memory context code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.3 1997/08/19 21:35:57 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/mcxt.c,v 1.4 1997/09/07 04:54:08 momjian Exp $
*
*-------------------------------------------------------------------------
*/
-#include <stdio.h> /* XXX for printf debugging */
+#include <stdio.h> /* XXX for printf debugging */
#include "postgres.h"
@@ -35,90 +35,93 @@
/*
* Global State
*/
-static int MemoryContextEnableCount = 0;
+static int MemoryContextEnableCount = 0;
+
#define MemoryContextEnabled (MemoryContextEnableCount > 0)
-static OrderedSetData ActiveGlobalMemorySetData; /* uninitialized */
+static OrderedSetData ActiveGlobalMemorySetData; /* uninitialized */
+
#define ActiveGlobalMemorySet (&ActiveGlobalMemorySetData)
/*
* description of allocated memory representation goes here
*/
-#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
+#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
#define PSIZEALL(PTR) (*((int32 *)(PTR) - 1) + sizeof (int32))
#define PSIZESKIP(PTR) ((char *)((int32 *)(PTR) + 1))
#define PSIZEFIND(PTR) ((char *)((int32 *)(PTR) - 1))
-#define PSIZESPACE(LEN) ((LEN) + sizeof (int32))
+#define PSIZESPACE(LEN) ((LEN) + sizeof (int32))
/*
* AllocSizeIsValid --
- * True iff 0 < size and size <= MaxAllocSize.
+ * True iff 0 < size and size <= MaxAllocSize.
*/
-#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
+#define AllocSizeIsValid(size) (0 < (size) && (size) <= MaxAllocSize)
/*****************************************************************************
- * GLOBAL MEMORY *
+ * GLOBAL MEMORY *
*****************************************************************************/
/*
* CurrentMemoryContext --
- * Memory context for general global allocations.
+ * Memory context for general global allocations.
*/
MemoryContext CurrentMemoryContext = NULL;
/*****************************************************************************
- * PRIVATE DEFINITIONS *
+ * PRIVATE DEFINITIONS *
*****************************************************************************/
-static Pointer GlobalMemoryAlloc(GlobalMemory this, Size size);
-static void GlobalMemoryFree(GlobalMemory this, Pointer pointer);
-static Pointer GlobalMemoryRealloc(GlobalMemory this, Pointer pointer,
- Size size);
-static char *GlobalMemoryGetName(GlobalMemory this);
-static void GlobalMemoryDump(GlobalMemory this);
+static Pointer GlobalMemoryAlloc(GlobalMemory this, Size size);
+static void GlobalMemoryFree(GlobalMemory this, Pointer pointer);
+static Pointer
+GlobalMemoryRealloc(GlobalMemory this, Pointer pointer,
+ Size size);
+static char *GlobalMemoryGetName(GlobalMemory this);
+static void GlobalMemoryDump(GlobalMemory this);
+
#ifdef NOT_USED
-static void DumpGlobalMemories(void);
+static void DumpGlobalMemories(void);
+
#endif
/*
* Global Memory Methods
*/
-static struct MemoryContextMethodsData GlobalContextMethodsData = {
- GlobalMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
- GlobalMemoryFree, /* void (*)(this, Pointer) pfree */
- GlobalMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
- GlobalMemoryGetName, /* char* (*)(this) getName */
- GlobalMemoryDump /* void (*)(this) dump */
+static struct MemoryContextMethodsData GlobalContextMethodsData = {
+ GlobalMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
+ GlobalMemoryFree, /* void (*)(this, Pointer) pfree */
+ GlobalMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
+ GlobalMemoryGetName, /* char* (*)(this) getName */
+ GlobalMemoryDump /* void (*)(this) dump */
};
/*
* Note:
- * TopGlobalMemory is handled specially because of bootstrapping.
+ * TopGlobalMemory is handled specially because of bootstrapping.
*/
/* extern bool EqualGlobalMemory(); */
static struct GlobalMemory TopGlobalMemoryData = {
- T_GlobalMemory, /* NodeTag tag */
- &GlobalContextMethodsData, /* ContextMethods method */
- { { 0 } }, /* uninitialized
- * OrderedSetData allocSetD
- */
- "TopGlobal", /* char* name */
- { 0 } /* uninitialized OrderedElemData elemD */
+ T_GlobalMemory, /* NodeTag tag */
+ &GlobalContextMethodsData, /* ContextMethods method */
+ {{0}}, /* uninitialized OrderedSetData allocSetD */
+ "TopGlobal", /* char* name */
+ {0} /* uninitialized OrderedElemData elemD */
};
/*
* TopMemoryContext --
- * Memory context for general global allocations.
+ * Memory context for general global allocations.
*
* Note:
- * Don't use this memory context for random allocations. If you
- * allocate something here, you are expected to clean it up when
- * appropriate.
+ * Don't use this memory context for random allocations. If you
+ * allocate something here, you are expected to clean it up when
+ * appropriate.
*/
-MemoryContext TopMemoryContext = (MemoryContext)&TopGlobalMemoryData;
+MemoryContext TopMemoryContext = (MemoryContext) & TopGlobalMemoryData;
@@ -129,213 +132,223 @@ MemoryContext TopMemoryContext = (MemoryContext)&TopGlobalMemoryData;
/*
* EnableMemoryContext --
- * Enables/disables memory management and global contexts.
+ * Enables/disables memory management and global contexts.
*
* Note:
- * This must be called before creating contexts or allocating memory.
- * This must be called before other contexts are created.
+ * This must be called before creating contexts or allocating memory.
+ * This must be called before other contexts are created.
*
* Exceptions:
- * BadArg if on is invalid.
- * BadState if on is false when disabled.
+ * BadArg if on is invalid.
+ * BadState if on is false when disabled.
*/
void
EnableMemoryContext(bool on)
{
- static bool processing = false;
-
- AssertState(!processing);
- AssertArg(BoolIsValid(on));
-
- if (BypassEnable(&MemoryContextEnableCount, on)) {
- return;
- }
-
- processing = true;
-
- if (on) { /* initialize */
- /* initialize TopGlobalMemoryData.setData */
- AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode,
- (Size)0);
-
- /* make TopGlobalMemoryData member of ActiveGlobalMemorySet */
- OrderedSetInit(ActiveGlobalMemorySet,
- offsetof(struct GlobalMemory, elemData));
- OrderedElemPushInto(&TopGlobalMemoryData.elemData,
- ActiveGlobalMemorySet);
-
- /* initialize CurrentMemoryContext */
- CurrentMemoryContext = TopMemoryContext;
-
- } else { /* cleanup */
- GlobalMemory context;
-
- /* walk the list of allocations */
- while (PointerIsValid(context = (GlobalMemory)
- OrderedSetGetHead(ActiveGlobalMemorySet))) {
-
- if (context == &TopGlobalMemoryData) {
- /* don't free it and clean it last */
- OrderedElemPop(&TopGlobalMemoryData.elemData);
- } else {
- GlobalMemoryDestroy(context);
- }
- /* what is needed for the top? */
+ static bool processing = false;
+
+ AssertState(!processing);
+ AssertArg(BoolIsValid(on));
+
+ if (BypassEnable(&MemoryContextEnableCount, on))
+ {
+ return;
}
-
- /*
- * Freeing memory here should be safe as this is called
- * only after all modules which allocate in TopMemoryContext
- * have been disabled.
- */
-
- /* step through remaining allocations and log */
- /* AllocSetStep(...); */
-
- /* deallocate whatever is left */
- AllocSetReset(&TopGlobalMemoryData.setData);
- }
-
- processing = false;
+
+ processing = true;
+
+ if (on)
+ { /* initialize */
+ /* initialize TopGlobalMemoryData.setData */
+ AllocSetInit(&TopGlobalMemoryData.setData, DynamicAllocMode,
+ (Size) 0);
+
+ /* make TopGlobalMemoryData member of ActiveGlobalMemorySet */
+ OrderedSetInit(ActiveGlobalMemorySet,
+ offsetof(struct GlobalMemory, elemData));
+ OrderedElemPushInto(&TopGlobalMemoryData.elemData,
+ ActiveGlobalMemorySet);
+
+ /* initialize CurrentMemoryContext */
+ CurrentMemoryContext = TopMemoryContext;
+
+ }
+ else
+ { /* cleanup */
+ GlobalMemory context;
+
+ /* walk the list of allocations */
+ while (PointerIsValid(context = (GlobalMemory)
+ OrderedSetGetHead(ActiveGlobalMemorySet)))
+ {
+
+ if (context == &TopGlobalMemoryData)
+ {
+ /* don't free it and clean it last */
+ OrderedElemPop(&TopGlobalMemoryData.elemData);
+ }
+ else
+ {
+ GlobalMemoryDestroy(context);
+ }
+ /* what is needed for the top? */
+ }
+
+ /*
+ * Freeing memory here should be safe as this is called only after
+ * all modules which allocate in TopMemoryContext have been
+ * disabled.
+ */
+
+ /* step through remaining allocations and log */
+ /* AllocSetStep(...); */
+
+ /* deallocate whatever is left */
+ AllocSetReset(&TopGlobalMemoryData.setData);
+ }
+
+ processing = false;
}
/*
* MemoryContextAlloc --
- * Returns pointer to aligned allocated memory in the given context.
+ * Returns pointer to aligned allocated memory in the given context.
*
* Note:
- * none
+ * none
*
* Exceptions:
- * BadState if called before InitMemoryManager.
- * BadArg if context is invalid or if size is 0.
- * BadAllocSize if size is larger than MaxAllocSize.
+ * BadState if called before InitMemoryManager.
+ * BadArg if context is invalid or if size is 0.
+ * BadAllocSize if size is larger than MaxAllocSize.
*/
Pointer
MemoryContextAlloc(MemoryContext context, Size size)
{
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
-
- LogTrap(!AllocSizeIsValid(size), BadAllocSize,
- ("size=%d [0x%x]", size, size));
-
- return (context->method->alloc(context, size));
+ AssertState(MemoryContextEnabled);
+ AssertArg(MemoryContextIsValid(context));
+
+ LogTrap(!AllocSizeIsValid(size), BadAllocSize,
+ ("size=%d [0x%x]", size, size));
+
+ return (context->method->alloc(context, size));
}
/*
* MemoryContextFree --
- * Frees allocated memory referenced by pointer in the given context.
+ * Frees allocated memory referenced by pointer in the given context.
*
* Note:
- * none
+ * none
*
* Exceptions:
- * ???
- * BadArgumentsErr if firstTime is true for subsequent calls.
+ * ???
+ * BadArgumentsErr if firstTime is true for subsequent calls.
*/
void
MemoryContextFree(MemoryContext context, Pointer pointer)
{
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
- AssertArg(PointerIsValid(pointer));
-
- context->method->free_p(context, pointer);
+ AssertState(MemoryContextEnabled);
+ AssertArg(MemoryContextIsValid(context));
+ AssertArg(PointerIsValid(pointer));
+
+ context->method->free_p(context, pointer);
}
/*
* MemoryContextRelloc --
- * Returns pointer to aligned allocated memory in the given context.
+ * Returns pointer to aligned allocated memory in the given context.
*
* Note:
- * none
+ * none
*
* Exceptions:
- * ???
- * BadArgumentsErr if firstTime is true for subsequent calls.
+ * ???
+ * BadArgumentsErr if firstTime is true for subsequent calls.
*/
Pointer
MemoryContextRealloc(MemoryContext context,
- Pointer pointer,
- Size size)
+ Pointer pointer,
+ Size size)
{
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
- AssertArg(PointerIsValid(pointer));
-
- LogTrap(!AllocSizeIsValid(size), BadAllocSize,
- ("size=%d [0x%x]", size, size));
-
- return (context->method->realloc(context, pointer, size));
+ AssertState(MemoryContextEnabled);
+ AssertArg(MemoryContextIsValid(context));
+ AssertArg(PointerIsValid(pointer));
+
+ LogTrap(!AllocSizeIsValid(size), BadAllocSize,
+ ("size=%d [0x%x]", size, size));
+
+ return (context->method->realloc(context, pointer, size));
}
/*
* MemoryContextGetName --
- * Returns pointer to aligned allocated memory in the given context.
+ * Returns pointer to aligned allocated memory in the given context.
*
* Note:
- * none
+ * none
*
* Exceptions:
- * ???
- * BadArgumentsErr if firstTime is true for subsequent calls.
+ * ???
+ * BadArgumentsErr if firstTime is true for subsequent calls.
*/
#ifdef NOT_USED
-char*
+char *
MemoryContextGetName(MemoryContext context)
{
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
-
- return (context->method->getName(context));
+ AssertState(MemoryContextEnabled);
+ AssertArg(MemoryContextIsValid(context));
+
+ return (context->method->getName(context));
}
+
#endif
/*
* PointerGetAllocSize --
- * Returns size of aligned allocated memory given pointer to it.
+ * Returns size of aligned allocated memory given pointer to it.
*
* Note:
- * none
+ * none
*
* Exceptions:
- * ???
- * BadArgumentsErr if firstTime is true for subsequent calls.
+ * ???
+ * BadArgumentsErr if firstTime is true for subsequent calls.
*/
#ifdef NOT_USED
Size
PointerGetAllocSize(Pointer pointer)
{
- AssertState(MemoryContextEnabled);
- AssertArg(PointerIsValid(pointer));
-
- return (PSIZE(pointer));
+ AssertState(MemoryContextEnabled);
+ AssertArg(PointerIsValid(pointer));
+
+ return (PSIZE(pointer));
}
+
#endif
/*
* MemoryContextSwitchTo --
- * Returns the current context; installs the given context.
+ * Returns the current context; installs the given context.
*
* Note:
- * none
+ * none
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
+ * BadState if called when disabled.
+ * BadArg if context is invalid.
*/
MemoryContext
MemoryContextSwitchTo(MemoryContext context)
{
- MemoryContext old;
-
- AssertState(MemoryContextEnabled);
- AssertArg(MemoryContextIsValid(context));
-
- old = CurrentMemoryContext;
- CurrentMemoryContext = context;
- return (old);
+ MemoryContext old;
+
+ AssertState(MemoryContextEnabled);
+ AssertArg(MemoryContextIsValid(context));
+
+ old = CurrentMemoryContext;
+ CurrentMemoryContext = context;
+ return (old);
}
/*
@@ -343,174 +356,178 @@ MemoryContextSwitchTo(MemoryContext context)
*/
/*
* CreateGlobalMemory --
- * Returns new global memory context.
+ * Returns new global memory context.
*
* Note:
- * Assumes name is static.
+ * Assumes name is static.
*
* Exceptions:
- * BadState if called when disabled.
- * BadState if called outside TopMemoryContext (TopGlobalMemory).
- * BadArg if name is invalid.
+ * BadState if called when disabled.
+ * BadState if called outside TopMemoryContext (TopGlobalMemory).
+ * BadArg if name is invalid.
*/
GlobalMemory
-CreateGlobalMemory(char *name) /* XXX MemoryContextName */
+CreateGlobalMemory(char *name) /* XXX MemoryContextName */
{
- GlobalMemory context;
- MemoryContext savecxt;
-
- AssertState(MemoryContextEnabled);
-
- savecxt = MemoryContextSwitchTo(TopMemoryContext);
-
- context = (GlobalMemory)newNode(sizeof(struct GlobalMemory), T_GlobalMemory);
- context->method = &GlobalContextMethodsData;
- context->name = name; /* assumes name is static */
- AllocSetInit(&context->setData, DynamicAllocMode, (Size)0);
-
- /* link the context */
- OrderedElemPushInto(&context->elemData, ActiveGlobalMemorySet);
-
- MemoryContextSwitchTo(savecxt);
- return (context);
+ GlobalMemory context;
+ MemoryContext savecxt;
+
+ AssertState(MemoryContextEnabled);
+
+ savecxt = MemoryContextSwitchTo(TopMemoryContext);
+
+ context = (GlobalMemory) newNode(sizeof(struct GlobalMemory), T_GlobalMemory);
+ context->method = &GlobalContextMethodsData;
+ context->name = name; /* assumes name is static */
+ AllocSetInit(&context->setData, DynamicAllocMode, (Size) 0);
+
+ /* link the context */
+ OrderedElemPushInto(&context->elemData, ActiveGlobalMemorySet);
+
+ MemoryContextSwitchTo(savecxt);
+ return (context);
}
/*
* GlobalMemoryDestroy --
- * Destroys given global memory context.
+ * Destroys given global memory context.
*
* Exceptions:
- * BadState if called when disabled.
- * BadState if called outside TopMemoryContext (TopGlobalMemory).
- * BadArg if context is invalid GlobalMemory.
- * BadArg if context is TopMemoryContext (TopGlobalMemory).
+ * BadState if called when disabled.
+ * BadState if called outside TopMemoryContext (TopGlobalMemory).
+ * BadArg if context is invalid GlobalMemory.
+ * BadArg if context is TopMemoryContext (TopGlobalMemory).
*/
void
GlobalMemoryDestroy(GlobalMemory context)
{
- AssertState(MemoryContextEnabled);
- AssertArg(IsA(context,GlobalMemory));
- AssertArg(context != &TopGlobalMemoryData);
-
- AllocSetReset(&context->setData);
-
- /* unlink and delete the context */
- OrderedElemPop(&context->elemData);
- MemoryContextFree(TopMemoryContext, (Pointer)context);
+ AssertState(MemoryContextEnabled);
+ AssertArg(IsA(context, GlobalMemory));
+ AssertArg(context != &TopGlobalMemoryData);
+
+ AllocSetReset(&context->setData);
+
+ /* unlink and delete the context */
+ OrderedElemPop(&context->elemData);
+ MemoryContextFree(TopMemoryContext, (Pointer) context);
}
/*****************************************************************************
- * PRIVATE *
+ * PRIVATE *
*****************************************************************************/
/*
* GlobalMemoryAlloc --
- * Returns pointer to aligned space in the global context.
+ * Returns pointer to aligned space in the global context.
*
* Exceptions:
- * ExhaustedMemory if allocation fails.
+ * ExhaustedMemory if allocation fails.
*/
-static Pointer
+static Pointer
GlobalMemoryAlloc(GlobalMemory this, Size size)
{
- return (AllocSetAlloc(&this->setData, size));
+ return (AllocSetAlloc(&this->setData, size));
}
/*
* GlobalMemoryFree --
- * Frees allocated memory in the global context.
+ * Frees allocated memory in the global context.
*
* Exceptions:
- * BadContextErr if current context is not the global context.
- * BadArgumentsErr if pointer is invalid.
+ * BadContextErr if current context is not the global context.
+ * BadArgumentsErr if pointer is invalid.
*/
static void
GlobalMemoryFree(GlobalMemory this,
- Pointer pointer)
+ Pointer pointer)
{
- AllocSetFree(&this->setData, pointer);
+ AllocSetFree(&this->setData, pointer);
}
/*
* GlobalMemoryRealloc --
- * Returns pointer to aligned space in the global context.
+ * Returns pointer to aligned space in the global context.
*
* Note:
- * Memory associated with the pointer is freed before return.
+ * Memory associated with the pointer is freed before return.
*
* Exceptions:
- * BadContextErr if current context is not the global context.
- * BadArgumentsErr if pointer is invalid.
- * NoMoreMemoryErr if allocation fails.
+ * BadContextErr if current context is not the global context.
+ * BadArgumentsErr if pointer is invalid.
+ * NoMoreMemoryErr if allocation fails.
*/
-static Pointer
+static Pointer
GlobalMemoryRealloc(GlobalMemory this,
- Pointer pointer,
- Size size)
+ Pointer pointer,
+ Size size)
{
- return (AllocSetRealloc(&this->setData, pointer, size));
+ return (AllocSetRealloc(&this->setData, pointer, size));
}
/*
* GlobalMemoryGetName --
- * Returns name string for context.
+ * Returns name string for context.
*
* Exceptions:
- * ???
+ * ???
*/
-static char*
+static char *
GlobalMemoryGetName(GlobalMemory this)
{
- return (this->name);
+ return (this->name);
}
/*
* GlobalMemoryDump --
- * Dumps global memory context for debugging.
+ * Dumps global memory context for debugging.
*
* Exceptions:
- * ???
+ * ???
*/
static void
GlobalMemoryDump(GlobalMemory this)
{
- GlobalMemory context;
-
- printf("--\n%s:\n", GlobalMemoryGetName(this));
-
- context = (GlobalMemory)OrderedElemGetPredecessor(&this->elemData);
- if (PointerIsValid(context)) {
- printf("\tpredecessor=%s\n", GlobalMemoryGetName(context));
- }
-
- context = (GlobalMemory)OrderedElemGetSuccessor(&this->elemData);
- if (PointerIsValid(context)) {
- printf("\tsucessor=%s\n", GlobalMemoryGetName(context));
- }
-
- AllocSetDump(&this->setData); /* XXX is this right interface */
+ GlobalMemory context;
+
+ printf("--\n%s:\n", GlobalMemoryGetName(this));
+
+ context = (GlobalMemory) OrderedElemGetPredecessor(&this->elemData);
+ if (PointerIsValid(context))
+ {
+ printf("\tpredecessor=%s\n", GlobalMemoryGetName(context));
+ }
+
+ context = (GlobalMemory) OrderedElemGetSuccessor(&this->elemData);
+ if (PointerIsValid(context))
+ {
+ printf("\tsucessor=%s\n", GlobalMemoryGetName(context));
+ }
+
+ AllocSetDump(&this->setData); /* XXX is this right interface */
}
/*
* DumpGlobalMemories --
- * Dumps all global memory contexts for debugging.
+ * Dumps all global memory contexts for debugging.
*
* Exceptions:
- * ???
+ * ???
*/
#ifdef NOT_USED
static void
DumpGlobalMemories()
{
- GlobalMemory context;
-
- context = (GlobalMemory)OrderedSetGetHead(&ActiveGlobalMemorySetData);
-
- while (PointerIsValid(context)) {
- GlobalMemoryDump(context);
-
- context = (GlobalMemory)OrderedElemGetSuccessor(
- &context->elemData);
- }
+ GlobalMemory context;
+
+ context = (GlobalMemory) OrderedSetGetHead(&ActiveGlobalMemorySetData);
+
+ while (PointerIsValid(context))
+ {
+ GlobalMemoryDump(context);
+
+ context = (GlobalMemory) OrderedElemGetSuccessor(
+ &context->elemData);
+ }
}
+
#endif
diff --git a/src/backend/utils/mmgr/oset.c b/src/backend/utils/mmgr/oset.c
index 6b42ee45d72..758b701ff55 100644
--- a/src/backend/utils/mmgr/oset.c
+++ b/src/backend/utils/mmgr/oset.c
@@ -1,39 +1,39 @@
/*-------------------------------------------------------------------------
*
* oset.c--
- * Fixed format ordered set definitions.
+ * Fixed format ordered set definitions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/oset.c,v 1.3 1997/08/24 23:07:50 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/oset.c,v 1.4 1997/09/07 04:54:11 momjian Exp $
*
* NOTE
- * XXX This is a preliminary implementation which lacks fail-fast
- * XXX validity checking of arguments.
+ * XXX This is a preliminary implementation which lacks fail-fast
+ * XXX validity checking of arguments.
*
*-------------------------------------------------------------------------
*/
#include "c.h"
-#include "utils/memutils.h" /* where declarations of this file goes */
+#include "utils/memutils.h" /* where declarations of this file goes */
-static Pointer OrderedElemGetBase(OrderedElem elem);
-static void OrderedElemPush(OrderedElem elem);
-static void OrderedElemPushHead(OrderedElem elem);
+static Pointer OrderedElemGetBase(OrderedElem elem);
+static void OrderedElemPush(OrderedElem elem);
+static void OrderedElemPushHead(OrderedElem elem);
/*
* OrderedElemGetBase --
- * Returns base of enclosing structure.
+ * Returns base of enclosing structure.
*/
-static Pointer
+static Pointer
OrderedElemGetBase(OrderedElem elem)
{
- if (elem == (OrderedElem) NULL)
- return (Pointer) NULL;
-
- return ((Pointer)((char*)(elem) - (elem)->set->offset));
+ if (elem == (OrderedElem) NULL)
+ return (Pointer) NULL;
+
+ return ((Pointer) ((char *) (elem) - (elem)->set->offset));
}
/*
@@ -42,20 +42,20 @@ OrderedElemGetBase(OrderedElem elem)
void
OrderedSetInit(OrderedSet set, Offset offset)
{
- set->head = (OrderedElem)&set->dummy;
- set->dummy = NULL;
- set->tail = (OrderedElem)&set->head;
- set->offset = offset;
+ set->head = (OrderedElem) & set->dummy;
+ set->dummy = NULL;
+ set->tail = (OrderedElem) & set->head;
+ set->offset = offset;
}
/*
* OrderedSetContains --
- * True iff ordered set contains given element.
+ * True iff ordered set contains given element.
*/
bool
OrderedSetContains(OrderedSet set, OrderedElem elem)
{
- return ((bool)(elem->set == set && (elem->next || elem->prev)));
+ return ((bool) (elem->set == set && (elem->next || elem->prev)));
}
/*
@@ -64,13 +64,14 @@ OrderedSetContains(OrderedSet set, OrderedElem elem)
Pointer
OrderedSetGetHead(OrderedSet set)
{
- register OrderedElem elem;
-
- elem = set->head;
- if (elem->next) {
- return (OrderedElemGetBase(elem));
- }
- return (NULL);
+ register OrderedElem elem;
+
+ elem = set->head;
+ if (elem->next)
+ {
+ return (OrderedElemGetBase(elem));
+ }
+ return (NULL);
}
/*
@@ -80,14 +81,16 @@ OrderedSetGetHead(OrderedSet set)
Pointer
OrderedSetGetTail(OrderedSet set)
{
- register OrderedElem elem;
-
- elem = set->tail;
- if (elem->prev) {
- return (OrderedElemGetBase(elem));
- }
- return (NULL);
+ register OrderedElem elem;
+
+ elem = set->tail;
+ if (elem->prev)
+ {
+ return (OrderedElemGetBase(elem));
+ }
+ return (NULL);
}
+
#endif
/*
@@ -96,11 +99,12 @@ OrderedSetGetTail(OrderedSet set)
Pointer
OrderedElemGetPredecessor(OrderedElem elem)
{
- elem = elem->prev;
- if (elem->prev) {
- return (OrderedElemGetBase(elem));
- }
- return (NULL);
+ elem = elem->prev;
+ if (elem->prev)
+ {
+ return (OrderedElemGetBase(elem));
+ }
+ return (NULL);
}
/*
@@ -109,24 +113,25 @@ OrderedElemGetPredecessor(OrderedElem elem)
Pointer
OrderedElemGetSuccessor(OrderedElem elem)
{
- elem = elem->next;
- if (elem->next) {
- return (OrderedElemGetBase(elem));
- }
- return (NULL);
+ elem = elem->next;
+ if (elem->next)
+ {
+ return (OrderedElemGetBase(elem));
+ }
+ return (NULL);
}
/*
* OrderedElemPop --
*/
-void
+void
OrderedElemPop(OrderedElem elem)
{
- elem->next->prev = elem->prev;
- elem->prev->next = elem->next;
- /* assignments used only for error detection */
- elem->next = NULL;
- elem->prev = NULL;
+ elem->next->prev = elem->prev;
+ elem->prev->next = elem->next;
+ /* assignments used only for error detection */
+ elem->next = NULL;
+ elem->prev = NULL;
}
/*
@@ -135,11 +140,11 @@ OrderedElemPop(OrderedElem elem)
void
OrderedElemPushInto(OrderedElem elem, OrderedSet set)
{
- elem->set = set;
- /* mark as unattached */
- elem->next = NULL;
- elem->prev = NULL;
- OrderedElemPush(elem);
+ elem->set = set;
+ /* mark as unattached */
+ elem->next = NULL;
+ elem->prev = NULL;
+ OrderedElemPush(elem);
}
/*
@@ -148,7 +153,7 @@ OrderedElemPushInto(OrderedElem elem, OrderedSet set)
static void
OrderedElemPush(OrderedElem elem)
{
- OrderedElemPushHead(elem);
+ OrderedElemPushHead(elem);
}
/*
@@ -157,9 +162,8 @@ OrderedElemPush(OrderedElem elem)
static void
OrderedElemPushHead(OrderedElem elem)
{
- elem->next = elem->set->head;
- elem->prev = (OrderedElem)&elem->set->head;
- elem->next->prev = elem;
- elem->prev->next = elem;
+ elem->next = elem->set->head;
+ elem->prev = (OrderedElem) & elem->set->head;
+ elem->next->prev = elem;
+ elem->prev->next = elem;
}
-
diff --git a/src/backend/utils/mmgr/palloc.c b/src/backend/utils/mmgr/palloc.c
index 8830a21f40a..f644706c911 100644
--- a/src/backend/utils/mmgr/palloc.c
+++ b/src/backend/utils/mmgr/palloc.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* palloc.c--
- * POSTGRES memory allocator code.
+ * POSTGRES memory allocator code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.3 1996/11/26 03:19:12 bryanh Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/Attic/palloc.c,v 1.4 1997/09/07 04:54:12 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,7 +25,7 @@
#include "utils/palloc.h"
/* ----------------------------------------------------------------
- * User library functions
+ * User library functions
* ----------------------------------------------------------------
*/
@@ -36,84 +36,84 @@
#undef malloc
#undef free
-/* define PALLOC_IS_MALLOC if you want palloc to go straight to the
+/* define PALLOC_IS_MALLOC if you want palloc to go straight to the
raw malloc, without concern for the extra bookkeeping needed to
ensure garbage is collected at the end of transactions - jolly 1/12/94 */
/*
* palloc --
- * Returns pointer to aligned memory of specified size.
+ * Returns pointer to aligned memory of specified size.
*
* Exceptions:
- * BadArgument if size < 1 or size >= MaxAllocSize.
- * ExhaustedMemory if allocation fails.
- * NonallocatedPointer if pointer was not returned by palloc or repalloc
- * or may have been freed already.
+ * BadArgument if size < 1 or size >= MaxAllocSize.
+ * ExhaustedMemory if allocation fails.
+ * NonallocatedPointer if pointer was not returned by palloc or repalloc
+ * or may have been freed already.
*
* pfree --
- * Frees memory associated with pointer returned from palloc or repalloc.
+ * Frees memory associated with pointer returned from palloc or repalloc.
*
* Exceptions:
- * BadArgument if pointer is invalid.
- * FreeInWrongContext if pointer was allocated in a different "context."
- * NonallocatedPointer if pointer was not returned by palloc or repalloc
- * or may have been subsequently freed.
+ * BadArgument if pointer is invalid.
+ * FreeInWrongContext if pointer was allocated in a different "context."
+ * NonallocatedPointer if pointer was not returned by palloc or repalloc
+ * or may have been subsequently freed.
*/
-void*
+void *
palloc(Size size)
{
#ifdef PALLOC_IS_MALLOC
- return malloc(size);
+ return malloc(size);
#else
- return (MemoryContextAlloc(CurrentMemoryContext, size));
-#endif /* PALLOC_IS_MALLOC */
+ return (MemoryContextAlloc(CurrentMemoryContext, size));
+#endif /* PALLOC_IS_MALLOC */
}
void
pfree(void *pointer)
-{
+{
#ifdef PALLOC_IS_MALLOC
- free(pointer);
+ free(pointer);
#else
- MemoryContextFree(CurrentMemoryContext, pointer);
-#endif /* PALLOC_IS_MALLOC */
+ MemoryContextFree(CurrentMemoryContext, pointer);
+#endif /* PALLOC_IS_MALLOC */
}
/*
* repalloc --
- * Returns pointer to aligned memory of specified size.
+ * Returns pointer to aligned memory of specified size.
*
* Side effects:
- * The returned memory is first filled with the contents of *pointer
- * up to the minimum of size and psize(pointer). Pointer is freed.
+ * The returned memory is first filled with the contents of *pointer
+ * up to the minimum of size and psize(pointer). Pointer is freed.
*
* Exceptions:
- * BadArgument if pointer is invalid or size < 1 or size >= MaxAllocSize.
- * ExhaustedMemory if allocation fails.
- * NonallocatedPointer if pointer was not returned by palloc or repalloc
- * or may have been freed already.
+ * BadArgument if pointer is invalid or size < 1 or size >= MaxAllocSize.
+ * ExhaustedMemory if allocation fails.
+ * NonallocatedPointer if pointer was not returned by palloc or repalloc
+ * or may have been freed already.
*/
-void *
+void *
repalloc(void *pointer, Size size)
{
#ifdef PALLOC_IS_MALLOC
- return realloc(pointer, size);
+ return realloc(pointer, size);
#else
- return (MemoryContextRealloc(CurrentMemoryContext, pointer, size));
+ return (MemoryContextRealloc(CurrentMemoryContext, pointer, size));
#endif
}
-/* pstrdup
- allocates space for and copies a string
- just like strdup except it uses palloc instead of malloc */
-char*
-pstrdup(char* string)
+/* pstrdup
+ allocates space for and copies a string
+ just like strdup except it uses palloc instead of malloc */
+char *
+pstrdup(char *string)
{
- char *nstr;
+ char *nstr;
- nstr = (char *)palloc(strlen(string)+1);
- strcpy(nstr, string);
+ nstr = (char *) palloc(strlen(string) + 1);
+ strcpy(nstr, string);
- return nstr;
+ return nstr;
}
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 7f1674d88db..595153b0ce6 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -1,86 +1,86 @@
/*-------------------------------------------------------------------------
*
* portalmem.c--
- * backend portal memory context management stuff
+ * backend portal memory context management stuff
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.5 1997/08/19 21:36:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.6 1997/09/07 04:54:13 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/*
* NOTES
- * Do not confuse "Portal" with "PortalEntry" (or "PortalBuffer").
- * When a PQexec() routine is run, the resulting tuples
- * find their way into a "PortalEntry". The contents of the resulting
- * "PortalEntry" can then be inspected by other PQxxx functions.
- *
- * A "Portal" is a structure used to keep track of queries of the
- * form:
- * retrieve portal FOO ( blah... ) where blah...
- *
- * When the backend sees a "retrieve portal" query, it allocates
- * a "PortalD" structure, plans the query and then stores the query
- * in the portal without executing it. Later, when the backend
- * sees a
- * fetch 1 into FOO
- *
- * the system looks up the portal named "FOO" in the portal table,
- * gets the planned query and then calls the executor with a feature of
- * '(EXEC_FOR 1). The executor then runs the query and returns a single
- * tuple. The problem is that we have to hold onto the state of the
- * portal query until we see a "close p". This means we have to be
- * careful about memory management.
- *
- * Having said all that, here is what a PortalD currently looks like:
+ * Do not confuse "Portal" with "PortalEntry" (or "PortalBuffer").
+ * When a PQexec() routine is run, the resulting tuples
+ * find their way into a "PortalEntry". The contents of the resulting
+ * "PortalEntry" can then be inspected by other PQxxx functions.
+ *
+ * A "Portal" is a structure used to keep track of queries of the
+ * form:
+ * retrieve portal FOO ( blah... ) where blah...
+ *
+ * When the backend sees a "retrieve portal" query, it allocates
+ * a "PortalD" structure, plans the query and then stores the query
+ * in the portal without executing it. Later, when the backend
+ * sees a
+ * fetch 1 into FOO
+ *
+ * the system looks up the portal named "FOO" in the portal table,
+ * gets the planned query and then calls the executor with a feature of
+ * '(EXEC_FOR 1). The executor then runs the query and returns a single
+ * tuple. The problem is that we have to hold onto the state of the
+ * portal query until we see a "close p". This means we have to be
+ * careful about memory management.
+ *
+ * Having said all that, here is what a PortalD currently looks like:
*
* struct PortalD {
- * char* name;
- * classObj(PortalVariableMemory) variable;
- * classObj(PortalHeapMemory) heap;
- * List queryDesc;
- * EState state;
- * void (*cleanup) ARGS((Portal portal));
+ * char* name;
+ * classObj(PortalVariableMemory) variable;
+ * classObj(PortalHeapMemory) heap;
+ * List queryDesc;
+ * EState state;
+ * void (*cleanup) ARGS((Portal portal));
* };
*
- * I hope this makes things clearer to whoever reads this -cim 2/22/91
+ * I hope this makes things clearer to whoever reads this -cim 2/22/91
*
- * Here is an old comment taken from nodes/memnodes.h
+ * Here is an old comment taken from nodes/memnodes.h
*
* MemoryContext --
- * A logical context in which memory allocations occur.
+ * A logical context in which memory allocations occur.
*
* The types of memory contexts can be thought of as members of the
* following inheritance hierarchy with properties summarized below.
*
- * Node
- * |
- * MemoryContext___
- * / \
- * GlobalMemory PortalMemoryContext
- * / \
- * PortalVariableMemory PortalHeapMemory
+ * Node
+ * |
+ * MemoryContext___
+ * / \
+ * GlobalMemory PortalMemoryContext
+ * / \
+ * PortalVariableMemory PortalHeapMemory
*
- * Flushed at Flushed at Checkpoints
- * Transaction Portal
- * Commit Close
+ * Flushed at Flushed at Checkpoints
+ * Transaction Portal
+ * Commit Close
*
- * GlobalMemory n n n
- * PortalVariableMemory n y n
- * PortalHeapMemory y y y *
+ * GlobalMemory n n n
+ * PortalVariableMemory n y n
+ * PortalHeapMemory y y y *
*
*/
-#include <stdio.h> /* for sprintf() */
-#include <string.h> /* for strlen, strncpy */
+#include <stdio.h> /* for sprintf() */
+#include <string.h> /* for strlen, strncpy */
#include "postgres.h"
#include "lib/hasht.h"
#include "utils/module.h"
-#include "utils/excid.h" /* for Unimplemented */
+#include "utils/excid.h" /* for Unimplemented */
#include "utils/mcxt.h"
#include "utils/hsearch.h"
@@ -91,324 +91,330 @@
#include "utils/portal.h"
-static void CollectNamedPortals(Portal *portalP, int destroy);
-static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
+static void CollectNamedPortals(Portal * portalP, int destroy);
+static Portal PortalHeapMemoryGetPortal(PortalHeapMemory context);
static PortalVariableMemory PortalHeapMemoryGetVariableMemory(PortalHeapMemory context);
-static void PortalResetHeapMemory(Portal portal);
-static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
+static void PortalResetHeapMemory(Portal portal);
+static Portal PortalVariableMemoryGetPortal(PortalVariableMemory context);
/* ----------------
- * ALLOCFREE_ERROR_ABORT
- * define this if you want a core dump when you try to
- * free memory already freed -cim 2/9/91
+ * ALLOCFREE_ERROR_ABORT
+ * define this if you want a core dump when you try to
+ * free memory already freed -cim 2/9/91
* ----------------
*/
#undef ALLOCFREE_ERROR_ABORT
/* ----------------
- * Global state
+ * Global state
* ----------------
*/
-static int PortalManagerEnableCount = 0;
-#define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
+static int PortalManagerEnableCount = 0;
-typedef struct portalhashent {
- char portalname[MAX_PORTALNAME_LEN];
- Portal portal;
-} PortalHashEnt;
+#define MAX_PORTALNAME_LEN 64 /* XXX LONGALIGNable value */
+
+typedef struct portalhashent
+{
+ char portalname[MAX_PORTALNAME_LEN];
+ Portal portal;
+} PortalHashEnt;
#define PortalManagerEnabled (PortalManagerEnableCount >= 1)
-static HTAB *PortalHashTable = NULL;
+static HTAB *PortalHashTable = NULL;
+
#define PortalHashTableLookup(NAME, PORTAL) \
- { PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
- memset(key, 0, MAX_PORTALNAME_LEN); \
- sprintf(key, "%s", NAME); \
- hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
- key, HASH_FIND, &found); \
- if (hentry == NULL) \
- elog(FATAL, "error in PortalHashTable"); \
- if (found) \
- PORTAL = hentry->portal; \
- else \
- PORTAL = NULL; \
- }
+ { PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
+ memset(key, 0, MAX_PORTALNAME_LEN); \
+ sprintf(key, "%s", NAME); \
+ hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
+ key, HASH_FIND, &found); \
+ if (hentry == NULL) \
+ elog(FATAL, "error in PortalHashTable"); \
+ if (found) \
+ PORTAL = hentry->portal; \
+ else \
+ PORTAL = NULL; \
+ }
#define PortalHashTableInsert(PORTAL) \
- { PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
- memset(key, 0, MAX_PORTALNAME_LEN); \
- sprintf(key, "%s", PORTAL->name); \
- hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
- key, HASH_ENTER, &found); \
- if (hentry == NULL) \
- elog(FATAL, "error in PortalHashTable"); \
- if (found) \
- elog(NOTICE, "trying to insert a portal name that exists."); \
- hentry->portal = PORTAL; \
- }
+ { PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
+ memset(key, 0, MAX_PORTALNAME_LEN); \
+ sprintf(key, "%s", PORTAL->name); \
+ hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
+ key, HASH_ENTER, &found); \
+ if (hentry == NULL) \
+ elog(FATAL, "error in PortalHashTable"); \
+ if (found) \
+ elog(NOTICE, "trying to insert a portal name that exists."); \
+ hentry->portal = PORTAL; \
+ }
#define PortalHashTableDelete(PORTAL) \
- { PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
- memset(key, 0, MAX_PORTALNAME_LEN); \
- sprintf(key, "%s", PORTAL->name); \
- hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
- key, HASH_REMOVE, &found); \
- if (hentry == NULL) \
- elog(FATAL, "error in PortalHashTable"); \
- if (!found) \
- elog(NOTICE, "trying to delete portal name that does not exist."); \
- }
-
-static GlobalMemory PortalMemory = NULL;
+ { PortalHashEnt *hentry; bool found; char key[MAX_PORTALNAME_LEN]; \
+ memset(key, 0, MAX_PORTALNAME_LEN); \
+ sprintf(key, "%s", PORTAL->name); \
+ hentry = (PortalHashEnt*)hash_search(PortalHashTable, \
+ key, HASH_REMOVE, &found); \
+ if (hentry == NULL) \
+ elog(FATAL, "error in PortalHashTable"); \
+ if (!found) \
+ elog(NOTICE, "trying to delete portal name that does not exist."); \
+ }
+
+static GlobalMemory PortalMemory = NULL;
static char PortalMemoryName[] = "Portal";
-static Portal BlankPortal = NULL;
+static Portal BlankPortal = NULL;
/* ----------------
- * Internal class definitions
+ * Internal class definitions
* ----------------
*/
-typedef struct HeapMemoryBlockData {
- AllocSetData setData;
- FixedItemData itemData;
-} HeapMemoryBlockData;
+typedef struct HeapMemoryBlockData
+{
+ AllocSetData setData;
+ FixedItemData itemData;
+} HeapMemoryBlockData;
-typedef HeapMemoryBlockData *HeapMemoryBlock;
+typedef HeapMemoryBlockData *HeapMemoryBlock;
#define HEAPMEMBLOCK(context) \
- ((HeapMemoryBlock)(context)->block)
+ ((HeapMemoryBlock)(context)->block)
/* ----------------------------------------------------------------
- * Variable and heap memory methods
+ * Variable and heap memory methods
* ----------------------------------------------------------------
*/
/* ----------------
- * PortalVariableMemoryAlloc
+ * PortalVariableMemoryAlloc
* ----------------
*/
-static Pointer
+static Pointer
PortalVariableMemoryAlloc(PortalVariableMemory this,
- Size size)
+ Size size)
{
- return (AllocSetAlloc(&this->setData, size));
+ return (AllocSetAlloc(&this->setData, size));
}
/* ----------------
- * PortalVariableMemoryFree
+ * PortalVariableMemoryFree
* ----------------
*/
static void
PortalVariableMemoryFree(PortalVariableMemory this,
- Pointer pointer)
+ Pointer pointer)
{
- AllocSetFree(&this->setData, pointer);
+ AllocSetFree(&this->setData, pointer);
}
/* ----------------
- * PortalVariableMemoryRealloc
+ * PortalVariableMemoryRealloc
* ----------------
*/
-static Pointer
+static Pointer
PortalVariableMemoryRealloc(PortalVariableMemory this,
- Pointer pointer,
- Size size)
+ Pointer pointer,
+ Size size)
{
- return (AllocSetRealloc(&this->setData, pointer, size));
+ return (AllocSetRealloc(&this->setData, pointer, size));
}
/* ----------------
- * PortalVariableMemoryGetName
+ * PortalVariableMemoryGetName
* ----------------
*/
-static char*
+static char *
PortalVariableMemoryGetName(PortalVariableMemory this)
{
- return (form("%s-var", PortalVariableMemoryGetPortal(this)->name));
+ return (form("%s-var", PortalVariableMemoryGetPortal(this)->name));
}
/* ----------------
- * PortalVariableMemoryDump
+ * PortalVariableMemoryDump
* ----------------
*/
static void
PortalVariableMemoryDump(PortalVariableMemory this)
{
- printf("--\n%s:\n", PortalVariableMemoryGetName(this));
-
- AllocSetDump(&this->setData); /* XXX is this the right interface */
+ printf("--\n%s:\n", PortalVariableMemoryGetName(this));
+
+ AllocSetDump(&this->setData); /* XXX is this the right interface */
}
/* ----------------
- * PortalHeapMemoryAlloc
+ * PortalHeapMemoryAlloc
* ----------------
*/
-static Pointer
+static Pointer
PortalHeapMemoryAlloc(PortalHeapMemory this,
- Size size)
+ Size size)
{
- HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
- AssertState(PointerIsValid(block));
-
- return (AllocSetAlloc(&block->setData, size));
+ HeapMemoryBlock block = HEAPMEMBLOCK(this);
+
+ AssertState(PointerIsValid(block));
+
+ return (AllocSetAlloc(&block->setData, size));
}
/* ----------------
- * PortalHeapMemoryFree
+ * PortalHeapMemoryFree
* ----------------
*/
static void
PortalHeapMemoryFree(PortalHeapMemory this,
- Pointer pointer)
-{
- HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
- AssertState(PointerIsValid(block));
-
- if (AllocSetContains(&block->setData, pointer))
- AllocSetFree(&block->setData, pointer);
- else {
- elog(NOTICE,
- "PortalHeapMemoryFree: 0x%x not in alloc set!",
- pointer);
+ Pointer pointer)
+{
+ HeapMemoryBlock block = HEAPMEMBLOCK(this);
+
+ AssertState(PointerIsValid(block));
+
+ if (AllocSetContains(&block->setData, pointer))
+ AllocSetFree(&block->setData, pointer);
+ else
+ {
+ elog(NOTICE,
+ "PortalHeapMemoryFree: 0x%x not in alloc set!",
+ pointer);
#ifdef ALLOCFREE_ERROR_ABORT
- Assert(AllocSetContains(&block->setData, pointer));
-#endif /* ALLOCFREE_ERROR_ABORT*/
- }
+ Assert(AllocSetContains(&block->setData, pointer));
+#endif /* ALLOCFREE_ERROR_ABORT */
+ }
}
/* ----------------
- * PortalHeapMemoryRealloc
+ * PortalHeapMemoryRealloc
* ----------------
*/
-static Pointer
+static Pointer
PortalHeapMemoryRealloc(PortalHeapMemory this,
- Pointer pointer,
- Size size)
+ Pointer pointer,
+ Size size)
{
- HeapMemoryBlock block = HEAPMEMBLOCK(this);
-
- AssertState(PointerIsValid(block));
-
- return (AllocSetRealloc(&block->setData, pointer, size));
+ HeapMemoryBlock block = HEAPMEMBLOCK(this);
+
+ AssertState(PointerIsValid(block));
+
+ return (AllocSetRealloc(&block->setData, pointer, size));
}
/* ----------------
- * PortalHeapMemoryGetName
+ * PortalHeapMemoryGetName
* ----------------
*/
-static char*
+static char *
PortalHeapMemoryGetName(PortalHeapMemory this)
{
- return (form("%s-heap", PortalHeapMemoryGetPortal(this)->name));
+ return (form("%s-heap", PortalHeapMemoryGetPortal(this)->name));
}
/* ----------------
- * PortalHeapMemoryDump
+ * PortalHeapMemoryDump
* ----------------
*/
static void
PortalHeapMemoryDump(PortalHeapMemory this)
{
- HeapMemoryBlock block;
-
- printf("--\n%s:\n", PortalHeapMemoryGetName(this));
-
- /* XXX is this the right interface */
- if (PointerIsValid(this->block))
- AllocSetDump(&HEAPMEMBLOCK(this)->setData);
-
- /* dump the stack too */
- for (block = (HeapMemoryBlock)FixedStackGetTop(&this->stackData);
- PointerIsValid(block);
- block = (HeapMemoryBlock)
- FixedStackGetNext(&this->stackData, (Pointer)block)) {
-
- printf("--\n");
- AllocSetDump(&block->setData);
- }
+ HeapMemoryBlock block;
+
+ printf("--\n%s:\n", PortalHeapMemoryGetName(this));
+
+ /* XXX is this the right interface */
+ if (PointerIsValid(this->block))
+ AllocSetDump(&HEAPMEMBLOCK(this)->setData);
+
+ /* dump the stack too */
+ for (block = (HeapMemoryBlock) FixedStackGetTop(&this->stackData);
+ PointerIsValid(block);
+ block = (HeapMemoryBlock)
+ FixedStackGetNext(&this->stackData, (Pointer) block))
+ {
+
+ printf("--\n");
+ AllocSetDump(&block->setData);
+ }
}
/* ----------------------------------------------------------------
- * variable / heap context method tables
+ * variable / heap context method tables
* ----------------------------------------------------------------
*/
-static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
- PortalVariableMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
- PortalVariableMemoryFree, /* void (*)(this, Pointer) pfree */
- PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer) repalloc */
- PortalVariableMemoryGetName,/* char* (*)(this) getName */
- PortalVariableMemoryDump /* void (*)(this) dump */
+static struct MemoryContextMethodsData PortalVariableContextMethodsData = {
+ PortalVariableMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
+ PortalVariableMemoryFree, /* void (*)(this, Pointer) pfree */
+ PortalVariableMemoryRealloc,/* Pointer (*)(this, Pointer) repalloc */
+ PortalVariableMemoryGetName,/* char* (*)(this) getName */
+ PortalVariableMemoryDump /* void (*)(this) dump */
};
-static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
- PortalHeapMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
- PortalHeapMemoryFree, /* void (*)(this, Pointer) pfree */
- PortalHeapMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
- PortalHeapMemoryGetName, /* char* (*)(this) getName */
- PortalHeapMemoryDump /* void (*)(this) dump */
+static struct MemoryContextMethodsData PortalHeapContextMethodsData = {
+ PortalHeapMemoryAlloc, /* Pointer (*)(this, uint32) palloc */
+ PortalHeapMemoryFree, /* void (*)(this, Pointer) pfree */
+ PortalHeapMemoryRealloc, /* Pointer (*)(this, Pointer) repalloc */
+ PortalHeapMemoryGetName, /* char* (*)(this) getName */
+ PortalHeapMemoryDump /* void (*)(this) dump */
};
/* ----------------------------------------------------------------
- * private internal support routines
+ * private internal support routines
* ----------------------------------------------------------------
*/
/* ----------------
- * CreateNewBlankPortal
+ * CreateNewBlankPortal
* ----------------
*/
static void
CreateNewBlankPortal()
{
- Portal portal;
-
- AssertState(!PortalIsValid(BlankPortal));
-
- /*
- * make new portal structure
- */
- portal = (Portal)
- MemoryContextAlloc((MemoryContext)PortalMemory, sizeof *portal);
-
- /*
- * initialize portal variable context
- */
- NodeSetTag((Node*)&portal->variable, T_PortalVariableMemory);
- AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size)0);
- portal->variable.method = &PortalVariableContextMethodsData;
-
- /*
- * initialize portal heap context
- */
- NodeSetTag((Node*)&portal->heap, T_PortalHeapMemory);
- portal->heap.block = NULL;
- FixedStackInit(&portal->heap.stackData,
- offsetof (HeapMemoryBlockData, itemData));
- portal->heap.method = &PortalHeapContextMethodsData;
-
- /*
- * set bogus portal name
- */
- portal->name = "** Blank Portal **";
-
- /* initialize portal query */
- portal->queryDesc = NULL;
- portal->attinfo = NULL;
- portal->state = NULL;
- portal->cleanup = NULL;
-
- /*
- * install blank portal
- */
- BlankPortal = portal;
+ Portal portal;
+
+ AssertState(!PortalIsValid(BlankPortal));
+
+ /*
+ * make new portal structure
+ */
+ portal = (Portal)
+ MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
+
+ /*
+ * initialize portal variable context
+ */
+ NodeSetTag((Node *) & portal->variable, T_PortalVariableMemory);
+ AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
+ portal->variable.method = &PortalVariableContextMethodsData;
+
+ /*
+ * initialize portal heap context
+ */
+ NodeSetTag((Node *) & portal->heap, T_PortalHeapMemory);
+ portal->heap.block = NULL;
+ FixedStackInit(&portal->heap.stackData,
+ offsetof(HeapMemoryBlockData, itemData));
+ portal->heap.method = &PortalHeapContextMethodsData;
+
+ /*
+ * set bogus portal name
+ */
+ portal->name = "** Blank Portal **";
+
+ /* initialize portal query */
+ portal->queryDesc = NULL;
+ portal->attinfo = NULL;
+ portal->state = NULL;
+ portal->cleanup = NULL;
+
+ /*
+ * install blank portal
+ */
+ BlankPortal = portal;
}
bool
PortalNameIsSpecial(char *pname)
{
- if (strcmp(pname, VACPNAME) == 0)
- return true;
- return false;
+ if (strcmp(pname, VACPNAME) == 0)
+ return true;
+ return false;
}
/*
@@ -420,572 +426,586 @@ PortalNameIsSpecial(char *pname)
* and screws up the sequential walk of the table). -mer 17 Aug 1992
*/
static void
-CollectNamedPortals(Portal *portalP, int destroy)
-{
- static Portal *portalList = (Portal *)NULL;
- static int listIndex = 0;
- static int maxIndex = 9;
-
- if (portalList == (Portal *)NULL)
- portalList = (Portal *)malloc(10*sizeof(Portal));
-
- if (destroy != 0)
+CollectNamedPortals(Portal * portalP, int destroy)
+{
+ static Portal *portalList = (Portal *) NULL;
+ static int listIndex = 0;
+ static int maxIndex = 9;
+
+ if (portalList == (Portal *) NULL)
+ portalList = (Portal *) malloc(10 * sizeof(Portal));
+
+ if (destroy != 0)
{
- int i;
-
- for (i = 0; i < listIndex; i++)
- PortalDestroy(&portalList[i]);
- listIndex = 0;
+ int i;
+
+ for (i = 0; i < listIndex; i++)
+ PortalDestroy(&portalList[i]);
+ listIndex = 0;
}
- else
+ else
{
- Assert(portalP);
- Assert(*portalP);
-
- /*
- * Don't delete special portals, up to portal creator to do this
- */
- if (PortalNameIsSpecial((*portalP)->name))
- return;
-
- portalList[listIndex] = *portalP;
- listIndex++;
- if (listIndex == maxIndex)
+ Assert(portalP);
+ Assert(*portalP);
+
+ /*
+ * Don't delete special portals, up to portal creator to do this
+ */
+ if (PortalNameIsSpecial((*portalP)->name))
+ return;
+
+ portalList[listIndex] = *portalP;
+ listIndex++;
+ if (listIndex == maxIndex)
{
- portalList = (Portal *)
- realloc(portalList, (maxIndex+11)*sizeof(Portal));
- maxIndex += 10;
+ portalList = (Portal *)
+ realloc(portalList, (maxIndex + 11) * sizeof(Portal));
+ maxIndex += 10;
}
}
- return;
+ return;
}
void
AtEOXact_portals()
{
- HashTableWalk(PortalHashTable, CollectNamedPortals, 0);
- CollectNamedPortals(NULL, 1);
+ HashTableWalk(PortalHashTable, CollectNamedPortals, 0);
+ CollectNamedPortals(NULL, 1);
}
/* ----------------
- * PortalDump
+ * PortalDump
* ----------------
*/
#ifdef NOT_USED
static void
-PortalDump(Portal *thisP)
+PortalDump(Portal * thisP)
{
- /* XXX state/argument checking here */
-
- PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
- PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
+ /* XXX state/argument checking here */
+
+ PortalVariableMemoryDump(PortalGetVariableMemory(*thisP));
+ PortalHeapMemoryDump(PortalGetHeapMemory(*thisP));
}
+
#endif
/* ----------------
- * DumpPortals
+ * DumpPortals
* ----------------
*/
#ifdef NOT_USED
static void
DumpPortals()
{
- /* XXX state checking here */
-
- HashTableWalk(PortalHashTable, PortalDump, 0);
+ /* XXX state checking here */
+
+ HashTableWalk(PortalHashTable, PortalDump, 0);
}
+
#endif
-
+
/* ----------------------------------------------------------------
- * public portal interface functions
+ * public portal interface functions
* ----------------------------------------------------------------
*/
/*
* EnablePortalManager --
- * Enables/disables the portal management module.
+ * Enables/disables the portal management module.
*/
void
EnablePortalManager(bool on)
{
- static bool processing = false;
- HASHCTL ctl;
-
- AssertState(!processing);
- AssertArg(BoolIsValid(on));
-
- if (BypassEnable(&PortalManagerEnableCount, on))
- return;
-
- processing = true;
-
- if (on) { /* initialize */
- EnableMemoryContext(true);
-
- PortalMemory = CreateGlobalMemory(PortalMemoryName);
-
- ctl.keysize = MAX_PORTALNAME_LEN;
- ctl.datasize = sizeof(Portal);
-
- /* use PORTALS_PER_USER, defined in utils/portal.h
- * as a guess of how many hash table entries to create, initially
- */
- PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
-
- CreateNewBlankPortal();
-
- } else { /* cleanup */
- if (PortalIsValid(BlankPortal)) {
- PortalDestroy(&BlankPortal);
- MemoryContextFree((MemoryContext)PortalMemory,
- (Pointer)BlankPortal);
- BlankPortal = NULL;
+ static bool processing = false;
+ HASHCTL ctl;
+
+ AssertState(!processing);
+ AssertArg(BoolIsValid(on));
+
+ if (BypassEnable(&PortalManagerEnableCount, on))
+ return;
+
+ processing = true;
+
+ if (on)
+ { /* initialize */
+ EnableMemoryContext(true);
+
+ PortalMemory = CreateGlobalMemory(PortalMemoryName);
+
+ ctl.keysize = MAX_PORTALNAME_LEN;
+ ctl.datasize = sizeof(Portal);
+
+ /*
+ * use PORTALS_PER_USER, defined in utils/portal.h as a guess of
+ * how many hash table entries to create, initially
+ */
+ PortalHashTable = hash_create(PORTALS_PER_USER * 3, &ctl, HASH_ELEM);
+
+ CreateNewBlankPortal();
+
}
- /*
- * Each portal must free its non-memory resources specially.
- */
- HashTableWalk(PortalHashTable, PortalDestroy, 0);
- hash_destroy(PortalHashTable);
- PortalHashTable = NULL;
-
- GlobalMemoryDestroy(PortalMemory);
- PortalMemory = NULL;
-
- EnableMemoryContext(true);
- }
-
- processing = false;
+ else
+ { /* cleanup */
+ if (PortalIsValid(BlankPortal))
+ {
+ PortalDestroy(&BlankPortal);
+ MemoryContextFree((MemoryContext) PortalMemory,
+ (Pointer) BlankPortal);
+ BlankPortal = NULL;
+ }
+
+ /*
+ * Each portal must free its non-memory resources specially.
+ */
+ HashTableWalk(PortalHashTable, PortalDestroy, 0);
+ hash_destroy(PortalHashTable);
+ PortalHashTable = NULL;
+
+ GlobalMemoryDestroy(PortalMemory);
+ PortalMemory = NULL;
+
+ EnableMemoryContext(true);
+ }
+
+ processing = false;
}
/*
* GetPortalByName --
- * Returns a portal given a portal name; returns blank portal given
+ * Returns a portal given a portal name; returns blank portal given
* NULL; returns invalid portal if portal not found.
*
* Exceptions:
- * BadState if called when disabled.
+ * BadState if called when disabled.
*/
Portal
GetPortalByName(char *name)
{
- Portal portal;
-
- AssertState(PortalManagerEnabled);
-
- if (PointerIsValid(name)) {
- PortalHashTableLookup(name, portal);
- }
- else {
- if (!PortalIsValid(BlankPortal))
- CreateNewBlankPortal();
- portal = BlankPortal;
- }
-
- return (portal);
+ Portal portal;
+
+ AssertState(PortalManagerEnabled);
+
+ if (PointerIsValid(name))
+ {
+ PortalHashTableLookup(name, portal);
+ }
+ else
+ {
+ if (!PortalIsValid(BlankPortal))
+ CreateNewBlankPortal();
+ portal = BlankPortal;
+ }
+
+ return (portal);
}
/*
* BlankPortalAssignName --
- * Returns former blank portal as portal with given name.
+ * Returns former blank portal as portal with given name.
*
* Side effect:
- * All references to the former blank portal become incorrect.
+ * All references to the former blank portal become incorrect.
*
* Exceptions:
- * BadState if called when disabled.
- * BadState if called without an intervening call to GetPortalByName(NULL).
- * BadArg if portal name is invalid.
- * "WARN" if portal name is in use.
+ * BadState if called when disabled.
+ * BadState if called without an intervening call to GetPortalByName(NULL).
+ * BadArg if portal name is invalid.
+ * "WARN" if portal name is in use.
*/
Portal
-BlankPortalAssignName(char *name) /* XXX PortalName */
-{
- Portal portal;
- uint16 length;
-
- AssertState(PortalManagerEnabled);
- AssertState(PortalIsValid(BlankPortal));
- AssertArg(PointerIsValid(name)); /* XXX PortalName */
-
- portal = GetPortalByName(name);
- if (PortalIsValid(portal)) {
- elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
+BlankPortalAssignName(char *name) /* XXX PortalName */
+{
+ Portal portal;
+ uint16 length;
+
+ AssertState(PortalManagerEnabled);
+ AssertState(PortalIsValid(BlankPortal));
+ AssertArg(PointerIsValid(name)); /* XXX PortalName */
+
+ portal = GetPortalByName(name);
+ if (PortalIsValid(portal))
+ {
+ elog(NOTICE, "BlankPortalAssignName: portal %s already exists", name);
+ return (portal);
+ }
+
+ /*
+ * remove blank portal
+ */
+ portal = BlankPortal;
+ BlankPortal = NULL;
+
+ /*
+ * initialize portal name
+ */
+ length = 1 + strlen(name);
+ portal->name = (char *)
+ MemoryContextAlloc((MemoryContext) & portal->variable, length);
+
+ strncpy(portal->name, name, length);
+
+ /*
+ * put portal in table
+ */
+ PortalHashTableInsert(portal);
+
return (portal);
- }
-
- /*
- * remove blank portal
- */
- portal = BlankPortal;
- BlankPortal = NULL;
-
- /*
- * initialize portal name
- */
- length = 1 + strlen(name);
- portal->name = (char*)
- MemoryContextAlloc((MemoryContext)&portal->variable, length);
-
- strncpy(portal->name, name, length);
-
- /*
- * put portal in table
- */
- PortalHashTableInsert(portal);
-
- return (portal);
}
/*
* PortalSetQuery --
- * Attaches a "query" to portal.
+ * Attaches a "query" to portal.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
- * BadArg if queryDesc is "invalid."
- * BadArg if state is "invalid."
+ * BadState if called when disabled.
+ * BadArg if portal is invalid.
+ * BadArg if queryDesc is "invalid."
+ * BadArg if state is "invalid."
*/
void
PortalSetQuery(Portal portal,
- QueryDesc *queryDesc,
- TupleDesc attinfo,
- EState *state,
- void (*cleanup)(Portal portal))
+ QueryDesc * queryDesc,
+ TupleDesc attinfo,
+ EState * state,
+ void (*cleanup) (Portal portal))
{
- AssertState(PortalManagerEnabled);
- AssertArg(PortalIsValid(portal));
- AssertArg(IsA((Node*)state,EState));
-
- portal->queryDesc = queryDesc;
- portal->state = state;
- portal->attinfo = attinfo;
- portal->cleanup = cleanup;
+ AssertState(PortalManagerEnabled);
+ AssertArg(PortalIsValid(portal));
+ AssertArg(IsA((Node *) state, EState));
+
+ portal->queryDesc = queryDesc;
+ portal->state = state;
+ portal->attinfo = attinfo;
+ portal->cleanup = cleanup;
}
/*
* PortalGetQueryDesc --
- * Returns query attached to portal.
+ * Returns query attached to portal.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
+ * BadState if called when disabled.
+ * BadArg if portal is invalid.
*/
-QueryDesc *
+QueryDesc *
PortalGetQueryDesc(Portal portal)
{
- AssertState(PortalManagerEnabled);
- AssertArg(PortalIsValid(portal));
-
- return (portal->queryDesc);
+ AssertState(PortalManagerEnabled);
+ AssertArg(PortalIsValid(portal));
+
+ return (portal->queryDesc);
}
/*
* PortalGetState --
- * Returns state attached to portal.
+ * Returns state attached to portal.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
+ * BadState if called when disabled.
+ * BadArg if portal is invalid.
*/
-EState *
+EState *
PortalGetState(Portal portal)
{
- AssertState(PortalManagerEnabled);
- AssertArg(PortalIsValid(portal));
-
- return (portal->state);
+ AssertState(PortalManagerEnabled);
+ AssertArg(PortalIsValid(portal));
+
+ return (portal->state);
}
/*
* CreatePortal --
- * Returns a new portal given a name.
+ * Returns a new portal given a name.
*
* Note:
- * This is expected to be of very limited usability. See instead,
+ * This is expected to be of very limited usability. See instead,
* BlankPortalAssignName.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if portal name is invalid.
- * "WARN" if portal name is in use.
+ * BadState if called when disabled.
+ * BadArg if portal name is invalid.
+ * "WARN" if portal name is in use.
*/
Portal
-CreatePortal(char *name) /* XXX PortalName */
-{
- Portal portal;
- uint16 length;
-
- AssertState(PortalManagerEnabled);
- AssertArg(PointerIsValid(name)); /* XXX PortalName */
-
- portal = GetPortalByName(name);
- if (PortalIsValid(portal)) {
- elog(NOTICE, "CreatePortal: portal %s already exists", name);
+CreatePortal(char *name) /* XXX PortalName */
+{
+ Portal portal;
+ uint16 length;
+
+ AssertState(PortalManagerEnabled);
+ AssertArg(PointerIsValid(name)); /* XXX PortalName */
+
+ portal = GetPortalByName(name);
+ if (PortalIsValid(portal))
+ {
+ elog(NOTICE, "CreatePortal: portal %s already exists", name);
+ return (portal);
+ }
+
+ /* make new portal structure */
+ portal = (Portal)
+ MemoryContextAlloc((MemoryContext) PortalMemory, sizeof *portal);
+
+ /* initialize portal variable context */
+ NodeSetTag((Node *) & portal->variable, T_PortalVariableMemory);
+ AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size) 0);
+ portal->variable.method = &PortalVariableContextMethodsData;
+
+ /* initialize portal heap context */
+ NodeSetTag((Node *) & portal->heap, T_PortalHeapMemory);
+ portal->heap.block = NULL;
+ FixedStackInit(&portal->heap.stackData,
+ offsetof(HeapMemoryBlockData, itemData));
+ portal->heap.method = &PortalHeapContextMethodsData;
+
+ /* initialize portal name */
+ length = 1 + strlen(name);
+ portal->name = (char *)
+ MemoryContextAlloc((MemoryContext) & portal->variable, length);
+ strncpy(portal->name, name, length);
+
+ /* initialize portal query */
+ portal->queryDesc = NULL;
+ portal->attinfo = NULL;
+ portal->state = NULL;
+ portal->cleanup = NULL;
+
+ /* put portal in table */
+ PortalHashTableInsert(portal);
+
+ /* Trap(PointerIsValid(name), Unimplemented); */
return (portal);
- }
-
- /* make new portal structure */
- portal = (Portal)
- MemoryContextAlloc((MemoryContext)PortalMemory, sizeof *portal);
-
- /* initialize portal variable context */
- NodeSetTag((Node*)&portal->variable, T_PortalVariableMemory);
- AllocSetInit(&portal->variable.setData, DynamicAllocMode, (Size)0);
- portal->variable.method = &PortalVariableContextMethodsData;
-
- /* initialize portal heap context */
- NodeSetTag((Node*)&portal->heap, T_PortalHeapMemory);
- portal->heap.block = NULL;
- FixedStackInit(&portal->heap.stackData,
- offsetof (HeapMemoryBlockData, itemData));
- portal->heap.method = &PortalHeapContextMethodsData;
-
- /* initialize portal name */
- length = 1 + strlen(name);
- portal->name = (char*)
- MemoryContextAlloc((MemoryContext)&portal->variable, length);
- strncpy(portal->name, name, length);
-
- /* initialize portal query */
- portal->queryDesc = NULL;
- portal->attinfo = NULL;
- portal->state = NULL;
- portal->cleanup = NULL;
-
- /* put portal in table */
- PortalHashTableInsert(portal);
-
- /* Trap(PointerIsValid(name), Unimplemented); */
- return (portal);
}
/*
* PortalDestroy --
- * Destroys portal.
+ * Destroys portal.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
+ * BadState if called when disabled.
+ * BadArg if portal is invalid.
*/
void
-PortalDestroy(Portal *portalP)
-{
- Portal portal = *portalP;
-
- AssertState(PortalManagerEnabled);
- AssertArg(PortalIsValid(portal));
-
- /* remove portal from table if not blank portal */
- if (portal != BlankPortal)
- PortalHashTableDelete(portal);
-
- /* reset portal */
- if (PointerIsValid(portal->cleanup))
- (*portal->cleanup)(portal);
-
- PortalResetHeapMemory(portal);
- MemoryContextFree((MemoryContext)&portal->variable,
- (Pointer)portal->name);
- AllocSetReset(&portal->variable.setData); /* XXX log */
-
- if (portal != BlankPortal)
- MemoryContextFree((MemoryContext)PortalMemory, (Pointer)portal);
+PortalDestroy(Portal * portalP)
+{
+ Portal portal = *portalP;
+
+ AssertState(PortalManagerEnabled);
+ AssertArg(PortalIsValid(portal));
+
+ /* remove portal from table if not blank portal */
+ if (portal != BlankPortal)
+ PortalHashTableDelete(portal);
+
+ /* reset portal */
+ if (PointerIsValid(portal->cleanup))
+ (*portal->cleanup) (portal);
+
+ PortalResetHeapMemory(portal);
+ MemoryContextFree((MemoryContext) & portal->variable,
+ (Pointer) portal->name);
+ AllocSetReset(&portal->variable.setData); /* XXX log */
+
+ if (portal != BlankPortal)
+ MemoryContextFree((MemoryContext) PortalMemory, (Pointer) portal);
}
/* ----------------
- * PortalResetHeapMemory --
- * Resets portal's heap memory context.
+ * PortalResetHeapMemory --
+ * Resets portal's heap memory context.
*
* Someday, Reset, Start, and End can be optimized by keeping a global
* portal module stack of free HeapMemoryBlock's. This will make Start
* and End be fast.
*
* Exceptions:
- * BadState if called when disabled.
- * BadState if called when not in PortalHeapMemory context.
- * BadArg if mode is invalid.
+ * BadState if called when disabled.
+ * BadState if called when not in PortalHeapMemory context.
+ * BadArg if mode is invalid.
* ----------------
*/
static void
PortalResetHeapMemory(Portal portal)
{
- PortalHeapMemory context;
- MemoryContext currentContext;
-
- context = PortalGetHeapMemory(portal);
-
- if (PointerIsValid(context->block)) {
- /* save present context */
- currentContext = MemoryContextSwitchTo((MemoryContext)context);
-
- do {
- EndPortalAllocMode();
- } while (PointerIsValid(context->block));
-
- /* restore context */
- MemoryContextSwitchTo(currentContext);
- }
+ PortalHeapMemory context;
+ MemoryContext currentContext;
+
+ context = PortalGetHeapMemory(portal);
+
+ if (PointerIsValid(context->block))
+ {
+ /* save present context */
+ currentContext = MemoryContextSwitchTo((MemoryContext) context);
+
+ do
+ {
+ EndPortalAllocMode();
+ } while (PointerIsValid(context->block));
+
+ /* restore context */
+ MemoryContextSwitchTo(currentContext);
+ }
}
/*
* StartPortalAllocMode --
- * Starts a new block of portal heap allocation using mode and limit;
- * the current block is disabled until EndPortalAllocMode is called.
+ * Starts a new block of portal heap allocation using mode and limit;
+ * the current block is disabled until EndPortalAllocMode is called.
*
* Note:
- * Note blocks may be stacked and restored arbitarily.
- * The semantics of mode and limit are described in aset.h.
+ * Note blocks may be stacked and restored arbitarily.
+ * The semantics of mode and limit are described in aset.h.
*
* Exceptions:
- * BadState if called when disabled.
- * BadState if called when not in PortalHeapMemory context.
- * BadArg if mode is invalid.
+ * BadState if called when disabled.
+ * BadState if called when not in PortalHeapMemory context.
+ * BadArg if mode is invalid.
*/
void
StartPortalAllocMode(AllocMode mode, Size limit)
{
- PortalHeapMemory context;
-
- AssertState(PortalManagerEnabled);
- AssertState(IsA(CurrentMemoryContext,PortalHeapMemory));
- /* AssertArg(AllocModeIsValid); */
-
- context = (PortalHeapMemory)CurrentMemoryContext;
-
- /* stack current mode */
- if (PointerIsValid(context->block))
- FixedStackPush(&context->stackData, context->block);
-
- /* allocate and initialize new block */
- context->block =
- MemoryContextAlloc(
- (MemoryContext)PortalHeapMemoryGetVariableMemory(context),
- sizeof (HeapMemoryBlockData) );
-
- /* XXX careful, context->block has never been stacked => bad state */
-
- AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
+ PortalHeapMemory context;
+
+ AssertState(PortalManagerEnabled);
+ AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
+ /* AssertArg(AllocModeIsValid); */
+
+ context = (PortalHeapMemory) CurrentMemoryContext;
+
+ /* stack current mode */
+ if (PointerIsValid(context->block))
+ FixedStackPush(&context->stackData, context->block);
+
+ /* allocate and initialize new block */
+ context->block =
+ MemoryContextAlloc(
+ (MemoryContext) PortalHeapMemoryGetVariableMemory(context),
+ sizeof(HeapMemoryBlockData));
+
+ /* XXX careful, context->block has never been stacked => bad state */
+
+ AllocSetInit(&HEAPMEMBLOCK(context)->setData, mode, limit);
}
/*
* EndPortalAllocMode --
- * Ends current block of portal heap allocation; previous block is
- * reenabled.
+ * Ends current block of portal heap allocation; previous block is
+ * reenabled.
*
* Note:
- * Note blocks may be stacked and restored arbitarily.
+ * Note blocks may be stacked and restored arbitarily.
*
* Exceptions:
- * BadState if called when disabled.
- * BadState if called when not in PortalHeapMemory context.
+ * BadState if called when disabled.
+ * BadState if called when not in PortalHeapMemory context.
*/
void
EndPortalAllocMode()
{
- PortalHeapMemory context;
-
- AssertState(PortalManagerEnabled);
- AssertState(IsA(CurrentMemoryContext,PortalHeapMemory));
-
- context = (PortalHeapMemory)CurrentMemoryContext;
- AssertState(PointerIsValid(context->block)); /* XXX Trap(...) */
-
- /* free current mode */
- AllocSetReset(&HEAPMEMBLOCK(context)->setData);
- MemoryContextFree((MemoryContext)PortalHeapMemoryGetVariableMemory(context),
- context->block);
-
- /* restore previous mode */
- context->block = FixedStackPop(&context->stackData);
+ PortalHeapMemory context;
+
+ AssertState(PortalManagerEnabled);
+ AssertState(IsA(CurrentMemoryContext, PortalHeapMemory));
+
+ context = (PortalHeapMemory) CurrentMemoryContext;
+ AssertState(PointerIsValid(context->block)); /* XXX Trap(...) */
+
+ /* free current mode */
+ AllocSetReset(&HEAPMEMBLOCK(context)->setData);
+ MemoryContextFree((MemoryContext) PortalHeapMemoryGetVariableMemory(context),
+ context->block);
+
+ /* restore previous mode */
+ context->block = FixedStackPop(&context->stackData);
}
/*
* PortalGetVariableMemory --
- * Returns variable memory context for a given portal.
+ * Returns variable memory context for a given portal.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
+ * BadState if called when disabled.
+ * BadArg if portal is invalid.
*/
PortalVariableMemory
PortalGetVariableMemory(Portal portal)
{
- return (&portal->variable);
+ return (&portal->variable);
}
/*
* PortalGetHeapMemory --
- * Returns heap memory context for a given portal.
+ * Returns heap memory context for a given portal.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if portal is invalid.
+ * BadState if called when disabled.
+ * BadArg if portal is invalid.
*/
PortalHeapMemory
PortalGetHeapMemory(Portal portal)
{
- return (&portal->heap);
+ return (&portal->heap);
}
/*
* PortalVariableMemoryGetPortal --
- * Returns portal containing given variable memory context.
+ * Returns portal containing given variable memory context.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
+ * BadState if called when disabled.
+ * BadArg if context is invalid.
*/
-static Portal
+static Portal
PortalVariableMemoryGetPortal(PortalVariableMemory context)
{
- return ((Portal)((char *)context - offsetof (PortalD, variable)));
+ return ((Portal) ((char *) context - offsetof(PortalD, variable)));
}
/*
* PortalHeapMemoryGetPortal --
- * Returns portal containing given heap memory context.
+ * Returns portal containing given heap memory context.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
+ * BadState if called when disabled.
+ * BadArg if context is invalid.
*/
-static Portal
+static Portal
PortalHeapMemoryGetPortal(PortalHeapMemory context)
{
- return ((Portal)((char *)context - offsetof (PortalD, heap)));
+ return ((Portal) ((char *) context - offsetof(PortalD, heap)));
}
/*
* PortalVariableMemoryGetHeapMemory --
- * Returns heap memory context associated with given variable memory.
+ * Returns heap memory context associated with given variable memory.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
+ * BadState if called when disabled.
+ * BadArg if context is invalid.
*/
#ifdef NOT_USED
PortalHeapMemory
PortalVariableMemoryGetHeapMemory(PortalVariableMemory context)
{
- return ((PortalHeapMemory)((char *)context
- - offsetof (PortalD, variable)
- + offsetof (PortalD, heap)));
+ return ((PortalHeapMemory) ((char *) context
+ - offsetof(PortalD, variable)
+ + offsetof(PortalD, heap)));
}
+
#endif
/*
* PortalHeapMemoryGetVariableMemory --
- * Returns variable memory context associated with given heap memory.
+ * Returns variable memory context associated with given heap memory.
*
* Exceptions:
- * BadState if called when disabled.
- * BadArg if context is invalid.
+ * BadState if called when disabled.
+ * BadArg if context is invalid.
*/
-static PortalVariableMemory
+static PortalVariableMemory
PortalHeapMemoryGetVariableMemory(PortalHeapMemory context)
{
- return ((PortalVariableMemory)((char *)context
- - offsetof (PortalD, heap)
- + offsetof (PortalD, variable)));
+ return ((PortalVariableMemory) ((char *) context
+ - offsetof(PortalD, heap)
+ + offsetof(PortalD, variable)));
}
-
diff --git a/src/backend/utils/sort/lselect.c b/src/backend/utils/sort/lselect.c
index 6797bd40ca0..bc6948292b3 100644
--- a/src/backend/utils/sort/lselect.c
+++ b/src/backend/utils/sort/lselect.c
@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* lselect.c--
- * leftist tree selection algorithm (linked priority queue--Knuth, Vol.3,
- * pp.150-52)
+ * leftist tree selection algorithm (linked priority queue--Knuth, Vol.3,
+ * pp.150-52)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.5 1997/08/12 22:55:00 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/lselect.c,v 1.6 1997/09/07 04:54:16 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,295 +26,340 @@
#include "utils/psort.h"
#include "utils/lselect.h"
-#define PUTTUP(TUP, FP) fwrite((char *)TUP, (TUP)->t_len, 1, FP)
+#define PUTTUP(TUP, FP) fwrite((char *)TUP, (TUP)->t_len, 1, FP)
/*
- * USEMEM - record use of memory
- * FREEMEM - record freeing of memory
+ * USEMEM - record use of memory
+ * FREEMEM - record freeing of memory
*/
-#define USEMEM(context,AMT) context->sortMem -= (AMT)
-#define FREEMEM(context,AMT) context->sortMem += (AMT)
+#define USEMEM(context,AMT) context->sortMem -= (AMT)
+#define FREEMEM(context,AMT) context->sortMem += (AMT)
/*
- * lmerge - merges two leftist trees into one
+ * lmerge - merges two leftist trees into one
*
- * Note:
- * Enforcing the rule that pt->lt_dist >= qt->lt_dist may
- * simplifify much of the code. Removing recursion will not
- * speed up code significantly.
+ * Note:
+ * Enforcing the rule that pt->lt_dist >= qt->lt_dist may
+ * simplifify much of the code. Removing recursion will not
+ * speed up code significantly.
*/
struct leftist *
-lmerge(struct leftist *pt, struct leftist *qt, LeftistContext context)
+lmerge(struct leftist * pt, struct leftist * qt, LeftistContext context)
{
- register struct leftist *root, *majorLeftist, *minorLeftist;
- int dist;
-
- if (tuplecmp(pt->lt_tuple, qt->lt_tuple, context)) {
- root = pt;
- majorLeftist = qt;
- } else {
- root = qt;
- majorLeftist = pt;
- }
- if (root->lt_left == NULL)
- root->lt_left = majorLeftist;
- else {
- if ((minorLeftist = root->lt_right) != NULL)
- majorLeftist = lmerge(majorLeftist, minorLeftist, context);
- if ((dist = root->lt_left->lt_dist) < majorLeftist->lt_dist) {
- root->lt_dist = 1 + dist;
- root->lt_right = root->lt_left;
- root->lt_left = majorLeftist;
- } else {
- root->lt_dist = 1 + majorLeftist->lt_dist;
- root->lt_right = majorLeftist;
+ register struct leftist *root,
+ *majorLeftist,
+ *minorLeftist;
+ int dist;
+
+ if (tuplecmp(pt->lt_tuple, qt->lt_tuple, context))
+ {
+ root = pt;
+ majorLeftist = qt;
+ }
+ else
+ {
+ root = qt;
+ majorLeftist = pt;
}
- }
- return(root);
+ if (root->lt_left == NULL)
+ root->lt_left = majorLeftist;
+ else
+ {
+ if ((minorLeftist = root->lt_right) != NULL)
+ majorLeftist = lmerge(majorLeftist, minorLeftist, context);
+ if ((dist = root->lt_left->lt_dist) < majorLeftist->lt_dist)
+ {
+ root->lt_dist = 1 + dist;
+ root->lt_right = root->lt_left;
+ root->lt_left = majorLeftist;
+ }
+ else
+ {
+ root->lt_dist = 1 + majorLeftist->lt_dist;
+ root->lt_right = majorLeftist;
+ }
+ }
+ return (root);
}
static struct leftist *
-linsert(struct leftist *root, struct leftist *new1, LeftistContext context)
+linsert(struct leftist * root, struct leftist * new1, LeftistContext context)
{
- register struct leftist *left, *right;
-
- if (! tuplecmp(root->lt_tuple, new1->lt_tuple, context)) {
- new1->lt_left = root;
- return(new1);
- }
- left = root->lt_left;
- right = root->lt_right;
- if (right == NULL) {
- if (left == NULL)
- root->lt_left = new1;
- else {
- root->lt_right = new1;
- root->lt_dist = 2;
+ register struct leftist *left,
+ *right;
+
+ if (!tuplecmp(root->lt_tuple, new1->lt_tuple, context))
+ {
+ new1->lt_left = root;
+ return (new1);
+ }
+ left = root->lt_left;
+ right = root->lt_right;
+ if (right == NULL)
+ {
+ if (left == NULL)
+ root->lt_left = new1;
+ else
+ {
+ root->lt_right = new1;
+ root->lt_dist = 2;
+ }
+ return (root);
+ }
+ right = linsert(right, new1, context);
+ if (right->lt_dist < left->lt_dist)
+ {
+ root->lt_dist = 1 + left->lt_dist;
+ root->lt_left = right;
+ root->lt_right = left;
+ }
+ else
+ {
+ root->lt_dist = 1 + right->lt_dist;
+ root->lt_right = right;
}
- return(root);
- }
- right = linsert(right, new1, context);
- if (right->lt_dist < left->lt_dist) {
- root->lt_dist = 1 + left->lt_dist;
- root->lt_left = right;
- root->lt_right = left;
- } else {
- root->lt_dist = 1 + right->lt_dist;
- root->lt_right = right;
- }
- return(root);
+ return (root);
}
/*
- * gettuple - returns tuple at top of tree (Tuples)
+ * gettuple - returns tuple at top of tree (Tuples)
*
- * Returns:
- * tuple at top of tree, NULL if failed ALLOC()
- * *devnum is set to the devnum of tuple returned
- * *treep is set to the new tree
+ * Returns:
+ * tuple at top of tree, NULL if failed ALLOC()
+ * *devnum is set to the devnum of tuple returned
+ * *treep is set to the new tree
*
- * Note:
- * *treep must not be NULL
- * NULL is currently never returned BUG
+ * Note:
+ * *treep must not be NULL
+ * NULL is currently never returned BUG
*/
HeapTuple
-gettuple(struct leftist **treep,
- short *devnum, /* device from which tuple came */
- LeftistContext context)
+gettuple(struct leftist ** treep,
+ short *devnum, /* device from which tuple came */
+ LeftistContext context)
{
- register struct leftist *tp;
- HeapTuple tup;
-
- tp = *treep;
- tup = tp->lt_tuple;
- *devnum = tp->lt_devnum;
- if (tp->lt_dist == 1) /* lt_left == NULL */
- *treep = tp->lt_left;
- else
- *treep = lmerge(tp->lt_left, tp->lt_right, context);
-
- FREEMEM(context,sizeof (struct leftist));
- FREE(tp);
- return(tup);
+ register struct leftist *tp;
+ HeapTuple tup;
+
+ tp = *treep;
+ tup = tp->lt_tuple;
+ *devnum = tp->lt_devnum;
+ if (tp->lt_dist == 1) /* lt_left == NULL */
+ *treep = tp->lt_left;
+ else
+ *treep = lmerge(tp->lt_left, tp->lt_right, context);
+
+ FREEMEM(context, sizeof(struct leftist));
+ FREE(tp);
+ return (tup);
}
/*
- * puttuple - inserts new tuple into tree
+ * puttuple - inserts new tuple into tree
*
- * Returns:
- * NULL iff failed ALLOC()
+ * Returns:
+ * NULL iff failed ALLOC()
*
- * Note:
- * Currently never returns NULL BUG
+ * Note:
+ * Currently never returns NULL BUG
*/
void
-puttuple(struct leftist **treep,
- HeapTuple newtuple,
- short devnum,
- LeftistContext context)
+puttuple(struct leftist ** treep,
+ HeapTuple newtuple,
+ short devnum,
+ LeftistContext context)
{
- register struct leftist *new1;
- register struct leftist *tp;
-
- new1 = (struct leftist *) palloc((unsigned) sizeof (struct leftist));
- USEMEM(context,sizeof (struct leftist));
- new1->lt_dist = 1;
- new1->lt_devnum = devnum;
- new1->lt_tuple = newtuple;
- new1->lt_left = NULL;
- new1->lt_right = NULL;
- if ((tp = *treep) == NULL)
- *treep = new1;
- else
- *treep = linsert(tp, new1, context);
- return;
+ register struct leftist *new1;
+ register struct leftist *tp;
+
+ new1 = (struct leftist *) palloc((unsigned) sizeof(struct leftist));
+ USEMEM(context, sizeof(struct leftist));
+ new1->lt_dist = 1;
+ new1->lt_devnum = devnum;
+ new1->lt_tuple = newtuple;
+ new1->lt_left = NULL;
+ new1->lt_right = NULL;
+ if ((tp = *treep) == NULL)
+ *treep = new1;
+ else
+ *treep = linsert(tp, new1, context);
+ return;
}
/*
- * tuplecmp - Compares two tuples with respect CmpList
+ * tuplecmp - Compares two tuples with respect CmpList
*
- * Returns:
- * 1 if left < right ;0 otherwise
- * Assumtions:
+ * Returns:
+ * 1 if left < right ;0 otherwise
+ * Assumtions:
*/
int
tuplecmp(HeapTuple ltup, HeapTuple rtup, LeftistContext context)
{
- register char *lattr, *rattr;
- int nkey = 0;
- int result = 0;
- bool isnull;
-
- if (ltup == (HeapTuple)NULL)
- return(0);
- if (rtup == (HeapTuple)NULL)
- return(1);
- while (nkey < context->nKeys && !result) {
- lattr = heap_getattr(ltup, InvalidBuffer,
- context->scanKeys[nkey].sk_attno,
- context->tupDesc, &isnull);
- if (isnull)
- return(0);
- rattr = heap_getattr(rtup, InvalidBuffer,
- context->scanKeys[nkey].sk_attno,
- context->tupDesc,
- &isnull);
- if (isnull)
- return(1);
- if (context->scanKeys[nkey].sk_flags & SK_COMMUTE) {
- if (!(result =
- (long) (*context->scanKeys[nkey].sk_func) (rattr, lattr)))
- result =
- -(long) (*context->scanKeys[nkey].sk_func) (lattr, rattr);
- } else if (!(result =
- (long) (*context->scanKeys[nkey].sk_func) (lattr, rattr)))
- result =
- -(long) (*context->scanKeys[nkey].sk_func) (rattr, lattr);
- nkey++;
- }
- return (result == 1);
+ register char *lattr,
+ *rattr;
+ int nkey = 0;
+ int result = 0;
+ bool isnull;
+
+ if (ltup == (HeapTuple) NULL)
+ return (0);
+ if (rtup == (HeapTuple) NULL)
+ return (1);
+ while (nkey < context->nKeys && !result)
+ {
+ lattr = heap_getattr(ltup, InvalidBuffer,
+ context->scanKeys[nkey].sk_attno,
+ context->tupDesc, &isnull);
+ if (isnull)
+ return (0);
+ rattr = heap_getattr(rtup, InvalidBuffer,
+ context->scanKeys[nkey].sk_attno,
+ context->tupDesc,
+ &isnull);
+ if (isnull)
+ return (1);
+ if (context->scanKeys[nkey].sk_flags & SK_COMMUTE)
+ {
+ if (!(result =
+ (long) (*context->scanKeys[nkey].sk_func) (rattr, lattr)))
+ result =
+ -(long) (*context->scanKeys[nkey].sk_func) (lattr, rattr);
+ }
+ else if (!(result =
+ (long) (*context->scanKeys[nkey].sk_func) (lattr, rattr)))
+ result =
+ -(long) (*context->scanKeys[nkey].sk_func) (rattr, lattr);
+ nkey++;
+ }
+ return (result == 1);
}
#ifdef EBUG
void
-checktree(struct leftist *tree, LeftistContext context)
+checktree(struct leftist * tree, LeftistContext context)
{
- int lnodes;
- int rnodes;
-
- if (tree == NULL) {
- puts("Null tree.");
- return;
- }
- lnodes = checktreer(tree->lt_left, 1, context);
- rnodes = checktreer(tree->lt_right, 1, context);
- if (lnodes < 0) {
- lnodes = -lnodes;
- puts("0:\tBad left side.");
- }
- if (rnodes < 0) {
- rnodes = -rnodes;
- puts("0:\tBad right side.");
- }
- if (lnodes == 0) {
- if (rnodes != 0)
- puts("0:\tLeft and right reversed.");
- if (tree->lt_dist != 1)
- puts("0:\tDistance incorrect.");
- } else if (rnodes == 0) {
- if (tree->lt_dist != 1)
- puts("0:\tDistance incorrect.");
- } else if (tree->lt_left->lt_dist < tree->lt_right->lt_dist) {
- puts("0:\tLeft and right reversed.");
- if (tree->lt_dist != 1 + tree->lt_left->lt_dist)
- puts("0:\tDistance incorrect.");
- } else if (tree->lt_dist != 1+ tree->lt_right->lt_dist)
- puts("0:\tDistance incorrect.");
- if (lnodes > 0)
- if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple, context))
- printf("%d:\tLeft child < parent.\n");
- if (rnodes > 0)
- if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple, context))
- printf("%d:\tRight child < parent.\n");
- printf("Tree has %d nodes\n", 1 + lnodes + rnodes);
+ int lnodes;
+ int rnodes;
+
+ if (tree == NULL)
+ {
+ puts("Null tree.");
+ return;
+ }
+ lnodes = checktreer(tree->lt_left, 1, context);
+ rnodes = checktreer(tree->lt_right, 1, context);
+ if (lnodes < 0)
+ {
+ lnodes = -lnodes;
+ puts("0:\tBad left side.");
+ }
+ if (rnodes < 0)
+ {
+ rnodes = -rnodes;
+ puts("0:\tBad right side.");
+ }
+ if (lnodes == 0)
+ {
+ if (rnodes != 0)
+ puts("0:\tLeft and right reversed.");
+ if (tree->lt_dist != 1)
+ puts("0:\tDistance incorrect.");
+ }
+ else if (rnodes == 0)
+ {
+ if (tree->lt_dist != 1)
+ puts("0:\tDistance incorrect.");
+ }
+ else if (tree->lt_left->lt_dist < tree->lt_right->lt_dist)
+ {
+ puts("0:\tLeft and right reversed.");
+ if (tree->lt_dist != 1 + tree->lt_left->lt_dist)
+ puts("0:\tDistance incorrect.");
+ }
+ else if (tree->lt_dist != 1 + tree->lt_right->lt_dist)
+ puts("0:\tDistance incorrect.");
+ if (lnodes > 0)
+ if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple, context))
+ printf("%d:\tLeft child < parent.\n");
+ if (rnodes > 0)
+ if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple, context))
+ printf("%d:\tRight child < parent.\n");
+ printf("Tree has %d nodes\n", 1 + lnodes + rnodes);
}
int
-checktreer(struct leftist *tree, int level, LeftistContext context)
+checktreer(struct leftist * tree, int level, LeftistContext context)
{
- int lnodes, rnodes;
- int error = 0;
-
- if (tree == NULL)
- return(0);
- lnodes = checktreer(tree->lt_left, level + 1, context);
- rnodes = checktreer(tree->lt_right, level + 1, context);
- if (lnodes < 0) {
- error = 1;
- lnodes = -lnodes;
- printf("%d:\tBad left side.\n", level);
- }
- if (rnodes < 0) {
- error = 1;
- rnodes = -rnodes;
- printf("%d:\tBad right side.\n", level);
- }
- if (lnodes == 0) {
- if (rnodes != 0) {
- error = 1;
- printf("%d:\tLeft and right reversed.\n", level);
+ int lnodes,
+ rnodes;
+ int error = 0;
+
+ if (tree == NULL)
+ return (0);
+ lnodes = checktreer(tree->lt_left, level + 1, context);
+ rnodes = checktreer(tree->lt_right, level + 1, context);
+ if (lnodes < 0)
+ {
+ error = 1;
+ lnodes = -lnodes;
+ printf("%d:\tBad left side.\n", level);
}
- if (tree->lt_dist != 1) {
- error = 1;
- printf("%d:\tDistance incorrect.\n", level);
+ if (rnodes < 0)
+ {
+ error = 1;
+ rnodes = -rnodes;
+ printf("%d:\tBad right side.\n", level);
}
- } else if (rnodes == 0) {
- if (tree->lt_dist != 1) {
- error = 1;
- printf("%d:\tDistance incorrect.\n", level);
- }
- } else if (tree->lt_left->lt_dist < tree->lt_right->lt_dist) {
- error = 1;
- printf("%d:\tLeft and right reversed.\n", level);
- if (tree->lt_dist != 1 + tree->lt_left->lt_dist)
- printf("%d:\tDistance incorrect.\n", level);
- } else if (tree->lt_dist != 1+ tree->lt_right->lt_dist) {
- error = 1;
- printf("%d:\tDistance incorrect.\n", level);
- }
- if (lnodes > 0)
- if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple, context)) {
- error = 1;
- printf("%d:\tLeft child < parent.\n");
+ if (lnodes == 0)
+ {
+ if (rnodes != 0)
+ {
+ error = 1;
+ printf("%d:\tLeft and right reversed.\n", level);
+ }
+ if (tree->lt_dist != 1)
+ {
+ error = 1;
+ printf("%d:\tDistance incorrect.\n", level);
+ }
}
- if (rnodes > 0)
- if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple, context)) {
- error = 1;
- printf("%d:\tRight child < parent.\n");
+ else if (rnodes == 0)
+ {
+ if (tree->lt_dist != 1)
+ {
+ error = 1;
+ printf("%d:\tDistance incorrect.\n", level);
+ }
}
- if (error)
- return(-1 + -lnodes + -rnodes);
- return(1 + lnodes + rnodes);
+ else if (tree->lt_left->lt_dist < tree->lt_right->lt_dist)
+ {
+ error = 1;
+ printf("%d:\tLeft and right reversed.\n", level);
+ if (tree->lt_dist != 1 + tree->lt_left->lt_dist)
+ printf("%d:\tDistance incorrect.\n", level);
+ }
+ else if (tree->lt_dist != 1 + tree->lt_right->lt_dist)
+ {
+ error = 1;
+ printf("%d:\tDistance incorrect.\n", level);
+ }
+ if (lnodes > 0)
+ if (tuplecmp(tree->lt_left->lt_tuple, tree->lt_tuple, context))
+ {
+ error = 1;
+ printf("%d:\tLeft child < parent.\n");
+ }
+ if (rnodes > 0)
+ if (tuplecmp(tree->lt_right->lt_tuple, tree->lt_tuple, context))
+ {
+ error = 1;
+ printf("%d:\tRight child < parent.\n");
+ }
+ if (error)
+ return (-1 + -lnodes + -rnodes);
+ return (1 + lnodes + rnodes);
}
+
#endif
diff --git a/src/backend/utils/sort/psort.c b/src/backend/utils/sort/psort.c
index 12486166268..00cbfbacba5 100644
--- a/src/backend/utils/sort/psort.c
+++ b/src/backend/utils/sort/psort.c
@@ -1,36 +1,36 @@
/*-------------------------------------------------------------------------
*
* psort.c--
- * Polyphase merge sort.
+ * Polyphase merge sort.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.18 1997/09/05 00:09:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/sort/Attic/psort.c,v 1.19 1997/09/07 04:54:17 momjian Exp $
*
* NOTES
- * Sorts the first relation into the second relation.
+ * Sorts the first relation into the second relation.
*
- * The old psort.c's routines formed a temporary relation from the merged
+ * The old psort.c's routines formed a temporary relation from the merged
* sort files. This version keeps the files around instead of generating the
* relation from them, and provides interface functions to the file so that
* you can grab tuples, mark a position in the file, restore a position in the
* file. You must now explicitly call an interface function to end the sort,
* psort_end, when you are done.
- * Now most of the global variables are stuck in the Sort nodes, and
+ * Now most of the global variables are stuck in the Sort nodes, and
* accessed from there (they are passed to all the psort routines) so that
* each sort running has its own separate state. This is facilitated by having
* the Sort nodes passed in to all the interface functions.
- * The one global variable that all the sorts still share is SortMemory.
- * You should now be allowed to run two or more psorts concurrently,
+ * The one global variable that all the sorts still share is SortMemory.
+ * You should now be allowed to run two or more psorts concurrently,
* so long as the memory they eat up is not greater than SORTMEM, the initial
- * value of SortMemory. -Rex 2.15.1995
+ * value of SortMemory. -Rex 2.15.1995
*
- * Use the tape-splitting method (Knuth, Vol. III, pp281-86) in the future.
+ * Use the tape-splitting method (Knuth, Vol. III, pp281-86) in the future.
*
- * Arguments? Variables?
- * MAXMERGE, MAXTAPES
+ * Arguments? Variables?
+ * MAXMERGE, MAXTAPES
*-------------------------------------------------------------------------
*/
#include <stdio.h>
@@ -46,11 +46,11 @@
#include "access/htup.h"
#include "access/relscan.h"
#include "access/skey.h"
-#include "utils/tqual.h" /* for NowTimeQual */
+#include "utils/tqual.h" /* for NowTimeQual */
#include "storage/buf.h"
-#include "storage/bufmgr.h" /* for BLCKSZ */
-#include "utils/portal.h" /* for {Start,End}PortalAllocMode */
+#include "storage/bufmgr.h" /* for BLCKSZ */
+#include "utils/portal.h" /* for {Start,End}PortalAllocMode */
#include "utils/elog.h"
#include "utils/rel.h"
@@ -64,47 +64,47 @@
#include "miscadmin.h"
#include "storage/fd.h"
-static bool createrun(Sort *node, FILE *file, bool *empty);
-static void destroytape(FILE *file);
-static void dumptuples(FILE *file, Sort *node);
-static FILE *gettape(void);
-static void initialrun(Sort *node, bool *empty);
-static void inittapes(Sort *node);
-static void merge(Sort *node, struct tape *dest);
-static FILE *mergeruns(Sort *node);
+static bool createrun(Sort * node, FILE * file, bool * empty);
+static void destroytape(FILE * file);
+static void dumptuples(FILE * file, Sort * node);
+static FILE *gettape(void);
+static void initialrun(Sort * node, bool * empty);
+static void inittapes(Sort * node);
+static void merge(Sort * node, struct tape * dest);
+static FILE *mergeruns(Sort * node);
static HeapTuple tuplecopy(HeapTuple tup);
-#define TEMPDIR "./"
+#define TEMPDIR "./"
-static long shortzero = 0; /* used to delimit runs */
+static long shortzero = 0; /* used to delimit runs */
/*
* old psort global variables
*
* (These are the global variables from the old psort. They are still used,
- * but are now accessed from Sort nodes using the PS macro. Note that while
- * these variables will be accessed by PS(node)->whatever, they will still
- * be called by their original names within the comments! -Rex 2.10.1995)
+ * but are now accessed from Sort nodes using the PS macro. Note that while
+ * these variables will be accessed by PS(node)->whatever, they will still
+ * be called by their original names within the comments! -Rex 2.10.1995)
*
- * LeftistContextData treeContext;
+ * LeftistContextData treeContext;
*
- * static int TapeRange; number of tapes - 1 (T)
- * static int Level; (l)
- * static int TotalDummy; summation of tp_dummy
- * static struct tape *Tape;
+ * static int TapeRange; number of tapes - 1 (T)
+ * static int Level; (l)
+ * static int TotalDummy; summation of tp_dummy
+ * static struct tape *Tape;
*
- * static int BytesRead; to keep track of # of IO
- * static int BytesWritten;
+ * static int BytesRead; to keep track of # of IO
+ * static int BytesWritten;
*
- * struct leftist *Tuples; current tuples in memory
+ * struct leftist *Tuples; current tuples in memory
*
- * FILE *psort_grab_file; this holds tuples grabbed
- * from merged sort runs
- * long psort_current; current file position
- * long psort_saved; file position saved for
- * mark and restore
+ * FILE *psort_grab_file; this holds tuples grabbed
+ * from merged sort runs
+ * long psort_current; current file position
+ * long psort_saved; file position saved for
+ * mark and restore
*/
/*
@@ -113,730 +113,777 @@ static long shortzero = 0; /* used to delimit runs */
#define PS(N) ((Psortstate *)N->psortstate)
/*
- * psort_begin - polyphase merge sort entry point. Sorts the subplan
- * into a temporary file psort_grab_file. After
- * this is called, calling the interface function
- * psort_grabtuple iteratively will get you the sorted
- * tuples. psort_end then finishes the sort off, after
- * all the tuples have been grabbed.
+ * psort_begin - polyphase merge sort entry point. Sorts the subplan
+ * into a temporary file psort_grab_file. After
+ * this is called, calling the interface function
+ * psort_grabtuple iteratively will get you the sorted
+ * tuples. psort_end then finishes the sort off, after
+ * all the tuples have been grabbed.
*
- * Allocates and initializes sort node's psort state.
+ * Allocates and initializes sort node's psort state.
*/
bool
-psort_begin(Sort *node, int nkeys, ScanKey key)
+psort_begin(Sort * node, int nkeys, ScanKey key)
{
- bool empty; /* to answer: is child node empty? */
-
- node->psortstate = (struct Psortstate *)palloc(sizeof(struct Psortstate));
- if (node->psortstate == NULL)
- return false;
-
- AssertArg(nkeys >= 1);
- AssertArg(key[0].sk_attno != 0);
- AssertArg(key[0].sk_procedure != 0);
-
- PS(node)->BytesRead = 0;
- PS(node)->BytesWritten = 0;
- PS(node)->treeContext.tupDesc =
- ExecGetTupType(outerPlan((Plan *)node));
- PS(node)->treeContext.nKeys = nkeys;
- PS(node)->treeContext.scanKeys = key;
- PS(node)->treeContext.sortMem = SortMem * 1024;
-
- PS(node)->Tuples = NULL;
- PS(node)->tupcount = 0;
-
- PS(node)->using_tape_files = false;
- PS(node)->memtuples = NULL;
-
- initialrun(node, &empty);
-
- if (empty)
- return false;
-
- if (PS(node)->using_tape_files)
- PS(node)->psort_grab_file = mergeruns(node);
-
- PS(node)->psort_current = 0;
- PS(node)->psort_saved = 0;
-
- return true;
+ bool empty; /* to answer: is child node empty? */
+
+ node->psortstate = (struct Psortstate *) palloc(sizeof(struct Psortstate));
+ if (node->psortstate == NULL)
+ return false;
+
+ AssertArg(nkeys >= 1);
+ AssertArg(key[0].sk_attno != 0);
+ AssertArg(key[0].sk_procedure != 0);
+
+ PS(node)->BytesRead = 0;
+ PS(node)->BytesWritten = 0;
+ PS(node)->treeContext.tupDesc =
+ ExecGetTupType(outerPlan((Plan *) node));
+ PS(node)->treeContext.nKeys = nkeys;
+ PS(node)->treeContext.scanKeys = key;
+ PS(node)->treeContext.sortMem = SortMem * 1024;
+
+ PS(node)->Tuples = NULL;
+ PS(node)->tupcount = 0;
+
+ PS(node)->using_tape_files = false;
+ PS(node)->memtuples = NULL;
+
+ initialrun(node, &empty);
+
+ if (empty)
+ return false;
+
+ if (PS(node)->using_tape_files)
+ PS(node)->psort_grab_file = mergeruns(node);
+
+ PS(node)->psort_current = 0;
+ PS(node)->psort_saved = 0;
+
+ return true;
}
/*
- * inittapes - initializes the tapes
- * - (polyphase merge Alg.D(D1)--Knuth, Vol.3, p.270)
- * Returns:
- * number of allocated tapes
+ * inittapes - initializes the tapes
+ * - (polyphase merge Alg.D(D1)--Knuth, Vol.3, p.270)
+ * Returns:
+ * number of allocated tapes
*/
static void
-inittapes(Sort *node)
+inittapes(Sort * node)
{
- register int i;
- register struct tape *tp;
-
- Assert(node != (Sort *) NULL);
- Assert(PS(node) != (Psortstate *) NULL);
-
- /*
- ASSERT(ntapes >= 3 && ntapes <= MAXTAPES,
- "inittapes: Invalid number of tapes to initialize.\n");
- */
-
- tp = PS(node)->Tape;
- for (i = 0; i < MAXTAPES && (tp->tp_file = gettape()) != NULL; i++) {
- tp->tp_dummy = 1;
- tp->tp_fib = 1;
- tp->tp_prev = tp - 1;
- tp++;
- }
- PS(node)->TapeRange = --tp - PS(node)->Tape;
- tp->tp_dummy = 0;
- tp->tp_fib = 0;
- PS(node)->Tape[0].tp_prev = tp;
-
- if (PS(node)->TapeRange <= 1)
- elog(WARN, "inittapes: Could only allocate %d < 3 tapes\n",
- PS(node)->TapeRange + 1);
-
- PS(node)->Level = 1;
- PS(node)->TotalDummy = PS(node)->TapeRange;
-
- PS(node)->using_tape_files = true;
+ register int i;
+ register struct tape *tp;
+
+ Assert(node != (Sort *) NULL);
+ Assert(PS(node) != (Psortstate *) NULL);
+
+ /*
+ * ASSERT(ntapes >= 3 && ntapes <= MAXTAPES, "inittapes: Invalid
+ * number of tapes to initialize.\n");
+ */
+
+ tp = PS(node)->Tape;
+ for (i = 0; i < MAXTAPES && (tp->tp_file = gettape()) != NULL; i++)
+ {
+ tp->tp_dummy = 1;
+ tp->tp_fib = 1;
+ tp->tp_prev = tp - 1;
+ tp++;
+ }
+ PS(node)->TapeRange = --tp - PS(node)->Tape;
+ tp->tp_dummy = 0;
+ tp->tp_fib = 0;
+ PS(node)->Tape[0].tp_prev = tp;
+
+ if (PS(node)->TapeRange <= 1)
+ elog(WARN, "inittapes: Could only allocate %d < 3 tapes\n",
+ PS(node)->TapeRange + 1);
+
+ PS(node)->Level = 1;
+ PS(node)->TotalDummy = PS(node)->TapeRange;
+
+ PS(node)->using_tape_files = true;
}
/*
- * PUTTUP - writes the next tuple
- * ENDRUN - mark end of run
- * GETLEN - reads the length of the next tuple
- * ALLOCTUP - returns space for the new tuple
- * SETTUPLEN - stores the length into the tuple
- * GETTUP - reads the tuple
+ * PUTTUP - writes the next tuple
+ * ENDRUN - mark end of run
+ * GETLEN - reads the length of the next tuple
+ * ALLOCTUP - returns space for the new tuple
+ * SETTUPLEN - stores the length into the tuple
+ * GETTUP - reads the tuple
*
- * Note:
- * LEN field must be a short; FP is a stream
+ * Note:
+ * LEN field must be a short; FP is a stream
*/
-#define PUTTUP(NODE, TUP, FP) do {\
- ((Psortstate *)NODE->psortstate)->BytesWritten += (TUP)->t_len; \
- fwrite((char *)TUP, (TUP)->t_len, 1, FP);} while (0)
-#define ENDRUN(FP) fwrite((char *)&shortzero, sizeof (shortzero), 1, FP)
-#define GETLEN(LEN, FP) fread((char *)&(LEN), sizeof (shortzero), 1, FP)
-#define ALLOCTUP(LEN) ((HeapTuple)palloc((unsigned)LEN))
-#define GETTUP(NODE, TUP, LEN, FP) do {\
- IncrProcessed(); \
- ((Psortstate *)NODE->psortstate)->BytesRead += (LEN) - sizeof (shortzero); \
- fread((char *)(TUP) + sizeof (shortzero), (LEN) - sizeof (shortzero), 1, FP);} \
- while (0)
-#define SETTUPLEN(TUP, LEN) (TUP)->t_len = LEN
-
- /*
- * USEMEM - record use of memory
- * FREEMEM - record freeing of memory
- * FULLMEM - 1 iff a tuple will fit
- */
-
-#define USEMEM(NODE,AMT) PS(node)->treeContext.sortMem -= (AMT)
-#define FREEMEM(NODE,AMT) PS(node)->treeContext.sortMem += (AMT)
-#define LACKMEM(NODE) (PS(node)->treeContext.sortMem <= MAXBLCKSZ) /* not accurate */
-#define TRACEMEM(FUNC)
-#define TRACEOUT(FUNC, TUP)
+#define PUTTUP(NODE, TUP, FP) do {\
+ ((Psortstate *)NODE->psortstate)->BytesWritten += (TUP)->t_len; \
+ fwrite((char *)TUP, (TUP)->t_len, 1, FP);} while (0)
+#define ENDRUN(FP) fwrite((char *)&shortzero, sizeof (shortzero), 1, FP)
+#define GETLEN(LEN, FP) fread((char *)&(LEN), sizeof (shortzero), 1, FP)
+#define ALLOCTUP(LEN) ((HeapTuple)palloc((unsigned)LEN))
+#define GETTUP(NODE, TUP, LEN, FP) do {\
+ IncrProcessed(); \
+ ((Psortstate *)NODE->psortstate)->BytesRead += (LEN) - sizeof (shortzero); \
+ fread((char *)(TUP) + sizeof (shortzero), (LEN) - sizeof (shortzero), 1, FP);} \
+ while (0)
+#define SETTUPLEN(TUP, LEN) (TUP)->t_len = LEN
+
+ /*
+ * USEMEM - record use of memory FREEMEM - record
+ * freeing of memory FULLMEM - 1 iff a tuple will fit
+ */
+
+#define USEMEM(NODE,AMT) PS(node)->treeContext.sortMem -= (AMT)
+#define FREEMEM(NODE,AMT) PS(node)->treeContext.sortMem += (AMT)
+#define LACKMEM(NODE) (PS(node)->treeContext.sortMem <= MAXBLCKSZ) /* not accurate */
+#define TRACEMEM(FUNC)
+#define TRACEOUT(FUNC, TUP)
/*
- * initialrun - distributes tuples from the relation
- * - (replacement selection(R2-R3)--Knuth, Vol.3, p.257)
- * - (polyphase merge Alg.D(D2-D4)--Knuth, Vol.3, p.271)
+ * initialrun - distributes tuples from the relation
+ * - (replacement selection(R2-R3)--Knuth, Vol.3, p.257)
+ * - (polyphase merge Alg.D(D2-D4)--Knuth, Vol.3, p.271)
*
- * Explaination:
- * Tuples are distributed to the tapes as in Algorithm D.
- * A "tuple" with t_size == 0 is used to mark the end of a run.
+ * Explaination:
+ * Tuples are distributed to the tapes as in Algorithm D.
+ * A "tuple" with t_size == 0 is used to mark the end of a run.
*
- * Note:
- * The replacement selection algorithm has been modified
- * to go from R1 directly to R3 skipping R2 the first time.
+ * Note:
+ * The replacement selection algorithm has been modified
+ * to go from R1 directly to R3 skipping R2 the first time.
*
- * Maybe should use closer(rdesc) before return
- * Perhaps should adjust the number of tapes if less than n.
- * used--v. likely to have problems in mergeruns().
- * Must know if should open/close files before each
- * call to psort()? If should--messy??
+ * Maybe should use closer(rdesc) before return
+ * Perhaps should adjust the number of tapes if less than n.
+ * used--v. likely to have problems in mergeruns().
+ * Must know if should open/close files before each
+ * call to psort()? If should--messy??
*
- * Possible optimization:
- * put the first xxx runs in quickly--problem here since
- * I (perhaps prematurely) combined the 2 algorithms.
- * Also, perhaps allocate tapes when needed. Split into 2 funcs.
+ * Possible optimization:
+ * put the first xxx runs in quickly--problem here since
+ * I (perhaps prematurely) combined the 2 algorithms.
+ * Also, perhaps allocate tapes when needed. Split into 2 funcs.
*/
static void
-initialrun(Sort *node, bool *empty)
+initialrun(Sort * node, bool * empty)
{
- /* register struct tuple *tup; */
- register struct tape *tp;
- int baseruns; /* D:(a) */
- int extrapasses; /* EOF */
-
- Assert(node != (Sort *) NULL);
- Assert(PS(node) != (Psortstate *) NULL);
-
- tp = PS(node)->Tape;
-
- if ((bool)createrun(node, NULL, empty) != false) {
- if (! PS(node)->using_tape_files)
- inittapes(node);
- extrapasses = 0;
- }
- else {
- /* if empty or rows fit in memory, we never access tape stuff */
- if (*empty || ! PS(node)->using_tape_files)
- return;
- if (! PS(node)->using_tape_files)
- inittapes(node);
- extrapasses = 1 + (PS(node)->Tuples != NULL); /* (T != N) ? 2 : 1 */
- }
-
- for ( ; ; ) {
- tp->tp_dummy--;
- PS(node)->TotalDummy--;
- if (tp->tp_dummy < (tp + 1)->tp_dummy)
- tp++;
- else if (tp->tp_dummy != 0)
- tp = PS(node)->Tape;
- else {
- PS(node)->Level++;
- baseruns = PS(node)->Tape[0].tp_fib;
- for (tp = PS(node)->Tape;
- tp - PS(node)->Tape < PS(node)->TapeRange; tp++) {
- PS(node)->TotalDummy +=
- (tp->tp_dummy = baseruns
- + (tp + 1)->tp_fib
- - tp->tp_fib);
- tp->tp_fib = baseruns
- + (tp + 1)->tp_fib;
- }
- tp = PS(node)->Tape; /* D4 */
- } /* D3 */
- if (extrapasses)
- if (--extrapasses) {
- dumptuples(tp->tp_file, node);
- ENDRUN(tp->tp_file);
- continue;
- } else
- break;
-
- if ((bool)createrun(node, tp->tp_file, empty) == false)
- extrapasses = 1 + (PS(node)->Tuples != NULL);
- /* D2 */
- }
- for (tp = PS(node)->Tape + PS(node)->TapeRange; tp >= PS(node)->Tape; tp--)
- rewind(tp->tp_file); /* D. */
+ /* register struct tuple *tup; */
+ register struct tape *tp;
+ int baseruns; /* D:(a) */
+ int extrapasses;/* EOF */
+
+ Assert(node != (Sort *) NULL);
+ Assert(PS(node) != (Psortstate *) NULL);
+
+ tp = PS(node)->Tape;
+
+ if ((bool) createrun(node, NULL, empty) != false)
+ {
+ if (!PS(node)->using_tape_files)
+ inittapes(node);
+ extrapasses = 0;
+ }
+ else
+ {
+ /* if empty or rows fit in memory, we never access tape stuff */
+ if (*empty || !PS(node)->using_tape_files)
+ return;
+ if (!PS(node)->using_tape_files)
+ inittapes(node);
+ extrapasses = 1 + (PS(node)->Tuples != NULL); /* (T != N) ? 2 : 1 */
+ }
+
+ for (;;)
+ {
+ tp->tp_dummy--;
+ PS(node)->TotalDummy--;
+ if (tp->tp_dummy < (tp + 1)->tp_dummy)
+ tp++;
+ else if (tp->tp_dummy != 0)
+ tp = PS(node)->Tape;
+ else
+ {
+ PS(node)->Level++;
+ baseruns = PS(node)->Tape[0].tp_fib;
+ for (tp = PS(node)->Tape;
+ tp - PS(node)->Tape < PS(node)->TapeRange; tp++)
+ {
+ PS(node)->TotalDummy +=
+ (tp->tp_dummy = baseruns
+ + (tp + 1)->tp_fib
+ - tp->tp_fib);
+ tp->tp_fib = baseruns
+ + (tp + 1)->tp_fib;
+ }
+ tp = PS(node)->Tape;/* D4 */
+ } /* D3 */
+ if (extrapasses)
+ if (--extrapasses)
+ {
+ dumptuples(tp->tp_file, node);
+ ENDRUN(tp->tp_file);
+ continue;
+ }
+ else
+ break;
+
+ if ((bool) createrun(node, tp->tp_file, empty) == false)
+ extrapasses = 1 + (PS(node)->Tuples != NULL);
+ /* D2 */
+ }
+ for (tp = PS(node)->Tape + PS(node)->TapeRange; tp >= PS(node)->Tape; tp--)
+ rewind(tp->tp_file); /* D. */
}
/*
- * createrun - places the next run on file, grabbing the tuples by
- * executing the subplan passed in
+ * createrun - places the next run on file, grabbing the tuples by
+ * executing the subplan passed in
*
- * Uses:
- * Tuples, which should contain any tuples for this run
+ * Uses:
+ * Tuples, which should contain any tuples for this run
*
- * Returns:
- * FALSE iff process through end of relation
- * Tuples contains the tuples for the following run upon exit
+ * Returns:
+ * FALSE iff process through end of relation
+ * Tuples contains the tuples for the following run upon exit
*/
-static bool
-createrun(Sort *node, FILE *file, bool *empty)
+static bool
+createrun(Sort * node, FILE * file, bool * empty)
{
- register HeapTuple lasttuple;
- register HeapTuple tup;
- struct leftist *nextrun;
- bool foundeor;
- short junk;
-
- int cr_tuples = 0; /* Count tuples grabbed from plannode */
- TupleTableSlot *cr_slot;
-
- Assert(node != (Sort *) NULL);
- Assert(PS(node) != (Psortstate *) NULL);
-
- lasttuple = NULL;
- nextrun = NULL;
- foundeor = false;
- for ( ; ; ) {
- while (LACKMEM(node) && PS(node)->Tuples != NULL) {
- if (lasttuple != NULL) {
- FREEMEM(node,lasttuple->t_len);
- FREE(lasttuple);
- TRACEMEM(createrun);
- }
- lasttuple = tup = gettuple(&PS(node)->Tuples, &junk,
- &PS(node)->treeContext);
- if (! PS(node)->using_tape_files) {
- inittapes(node);
- if (! file)
- file = PS(node)->Tape->tp_file; /* was NULL */
- }
- PUTTUP(node, tup, file);
- TRACEOUT(createrun, tup);
- }
- if (LACKMEM(node))
- break;
+ register HeapTuple lasttuple;
+ register HeapTuple tup;
+ struct leftist *nextrun;
+ bool foundeor;
+ short junk;
- /* About to call ExecProcNode, it can mess up the state if it
- * eventually calls another Sort node. So must stow it away here for
- * the meantime. -Rex 2.2.1995
- */
+ int cr_tuples = 0; /* Count tuples grabbed from
+ * plannode */
+ TupleTableSlot *cr_slot;
- cr_slot = ExecProcNode(outerPlan((Plan *)node), (Plan *)node);
+ Assert(node != (Sort *) NULL);
+ Assert(PS(node) != (Psortstate *) NULL);
+
+ lasttuple = NULL;
+ nextrun = NULL;
+ foundeor = false;
+ for (;;)
+ {
+ while (LACKMEM(node) && PS(node)->Tuples != NULL)
+ {
+ if (lasttuple != NULL)
+ {
+ FREEMEM(node, lasttuple->t_len);
+ FREE(lasttuple);
+ TRACEMEM(createrun);
+ }
+ lasttuple = tup = gettuple(&PS(node)->Tuples, &junk,
+ &PS(node)->treeContext);
+ if (!PS(node)->using_tape_files)
+ {
+ inittapes(node);
+ if (!file)
+ file = PS(node)->Tape->tp_file; /* was NULL */
+ }
+ PUTTUP(node, tup, file);
+ TRACEOUT(createrun, tup);
+ }
+ if (LACKMEM(node))
+ break;
+
+ /*
+ * About to call ExecProcNode, it can mess up the state if it
+ * eventually calls another Sort node. So must stow it away here
+ * for the meantime. -Rex
+ * 2.2.1995
+ */
+
+ cr_slot = ExecProcNode(outerPlan((Plan *) node), (Plan *) node);
+
+ if (TupIsNull(cr_slot))
+ {
+ foundeor = true;
+ break;
+ }
+ else
+ {
+ tup = tuplecopy(cr_slot->val);
+ ExecClearTuple(cr_slot);
+ PS(node)->tupcount++;
+ cr_tuples++;
+ }
- if (TupIsNull(cr_slot)) {
- foundeor = true;
- break;
+ IncrProcessed();
+ USEMEM(node, tup->t_len);
+ TRACEMEM(createrun);
+ if (lasttuple != NULL && tuplecmp(tup, lasttuple,
+ &PS(node)->treeContext))
+ puttuple(&nextrun, tup, 0, &PS(node)->treeContext);
+ else
+ puttuple(&PS(node)->Tuples, tup, 0, &PS(node)->treeContext);
}
- else {
- tup = tuplecopy(cr_slot->val);
- ExecClearTuple(cr_slot);
- PS(node)->tupcount++;
- cr_tuples++;
+ if (lasttuple != NULL)
+ {
+ FREEMEM(node, lasttuple->t_len);
+ FREE(lasttuple);
+ TRACEMEM(createrun);
}
+ dumptuples(file, node);
+ if (PS(node)->using_tape_files)
+ ENDRUN(file);
+ /* delimit the end of the run */
+ PS(node)->Tuples = nextrun;
- IncrProcessed();
- USEMEM(node,tup->t_len);
- TRACEMEM(createrun);
- if (lasttuple != NULL && tuplecmp(tup, lasttuple,
- &PS(node)->treeContext))
- puttuple(&nextrun, tup, 0, &PS(node)->treeContext);
- else
- puttuple(&PS(node)->Tuples, tup, 0, &PS(node)->treeContext);
- }
- if (lasttuple != NULL) {
- FREEMEM(node,lasttuple->t_len);
- FREE(lasttuple);
- TRACEMEM(createrun);
- }
- dumptuples(file, node);
- if (PS(node)->using_tape_files)
- ENDRUN(file);
- /* delimit the end of the run */
- PS(node)->Tuples = nextrun;
-
- /* if we did not see any tuples, mark empty */
- *empty = (cr_tuples > 0) ? false : true;
-
- return((bool)! foundeor); /* XXX - works iff bool is {0,1} */
+ /* if we did not see any tuples, mark empty */
+ *empty = (cr_tuples > 0) ? false : true;
+
+ return ((bool) ! foundeor); /* XXX - works iff bool is {0,1} */
}
/*
- * tuplecopy - see also tuple.c:palloctup()
+ * tuplecopy - see also tuple.c:palloctup()
*
- * This should eventually go there under that name? And this will
- * then use palloc directly (see version -r1.2).
+ * This should eventually go there under that name? And this will
+ * then use palloc directly (see version -r1.2).
*/
-static HeapTuple
+static HeapTuple
tuplecopy(HeapTuple tup)
{
- HeapTuple rettup;
-
- if (!HeapTupleIsValid(tup)) {
- return(NULL); /* just in case */
- }
- rettup = (HeapTuple)palloc(tup->t_len);
- memmove((char *)rettup, (char *)tup, tup->t_len); /* XXX */
- return(rettup);
+ HeapTuple rettup;
+
+ if (!HeapTupleIsValid(tup))
+ {
+ return (NULL); /* just in case */
+ }
+ rettup = (HeapTuple) palloc(tup->t_len);
+ memmove((char *) rettup, (char *) tup, tup->t_len); /* XXX */
+ return (rettup);
}
/*
- * mergeruns - merges all runs from input tapes
- * (polyphase merge Alg.D(D6)--Knuth, Vol.3, p271)
+ * mergeruns - merges all runs from input tapes
+ * (polyphase merge Alg.D(D6)--Knuth, Vol.3, p271)
*
- * Returns:
- * file of tuples in order
+ * Returns:
+ * file of tuples in order
*/
-static FILE *
-mergeruns(Sort *node)
+static FILE *
+mergeruns(Sort * node)
{
- register struct tape *tp;
+ register struct tape *tp;
- Assert(node != (Sort *) NULL);
- Assert(PS(node) != (Psortstate *) NULL);
- Assert(PS(node)->using_tape_files == true);
+ Assert(node != (Sort *) NULL);
+ Assert(PS(node) != (Psortstate *) NULL);
+ Assert(PS(node)->using_tape_files == true);
- tp = PS(node)->Tape + PS(node)->TapeRange;
- merge(node, tp);
- rewind(tp->tp_file);
- while (--PS(node)->Level != 0) {
- tp = tp->tp_prev;
- rewind(tp->tp_file);
- /* resettape(tp->tp_file); -not sufficient */
+ tp = PS(node)->Tape + PS(node)->TapeRange;
merge(node, tp);
rewind(tp->tp_file);
- }
- return(tp->tp_file);
+ while (--PS(node)->Level != 0)
+ {
+ tp = tp->tp_prev;
+ rewind(tp->tp_file);
+ /* resettape(tp->tp_file); -not sufficient */
+ merge(node, tp);
+ rewind(tp->tp_file);
+ }
+ return (tp->tp_file);
}
/*
- * merge - handles a single merge of the tape
- * (polyphase merge Alg.D(D5)--Knuth, Vol.3, p271)
+ * merge - handles a single merge of the tape
+ * (polyphase merge Alg.D(D5)--Knuth, Vol.3, p271)
*/
static void
-merge(Sort *node, struct tape *dest)
+merge(Sort * node, struct tape * dest)
{
- register HeapTuple tup;
- register struct tape *lasttp; /* (TAPE[P]) */
- register struct tape *tp;
- struct leftist *tuples;
- FILE *destfile;
- int times; /* runs left to merge */
- int outdummy; /* complete dummy runs */
- short fromtape;
- long tuplen;
-
- Assert(node != (Sort *) NULL);
- Assert(PS(node) != (Psortstate *) NULL);
- Assert(PS(node)->using_tape_files == true);
-
- lasttp = dest->tp_prev;
- times = lasttp->tp_fib;
- for (tp = lasttp ; tp != dest; tp = tp->tp_prev)
- tp->tp_fib -= times;
- tp->tp_fib += times;
- /* Tape[].tp_fib (A[]) is set to proper exit values */
-
- if (PS(node)->TotalDummy < PS(node)->TapeRange)/* no complete dummy runs */
- outdummy = 0;
- else {
- outdummy = PS(node)->TotalDummy; /* a large positive number */
- for (tp = lasttp; tp != dest; tp = tp->tp_prev)
- if (outdummy > tp->tp_dummy)
- outdummy = tp->tp_dummy;
+ register HeapTuple tup;
+ register struct tape *lasttp; /* (TAPE[P]) */
+ register struct tape *tp;
+ struct leftist *tuples;
+ FILE *destfile;
+ int times; /* runs left to merge */
+ int outdummy; /* complete dummy runs */
+ short fromtape;
+ long tuplen;
+
+ Assert(node != (Sort *) NULL);
+ Assert(PS(node) != (Psortstate *) NULL);
+ Assert(PS(node)->using_tape_files == true);
+
+ lasttp = dest->tp_prev;
+ times = lasttp->tp_fib;
for (tp = lasttp; tp != dest; tp = tp->tp_prev)
- tp->tp_dummy -= outdummy;
- tp->tp_dummy += outdummy;
- PS(node)->TotalDummy -= outdummy * PS(node)->TapeRange;
- /* do not add the outdummy runs yet */
- times -= outdummy;
- }
- destfile = dest->tp_file;
- while (times-- != 0) { /* merge one run */
- tuples = NULL;
- if (PS(node)->TotalDummy == 0)
- for (tp = dest->tp_prev; tp != dest; tp = tp->tp_prev) {
- GETLEN(tuplen, tp->tp_file);
- tup = ALLOCTUP(tuplen);
- USEMEM(node,tuplen);
- TRACEMEM(merge);
- SETTUPLEN(tup, tuplen);
- GETTUP(node, tup, tuplen, tp->tp_file);
- puttuple(&tuples, tup, tp - PS(node)->Tape,
- &PS(node)->treeContext);
- }
- else {
- for (tp = dest->tp_prev; tp != dest; tp = tp->tp_prev) {
- if (tp->tp_dummy != 0) {
- tp->tp_dummy--;
- PS(node)->TotalDummy--;
- } else {
- GETLEN(tuplen, tp->tp_file);
- tup = ALLOCTUP(tuplen);
- USEMEM(node,tuplen);
- TRACEMEM(merge);
- SETTUPLEN(tup, tuplen);
- GETTUP(node, tup, tuplen, tp->tp_file);
- puttuple(&tuples, tup, tp - PS(node)->Tape,
- &PS(node)->treeContext);
+ tp->tp_fib -= times;
+ tp->tp_fib += times;
+ /* Tape[].tp_fib (A[]) is set to proper exit values */
+
+ if (PS(node)->TotalDummy < PS(node)->TapeRange) /* no complete dummy
+ * runs */
+ outdummy = 0;
+ else
+ {
+ outdummy = PS(node)->TotalDummy; /* a large positive number */
+ for (tp = lasttp; tp != dest; tp = tp->tp_prev)
+ if (outdummy > tp->tp_dummy)
+ outdummy = tp->tp_dummy;
+ for (tp = lasttp; tp != dest; tp = tp->tp_prev)
+ tp->tp_dummy -= outdummy;
+ tp->tp_dummy += outdummy;
+ PS(node)->TotalDummy -= outdummy * PS(node)->TapeRange;
+ /* do not add the outdummy runs yet */
+ times -= outdummy;
+ }
+ destfile = dest->tp_file;
+ while (times-- != 0)
+ { /* merge one run */
+ tuples = NULL;
+ if (PS(node)->TotalDummy == 0)
+ for (tp = dest->tp_prev; tp != dest; tp = tp->tp_prev)
+ {
+ GETLEN(tuplen, tp->tp_file);
+ tup = ALLOCTUP(tuplen);
+ USEMEM(node, tuplen);
+ TRACEMEM(merge);
+ SETTUPLEN(tup, tuplen);
+ GETTUP(node, tup, tuplen, tp->tp_file);
+ puttuple(&tuples, tup, tp - PS(node)->Tape,
+ &PS(node)->treeContext);
+ }
+ else
+ {
+ for (tp = dest->tp_prev; tp != dest; tp = tp->tp_prev)
+ {
+ if (tp->tp_dummy != 0)
+ {
+ tp->tp_dummy--;
+ PS(node)->TotalDummy--;
+ }
+ else
+ {
+ GETLEN(tuplen, tp->tp_file);
+ tup = ALLOCTUP(tuplen);
+ USEMEM(node, tuplen);
+ TRACEMEM(merge);
+ SETTUPLEN(tup, tuplen);
+ GETTUP(node, tup, tuplen, tp->tp_file);
+ puttuple(&tuples, tup, tp - PS(node)->Tape,
+ &PS(node)->treeContext);
+ }
+ }
+ }
+ while (tuples != NULL)
+ {
+ /* possible optimization by using count in tuples */
+ tup = gettuple(&tuples, &fromtape, &PS(node)->treeContext);
+ PUTTUP(node, tup, destfile);
+ FREEMEM(node, tup->t_len);
+ FREE(tup);
+ TRACEMEM(merge);
+ GETLEN(tuplen, PS(node)->Tape[fromtape].tp_file);
+ if (tuplen == 0)
+ ;
+ else
+ {
+ tup = ALLOCTUP(tuplen);
+ USEMEM(node, tuplen);
+ TRACEMEM(merge);
+ SETTUPLEN(tup, tuplen);
+ GETTUP(node, tup, tuplen, PS(node)->Tape[fromtape].tp_file);
+ puttuple(&tuples, tup, fromtape, &PS(node)->treeContext);
+ }
}
- }
+ ENDRUN(destfile);
}
- while (tuples != NULL) {
- /* possible optimization by using count in tuples */
- tup = gettuple(&tuples, &fromtape, &PS(node)->treeContext);
- PUTTUP(node, tup, destfile);
- FREEMEM(node,tup->t_len);
- FREE(tup);
- TRACEMEM(merge);
- GETLEN(tuplen, PS(node)->Tape[fromtape].tp_file);
- if (tuplen == 0)
- ;
- else {
- tup = ALLOCTUP(tuplen);
- USEMEM(node,tuplen);
- TRACEMEM(merge);
- SETTUPLEN(tup, tuplen);
- GETTUP(node, tup, tuplen, PS(node)->Tape[fromtape].tp_file);
- puttuple(&tuples, tup, fromtape, &PS(node)->treeContext);
- }
- }
- ENDRUN(destfile);
- }
- PS(node)->TotalDummy += outdummy;
+ PS(node)->TotalDummy += outdummy;
}
/*
* dumptuples - stores all the tuples in tree into file
*/
static void
-dumptuples(FILE *file, Sort *node)
+dumptuples(FILE * file, Sort * node)
{
- register struct leftist *tp;
- register struct leftist *newp;
- struct leftist **treep = &PS(node)->Tuples;
- LeftistContext context = &PS(node)->treeContext;
- HeapTuple tup;
- int memtupindex = 0;
-
- if (! PS(node)->using_tape_files && PS(node)->tupcount) {
- Assert(PS(node)->memtuples == NULL);
- PS(node)->memtuples = palloc(PS(node)->tupcount * sizeof(HeapTuple));
- }
-
- tp = *treep;
- while (tp != NULL) {
- tup = tp->lt_tuple;
- if (tp->lt_dist == 1) /* lt_right == NULL */
- newp = tp->lt_left;
- else
- newp = lmerge(tp->lt_left, tp->lt_right, context);
- FREEMEM(node,sizeof (struct leftist));
- FREE(tp);
- if (PS(node)->using_tape_files) {
- PUTTUP(node, tup, file);
- FREEMEM(node,tup->t_len);
- FREE(tup);
+ register struct leftist *tp;
+ register struct leftist *newp;
+ struct leftist **treep = &PS(node)->Tuples;
+ LeftistContext context = &PS(node)->treeContext;
+ HeapTuple tup;
+ int memtupindex = 0;
+
+ if (!PS(node)->using_tape_files && PS(node)->tupcount)
+ {
+ Assert(PS(node)->memtuples == NULL);
+ PS(node)->memtuples = palloc(PS(node)->tupcount * sizeof(HeapTuple));
}
- else
- PS(node)->memtuples[memtupindex++] = tup;
- tp = newp;
- }
- *treep = NULL;
+ tp = *treep;
+ while (tp != NULL)
+ {
+ tup = tp->lt_tuple;
+ if (tp->lt_dist == 1) /* lt_right == NULL */
+ newp = tp->lt_left;
+ else
+ newp = lmerge(tp->lt_left, tp->lt_right, context);
+ FREEMEM(node, sizeof(struct leftist));
+ FREE(tp);
+ if (PS(node)->using_tape_files)
+ {
+ PUTTUP(node, tup, file);
+ FREEMEM(node, tup->t_len);
+ FREE(tup);
+ }
+ else
+ PS(node)->memtuples[memtupindex++] = tup;
+
+ tp = newp;
+ }
+ *treep = NULL;
}
/*
- * psort_grabtuple - gets a tuple from the sorted file and returns it.
- * If there are no tuples left, returns NULL.
- * Should not call psort_end unless this has returned
- * a NULL indicating the last tuple has been processed.
+ * psort_grabtuple - gets a tuple from the sorted file and returns it.
+ * If there are no tuples left, returns NULL.
+ * Should not call psort_end unless this has returned
+ * a NULL indicating the last tuple has been processed.
*/
HeapTuple
-psort_grabtuple(Sort *node)
+psort_grabtuple(Sort * node)
{
- register HeapTuple tup;
- long tuplen;
-
- Assert(node != (Sort *) NULL);
- Assert(PS(node) != (Psortstate *) NULL);
-
- if (PS(node)->using_tape_files == true) {
- if (!feof(PS(node)->psort_grab_file)) {
- if (GETLEN(tuplen, PS(node)->psort_grab_file) && tuplen != 0) {
- tup = (HeapTuple)palloc((unsigned)tuplen);
- SETTUPLEN(tup, tuplen);
- GETTUP(node, tup, tuplen, PS(node)->psort_grab_file);
-
- /* Update current merged sort file position */
- PS(node)->psort_current += tuplen;
-
- return tup;
- }
- else
- return NULL;
- }
- else
- return NULL;
- }
- else {
- if (PS(node)->psort_current < PS(node)->tupcount)
- return PS(node)->memtuples[PS(node)->psort_current++];
- else
- return NULL;
- }
+ register HeapTuple tup;
+ long tuplen;
+
+ Assert(node != (Sort *) NULL);
+ Assert(PS(node) != (Psortstate *) NULL);
+
+ if (PS(node)->using_tape_files == true)
+ {
+ if (!feof(PS(node)->psort_grab_file))
+ {
+ if (GETLEN(tuplen, PS(node)->psort_grab_file) && tuplen != 0)
+ {
+ tup = (HeapTuple) palloc((unsigned) tuplen);
+ SETTUPLEN(tup, tuplen);
+ GETTUP(node, tup, tuplen, PS(node)->psort_grab_file);
+
+ /* Update current merged sort file position */
+ PS(node)->psort_current += tuplen;
+
+ return tup;
+ }
+ else
+ return NULL;
+ }
+ else
+ return NULL;
+ }
+ else
+ {
+ if (PS(node)->psort_current < PS(node)->tupcount)
+ return PS(node)->memtuples[PS(node)->psort_current++];
+ else
+ return NULL;
+ }
}
/*
- * psort_markpos - saves current position in the merged sort file
+ * psort_markpos - saves current position in the merged sort file
*/
void
-psort_markpos(Sort *node)
+psort_markpos(Sort * node)
{
- Assert(node != (Sort *) NULL);
- Assert(PS(node) != (Psortstate *) NULL);
+ Assert(node != (Sort *) NULL);
+ Assert(PS(node) != (Psortstate *) NULL);
- PS(node)->psort_saved = PS(node)->psort_current;
+ PS(node)->psort_saved = PS(node)->psort_current;
}
/*
- * psort_restorepos- restores current position in merged sort file to
- * last saved position
+ * psort_restorepos- restores current position in merged sort file to
+ * last saved position
*/
void
-psort_restorepos(Sort *node)
+psort_restorepos(Sort * node)
{
- Assert(node != (Sort *) NULL);
- Assert(PS(node) != (Psortstate *) NULL);
+ Assert(node != (Sort *) NULL);
+ Assert(PS(node) != (Psortstate *) NULL);
- if (PS(node)->using_tape_files == true)
- fseek(PS(node)->psort_grab_file, PS(node)->psort_saved, SEEK_SET);
- PS(node)->psort_current = PS(node)->psort_saved;
+ if (PS(node)->using_tape_files == true)
+ fseek(PS(node)->psort_grab_file, PS(node)->psort_saved, SEEK_SET);
+ PS(node)->psort_current = PS(node)->psort_saved;
}
/*
- * psort_end - unlinks the tape files, and cleans up. Should not be
- * called unless psort_grabtuple has returned a NULL.
+ * psort_end - unlinks the tape files, and cleans up. Should not be
+ * called unless psort_grabtuple has returned a NULL.
*/
void
-psort_end(Sort *node)
+psort_end(Sort * node)
{
- register struct tape *tp;
-
- if (!node->cleaned) {
- Assert(node != (Sort *) NULL);
-/* Assert(PS(node) != (Psortstate *) NULL); */
-
- /*
- * I'm changing this because if we are sorting a relation
- * with no tuples, psortstate is NULL.
- */
- if (PS(node) != (Psortstate *) NULL) {
- if (PS(node)->using_tape_files == true)
- for (tp = PS(node)->Tape + PS(node)->TapeRange; tp >= PS(node)->Tape; tp--)
- destroytape(tp->tp_file);
- else if (PS(node)->memtuples)
- pfree(PS(node)->memtuples);
-
- NDirectFileRead +=
- (int)ceil((double)PS(node)->BytesRead / BLCKSZ);
- NDirectFileWrite +=
- (int)ceil((double)PS(node)->BytesWritten / BLCKSZ);
-
- pfree((void *)node->psortstate);
-
- node->cleaned = TRUE;
+ register struct tape *tp;
+
+ if (!node->cleaned)
+ {
+ Assert(node != (Sort *) NULL);
+/* Assert(PS(node) != (Psortstate *) NULL); */
+
+ /*
+ * I'm changing this because if we are sorting a relation with no
+ * tuples, psortstate is NULL.
+ */
+ if (PS(node) != (Psortstate *) NULL)
+ {
+ if (PS(node)->using_tape_files == true)
+ for (tp = PS(node)->Tape + PS(node)->TapeRange; tp >= PS(node)->Tape; tp--)
+ destroytape(tp->tp_file);
+ else if (PS(node)->memtuples)
+ pfree(PS(node)->memtuples);
+
+ NDirectFileRead +=
+ (int) ceil((double) PS(node)->BytesRead / BLCKSZ);
+ NDirectFileWrite +=
+ (int) ceil((double) PS(node)->BytesWritten / BLCKSZ);
+
+ pfree((void *) node->psortstate);
+
+ node->cleaned = TRUE;
+ }
}
- }
}
/*
- * gettape - handles access temporary files in polyphase merging
+ * gettape - handles access temporary files in polyphase merging
*
- * Optimizations:
- * If guarenteed that only one sort running/process,
- * can simplify the file generation--and need not store the
- * name for later unlink.
+ * Optimizations:
+ * If guarenteed that only one sort running/process,
+ * can simplify the file generation--and need not store the
+ * name for later unlink.
*/
-struct tapelst {
- char *tl_name;
- int tl_fd;
- struct tapelst *tl_next;
+struct tapelst
+{
+ char *tl_name;
+ int tl_fd;
+ struct tapelst *tl_next;
};
-static struct tapelst *Tapes = NULL;
+static struct tapelst *Tapes = NULL;
/*
- * gettape - returns an open stream for writing/reading
+ * gettape - returns an open stream for writing/reading
*
- * Returns:
- * Open stream for writing/reading.
- * NULL if unable to open temporary file.
+ * Returns:
+ * Open stream for writing/reading.
+ * NULL if unable to open temporary file.
*/
-static FILE *
+static FILE *
gettape()
{
- register struct tapelst *tp;
- FILE *file;
- static int tapeinit = 0;
- char *mktemp();
- static unsigned int uniqueFileId = 0;
- extern int errno;
- char uniqueName[MAXPGPATH];
-
- tp = (struct tapelst *)palloc((unsigned)sizeof (struct tapelst));
-
- sprintf(uniqueName, "%spg_psort.%d.%d", TEMPDIR, (int)getpid(), uniqueFileId);
- uniqueFileId++;
-
- tapeinit = 1;
-
- tp->tl_name = palloc((unsigned)sizeof(uniqueName));
-
- /*
- * now, copy template with final null into palloc'd space
- */
-
- memmove(tp->tl_name, uniqueName, strlen(uniqueName));
-
-
- file = AllocateFile(tp->tl_name, "w+");
- if (file == NULL)
- elog(WARN,"Open: %s in %s line %d, %s", tp->tl_name,
- __FILE__, __LINE__, strerror(errno));
-
- tp->tl_fd = fileno(file);
- tp->tl_next = Tapes;
- Tapes = tp;
- return(file);
+ register struct tapelst *tp;
+ FILE *file;
+ static int tapeinit = 0;
+ char *mktemp();
+ static unsigned int uniqueFileId = 0;
+ extern int errno;
+ char uniqueName[MAXPGPATH];
+
+ tp = (struct tapelst *) palloc((unsigned) sizeof(struct tapelst));
+
+ sprintf(uniqueName, "%spg_psort.%d.%d", TEMPDIR, (int) getpid(), uniqueFileId);
+ uniqueFileId++;
+
+ tapeinit = 1;
+
+ tp->tl_name = palloc((unsigned) sizeof(uniqueName));
+
+ /*
+ * now, copy template with final null into palloc'd space
+ */
+
+ memmove(tp->tl_name, uniqueName, strlen(uniqueName));
+
+
+ file = AllocateFile(tp->tl_name, "w+");
+ if (file == NULL)
+ elog(WARN, "Open: %s in %s line %d, %s", tp->tl_name,
+ __FILE__, __LINE__, strerror(errno));
+
+ tp->tl_fd = fileno(file);
+ tp->tl_next = Tapes;
+ Tapes = tp;
+ return (file);
}
/*
- * resettape - resets the tape to size 0
+ * resettape - resets the tape to size 0
*/
#ifdef NOT_USED
static void
-resettape(FILE *file)
+resettape(FILE * file)
{
- register struct tapelst *tp;
- register int fd;
-
- Assert(PointerIsValid(file));
-
- fd = fileno(file);
- for (tp = Tapes; tp != NULL && tp->tl_fd != fd; tp = tp->tl_next)
- ;
- if (tp == NULL)
- elog(WARN, "resettape: tape not found");
-
- file = freopen(tp->tl_name, "w+", file);
- if (file == NULL) {
- elog(FATAL, "could not freopen temporary file");
- }
+ register struct tapelst *tp;
+ register int fd;
+
+ Assert(PointerIsValid(file));
+
+ fd = fileno(file);
+ for (tp = Tapes; tp != NULL && tp->tl_fd != fd; tp = tp->tl_next)
+ ;
+ if (tp == NULL)
+ elog(WARN, "resettape: tape not found");
+
+ file = freopen(tp->tl_name, "w+", file);
+ if (file == NULL)
+ {
+ elog(FATAL, "could not freopen temporary file");
+ }
}
+
#endif
/*
- * distroytape - unlinks the tape
+ * distroytape - unlinks the tape
*
- * Efficiency note:
- * More efficient to destroy more recently allocated tapes first.
+ * Efficiency note:
+ * More efficient to destroy more recently allocated tapes first.
*
- * Possible bugs:
- * Exits instead of returning status, if given invalid tape.
+ * Possible bugs:
+ * Exits instead of returning status, if given invalid tape.
*/
static void
-destroytape(FILE *file)
+destroytape(FILE * file)
{
- register struct tapelst *tp, *tq;
- register int fd;
-
- if ((tp = Tapes) == NULL)
- elog(FATAL, "destroytape: tape not found");
-
- if ((fd = fileno(file)) == tp->tl_fd) {
- Tapes = tp->tl_next;
- FreeFile(file);
- unlink(tp->tl_name);
- FREE(tp->tl_name);
- FREE(tp);
- } else
- for ( ; ; ) {
- if (tp->tl_next == NULL)
+ register struct tapelst *tp,
+ *tq;
+ register int fd;
+
+ if ((tp = Tapes) == NULL)
elog(FATAL, "destroytape: tape not found");
- if (tp->tl_next->tl_fd == fd) {
+
+ if ((fd = fileno(file)) == tp->tl_fd)
+ {
+ Tapes = tp->tl_next;
FreeFile(file);
- tq = tp->tl_next;
- tp->tl_next = tq->tl_next;
- unlink(tq->tl_name);
- FREE((tq->tl_name));
- FREE(tq);
- break;
- }
- tp = tp->tl_next;
+ unlink(tp->tl_name);
+ FREE(tp->tl_name);
+ FREE(tp);
}
+ else
+ for (;;)
+ {
+ if (tp->tl_next == NULL)
+ elog(FATAL, "destroytape: tape not found");
+ if (tp->tl_next->tl_fd == fd)
+ {
+ FreeFile(file);
+ tq = tp->tl_next;
+ tp->tl_next = tq->tl_next;
+ unlink(tq->tl_name);
+ FREE((tq->tl_name));
+ FREE(tq);
+ break;
+ }
+ tp = tp->tl_next;
+ }
}
diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
index 1fcf3679fe4..2a85ecd712b 100644
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* tqual.c--
- * POSTGRES time qualification code.
+ * POSTGRES time qualification code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.4 1997/08/29 09:04:54 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.5 1997/09/07 04:54:20 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,23 +29,23 @@
static AbsoluteTime TimeQualGetEndTime(TimeQual qual);
static AbsoluteTime TimeQualGetSnapshotTime(TimeQual qual);
static AbsoluteTime TimeQualGetStartTime(TimeQual qual);
-static bool TimeQualIncludesNow(TimeQual qual);
-static bool TimeQualIndicatesDisableValidityChecking(TimeQual qual);
-static bool TimeQualIsLegal(TimeQual qual);
-static bool TimeQualIsRanged(TimeQual qual);
-static bool TimeQualIsSnapshot(TimeQual qual);
-static bool TimeQualIsValid(TimeQual qual);
+static bool TimeQualIncludesNow(TimeQual qual);
+static bool TimeQualIndicatesDisableValidityChecking(TimeQual qual);
+static bool TimeQualIsLegal(TimeQual qual);
+static bool TimeQualIsRanged(TimeQual qual);
+static bool TimeQualIsSnapshot(TimeQual qual);
+static bool TimeQualIsValid(TimeQual qual);
/*
* TimeQualMode --
- * Mode indicator for treatment of time qualifications.
+ * Mode indicator for treatment of time qualifications.
*/
typedef uint16 TimeQualMode;
-#define TimeQualAt 0x1
+#define TimeQualAt 0x1
#define TimeQualNewer 0x2
#define TimeQualOlder 0x4
-#define TimeQualAll 0x8
+#define TimeQualAll 0x8
#define TimeQualMask 0xf
@@ -53,820 +53,903 @@ typedef uint16 TimeQualMode;
#define TimeQualRange (TimeQualNewer | TimeQualOlder)
#define TimeQualAllAt (TimeQualAt | TimeQualAll)
-typedef struct TimeQualData {
- AbsoluteTime start;
- AbsoluteTime end;
- TimeQualMode mode;
-} TimeQualData;
+typedef struct TimeQualData
+{
+ AbsoluteTime start;
+ AbsoluteTime end;
+ TimeQualMode mode;
+} TimeQualData;
-typedef TimeQualData *InternalTimeQual;
+typedef TimeQualData *InternalTimeQual;
-static TimeQualData SelfTimeQualData;
-TimeQual SelfTimeQual = (Pointer)&SelfTimeQualData;
+static TimeQualData SelfTimeQualData;
+TimeQual SelfTimeQual = (Pointer) & SelfTimeQualData;
extern bool PostgresIsInitialized;
/*
* XXX Transaction system override hacks start here
*/
-#ifndef GOODAMI
+#ifndef GOODAMI
-static TransactionId HeapSpecialTransactionId = InvalidTransactionId;
-static CommandId HeapSpecialCommandId = FirstCommandId;
+static TransactionId HeapSpecialTransactionId = InvalidTransactionId;
+static CommandId HeapSpecialCommandId = FirstCommandId;
void
setheapoverride(bool on)
{
- if (on) {
- TransactionIdStore(GetCurrentTransactionId(),
- &HeapSpecialTransactionId);
- HeapSpecialCommandId = GetCurrentCommandId();
- } else {
- HeapSpecialTransactionId = InvalidTransactionId;
- }
+ if (on)
+ {
+ TransactionIdStore(GetCurrentTransactionId(),
+ &HeapSpecialTransactionId);
+ HeapSpecialCommandId = GetCurrentCommandId();
+ }
+ else
+ {
+ HeapSpecialTransactionId = InvalidTransactionId;
+ }
}
/* static */
bool
heapisoverride()
{
- if (!TransactionIdIsValid(HeapSpecialTransactionId)) {
- return (false);
- }
-
- if (!TransactionIdEquals(GetCurrentTransactionId(),
- HeapSpecialTransactionId) ||
- GetCurrentCommandId() != HeapSpecialCommandId) {
- HeapSpecialTransactionId = InvalidTransactionId;
-
- return (false);
- }
- return (true);
+ if (!TransactionIdIsValid(HeapSpecialTransactionId))
+ {
+ return (false);
+ }
+
+ if (!TransactionIdEquals(GetCurrentTransactionId(),
+ HeapSpecialTransactionId) ||
+ GetCurrentCommandId() != HeapSpecialCommandId)
+ {
+ HeapSpecialTransactionId = InvalidTransactionId;
+
+ return (false);
+ }
+ return (true);
}
-#endif /* !defined(GOODAMI) */
+#endif /* !defined(GOODAMI) */
/*
* XXX Transaction system override hacks end here
*/
-static bool HeapTupleSatisfiesItself(HeapTuple tuple);
-static bool HeapTupleSatisfiesNow(HeapTuple tuple);
-static bool HeapTupleSatisfiesSnapshotInternalTimeQual(HeapTuple tuple,
- InternalTimeQual qual);
-static bool HeapTupleSatisfiesUpperBoundedInternalTimeQual(HeapTuple tuple,
- InternalTimeQual qual);
-static bool HeapTupleSatisfiesUpperUnboundedInternalTimeQual(HeapTuple tuple,
- InternalTimeQual qual);
+static bool HeapTupleSatisfiesItself(HeapTuple tuple);
+static bool HeapTupleSatisfiesNow(HeapTuple tuple);
+static bool
+HeapTupleSatisfiesSnapshotInternalTimeQual(HeapTuple tuple,
+ InternalTimeQual qual);
+static bool
+HeapTupleSatisfiesUpperBoundedInternalTimeQual(HeapTuple tuple,
+ InternalTimeQual qual);
+static bool
+HeapTupleSatisfiesUpperUnboundedInternalTimeQual(HeapTuple tuple,
+ InternalTimeQual qual);
+
-
/*
* TimeQualIsValid --
- * True iff time qualification is valid.
+ * True iff time qualification is valid.
*/
-static bool
+static bool
TimeQualIsValid(TimeQual qual)
{
- bool hasStartTime;
-
- if (!PointerIsValid(qual) || qual == SelfTimeQual) {
+ bool hasStartTime;
+
+ if (!PointerIsValid(qual) || qual == SelfTimeQual)
+ {
+ return (true);
+ }
+
+ if (((InternalTimeQual) qual)->mode & ~TimeQualMask)
+ {
+ return (false);
+ }
+
+ if (((InternalTimeQual) qual)->mode & TimeQualAt)
+ {
+ return (AbsoluteTimeIsBackwardCompatiblyValid(((InternalTimeQual) qual)->start));
+ }
+
+ hasStartTime = false;
+
+ if (((InternalTimeQual) qual)->mode & TimeQualNewer)
+ {
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(((InternalTimeQual) qual)->start))
+ {
+ return (false);
+ }
+ hasStartTime = true;
+ }
+
+ if (((InternalTimeQual) qual)->mode & TimeQualOlder)
+ {
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(((InternalTimeQual) qual)->end))
+ {
+ return (false);
+ }
+ if (hasStartTime)
+ {
+ return ((bool) ! AbsoluteTimeIsBefore(
+ ((InternalTimeQual) qual)->end,
+ ((InternalTimeQual) qual)->start));
+ }
+ }
return (true);
- }
-
- if (((InternalTimeQual)qual)->mode & ~TimeQualMask) {
- return (false);
- }
-
- if (((InternalTimeQual)qual)->mode & TimeQualAt) {
- return (AbsoluteTimeIsBackwardCompatiblyValid(((InternalTimeQual)qual)->start));
- }
-
- hasStartTime = false;
-
- if (((InternalTimeQual)qual)->mode & TimeQualNewer) {
- if (!AbsoluteTimeIsBackwardCompatiblyValid(((InternalTimeQual)qual)->start)) {
- return (false);
- }
- hasStartTime = true;
- }
-
- if (((InternalTimeQual)qual)->mode & TimeQualOlder) {
- if (!AbsoluteTimeIsBackwardCompatiblyValid(((InternalTimeQual)qual)->end)) {
- return (false);
- }
- if (hasStartTime) {
- return ((bool)!AbsoluteTimeIsBefore(
- ((InternalTimeQual)qual)->end,
- ((InternalTimeQual)qual)->start));
- }
- }
- return (true);
}
/*
* TimeQualIsLegal --
- * True iff time qualification is legal.
- * I.e., true iff time qualification does not intersects the future,
- * relative to the transaction start time.
+ * True iff time qualification is legal.
+ * I.e., true iff time qualification does not intersects the future,
+ * relative to the transaction start time.
*
* Note:
- * Assumes time qualification is valid.
+ * Assumes time qualification is valid.
*/
-static bool
+static bool
TimeQualIsLegal(TimeQual qual)
{
- Assert(TimeQualIsValid(qual));
-
- if (qual == NowTimeQual || qual == SelfTimeQual) {
+ Assert(TimeQualIsValid(qual));
+
+ if (qual == NowTimeQual || qual == SelfTimeQual)
+ {
+ return (true);
+ }
+
+ /* TimeQualAt */
+ if (((InternalTimeQual) qual)->mode & TimeQualAt)
+ {
+ AbsoluteTime a,
+ b;
+
+ a = ((InternalTimeQual) qual)->start;
+ b = GetCurrentTransactionStartTime();
+
+ if (AbsoluteTimeIsAfter(a, b))
+ return (false);
+ else
+ return (true);
+ }
+
+ /* TimeQualOlder or TimeQualRange */
+ if (((InternalTimeQual) qual)->mode & TimeQualOlder)
+ {
+ AbsoluteTime a,
+ b;
+
+ a = ((InternalTimeQual) qual)->end;
+ b = GetCurrentTransactionStartTime();
+
+ if (AbsoluteTimeIsAfter(a, b))
+ return (false);
+ else
+ return (true);
+ }
+
+ /* TimeQualNewer */
+ if (((InternalTimeQual) qual)->mode & TimeQualNewer)
+ {
+ AbsoluteTime a,
+ b;
+
+ a = ((InternalTimeQual) qual)->start;
+ b = GetCurrentTransactionStartTime();
+
+ if (AbsoluteTimeIsAfter(a, b))
+ return (false);
+ else
+ return (true);
+ }
+
+ /* TimeQualEvery */
return (true);
- }
-
- /* TimeQualAt */
- if (((InternalTimeQual)qual)->mode & TimeQualAt) {
- AbsoluteTime a, b;
-
- a = ((InternalTimeQual)qual)->start;
- b = GetCurrentTransactionStartTime();
-
- if (AbsoluteTimeIsAfter(a, b))
- return (false);
- else
- return (true);
- }
-
- /* TimeQualOlder or TimeQualRange */
- if (((InternalTimeQual)qual)->mode & TimeQualOlder) {
- AbsoluteTime a, b;
-
- a = ((InternalTimeQual)qual)->end;
- b = GetCurrentTransactionStartTime();
-
- if (AbsoluteTimeIsAfter(a, b))
- return (false);
- else
- return (true);
- }
-
- /* TimeQualNewer */
- if (((InternalTimeQual)qual)->mode & TimeQualNewer) {
- AbsoluteTime a, b;
-
- a = ((InternalTimeQual)qual)->start;
- b = GetCurrentTransactionStartTime();
-
- if (AbsoluteTimeIsAfter(a, b))
- return (false);
- else
- return (true);
- }
-
- /* TimeQualEvery */
- return (true);
}
/*
* TimeQualIncludesNow --
- * True iff time qualification includes "now."
+ * True iff time qualification includes "now."
*
* Note:
- * Assumes time qualification is valid.
+ * Assumes time qualification is valid.
*/
-static bool
+static bool
TimeQualIncludesNow(TimeQual qual)
{
- Assert(TimeQualIsValid(qual));
-
- if (qual == NowTimeQual || qual == SelfTimeQual) {
+ Assert(TimeQualIsValid(qual));
+
+ if (qual == NowTimeQual || qual == SelfTimeQual)
+ {
+ return (true);
+ }
+
+ if (((InternalTimeQual) qual)->mode & TimeQualAt)
+ {
+ return (false);
+ }
+ if (((InternalTimeQual) qual)->mode & TimeQualOlder &&
+ !AbsoluteTimeIsAfter(
+ ((InternalTimeQual) qual)->end,
+ GetCurrentTransactionStartTime()))
+ {
+
+ return (false);
+ }
return (true);
- }
-
- if (((InternalTimeQual)qual)->mode & TimeQualAt) {
- return (false);
- }
- if (((InternalTimeQual)qual)->mode & TimeQualOlder &&
- !AbsoluteTimeIsAfter(
- ((InternalTimeQual)qual)->end,
- GetCurrentTransactionStartTime())) {
-
- return (false);
- }
- return (true);
}
/*
* TimeQualIncludesPast --
- * True iff time qualification includes some time in the past.
+ * True iff time qualification includes some time in the past.
*
* Note:
- * Assumes time qualification is valid.
- * XXX may not be needed?
+ * Assumes time qualification is valid.
+ * XXX may not be needed?
*/
#ifdef NOT_USED
bool
TimeQualIncludesPast(TimeQual qual)
{
- Assert(TimeQualIsValid(qual));
-
- if (qual == NowTimeQual || qual == SelfTimeQual) {
- return (false);
- }
-
- /* otherwise, must check archive (setting locks as appropriate) */
- return (true);
+ Assert(TimeQualIsValid(qual));
+
+ if (qual == NowTimeQual || qual == SelfTimeQual)
+ {
+ return (false);
+ }
+
+ /* otherwise, must check archive (setting locks as appropriate) */
+ return (true);
}
+
#endif
/*
* TimeQualIsSnapshot --
- * True iff time qualification is a snapshot qualification.
+ * True iff time qualification is a snapshot qualification.
*
* Note:
- * Assumes time qualification is valid.
+ * Assumes time qualification is valid.
*/
-static bool
+static bool
TimeQualIsSnapshot(TimeQual qual)
{
- Assert(TimeQualIsValid(qual));
-
- if (qual == NowTimeQual || qual == SelfTimeQual) {
- return (false);
- }
-
- return ((bool)!!(((InternalTimeQual)qual)->mode & TimeQualAt));
+ Assert(TimeQualIsValid(qual));
+
+ if (qual == NowTimeQual || qual == SelfTimeQual)
+ {
+ return (false);
+ }
+
+ return ((bool) ! !(((InternalTimeQual) qual)->mode & TimeQualAt));
}
/*
* TimeQualIsRanged --
- * True iff time qualification is a ranged qualification.
+ * True iff time qualification is a ranged qualification.
*
* Note:
- * Assumes time qualification is valid.
+ * Assumes time qualification is valid.
*/
-static bool
+static bool
TimeQualIsRanged(TimeQual qual)
{
- Assert(TimeQualIsValid(qual));
-
- if (qual == NowTimeQual || qual == SelfTimeQual) {
- return (false);
- }
-
- return ((bool)!(((InternalTimeQual)qual)->mode & TimeQualAt));
+ Assert(TimeQualIsValid(qual));
+
+ if (qual == NowTimeQual || qual == SelfTimeQual)
+ {
+ return (false);
+ }
+
+ return ((bool) ! (((InternalTimeQual) qual)->mode & TimeQualAt));
}
/*
* TimeQualIndicatesDisableValidityChecking --
- * True iff time qualification indicates validity checking should be
- * disabled.
+ * True iff time qualification indicates validity checking should be
+ * disabled.
*
* Note:
- * XXX This should not be implemented since this does not make sense.
+ * XXX This should not be implemented since this does not make sense.
*/
-static bool
+static bool
TimeQualIndicatesDisableValidityChecking(TimeQual qual)
{
- Assert (TimeQualIsValid(qual));
-
- if (qual == NowTimeQual || qual == SelfTimeQual) {
+ Assert(TimeQualIsValid(qual));
+
+ if (qual == NowTimeQual || qual == SelfTimeQual)
+ {
+ return (false);
+ }
+
+ if (((InternalTimeQual) qual)->mode & TimeQualAll)
+ {
+ return (true);
+ }
return (false);
- }
-
- if (((InternalTimeQual)qual)->mode & TimeQualAll) {
- return (true);
- }
- return (false);
}
/*
* TimeQualGetSnapshotTime --
- * Returns time for a snapshot time qual.
+ * Returns time for a snapshot time qual.
*
* Note:
- * Assumes time qual is valid snapshot time qual.
+ * Assumes time qual is valid snapshot time qual.
*/
-static AbsoluteTime
+static AbsoluteTime
TimeQualGetSnapshotTime(TimeQual qual)
{
- Assert(TimeQualIsSnapshot(qual));
-
- return (((InternalTimeQual)qual)->start);
+ Assert(TimeQualIsSnapshot(qual));
+
+ return (((InternalTimeQual) qual)->start);
}
/*
* TimeQualGetStartTime --
- * Returns start time for a ranged time qual.
+ * Returns start time for a ranged time qual.
*
* Note:
- * Assumes time qual is valid ranged time qual.
+ * Assumes time qual is valid ranged time qual.
*/
-static AbsoluteTime
+static AbsoluteTime
TimeQualGetStartTime(TimeQual qual)
{
- Assert(TimeQualIsRanged(qual));
-
- return (((InternalTimeQual)qual)->start);
+ Assert(TimeQualIsRanged(qual));
+
+ return (((InternalTimeQual) qual)->start);
}
/*
* TimeQualGetEndTime --
- * Returns end time for a ranged time qual.
+ * Returns end time for a ranged time qual.
*
* Note:
- * Assumes time qual is valid ranged time qual.
+ * Assumes time qual is valid ranged time qual.
*/
-static AbsoluteTime
+static AbsoluteTime
TimeQualGetEndTime(TimeQual qual)
{
- Assert(TimeQualIsRanged(qual));
-
- return (((InternalTimeQual)qual)->end);
+ Assert(TimeQualIsRanged(qual));
+
+ return (((InternalTimeQual) qual)->end);
}
/*
* TimeFormSnapshotTimeQual --
- * Returns snapshot time qual for a time.
+ * Returns snapshot time qual for a time.
*
* Note:
- * Assumes time is valid.
+ * Assumes time is valid.
*/
TimeQual
TimeFormSnapshotTimeQual(AbsoluteTime time)
{
- InternalTimeQual qual;
-
- Assert(AbsoluteTimeIsBackwardCompatiblyValid(time));
-
- qual = (InternalTimeQual)palloc(sizeof *qual);
-
- qual->start = time;
- qual->end = INVALID_ABSTIME;
- qual->mode = TimeQualAt;
-
- return ((TimeQual)qual);
+ InternalTimeQual qual;
+
+ Assert(AbsoluteTimeIsBackwardCompatiblyValid(time));
+
+ qual = (InternalTimeQual) palloc(sizeof *qual);
+
+ qual->start = time;
+ qual->end = INVALID_ABSTIME;
+ qual->mode = TimeQualAt;
+
+ return ((TimeQual) qual);
}
/*
* TimeFormRangedTimeQual --
- * Returns ranged time qual for a pair of times.
+ * Returns ranged time qual for a pair of times.
*
* Note:
- * If start time is invalid, it is regarded as the epoch.
- * If end time is invalid, it is regarded as "now."
- * Assumes start time is before (or the same as) end time.
+ * If start time is invalid, it is regarded as the epoch.
+ * If end time is invalid, it is regarded as "now."
+ * Assumes start time is before (or the same as) end time.
*/
TimeQual
TimeFormRangedTimeQual(AbsoluteTime startTime,
- AbsoluteTime endTime)
+ AbsoluteTime endTime)
{
- InternalTimeQual qual;
-
- qual = (InternalTimeQual)palloc(sizeof *qual);
-
- qual->start = startTime;
- qual->end = endTime;
- qual->mode = TimeQualEvery;
-
- if (AbsoluteTimeIsBackwardCompatiblyValid(startTime)) {
- qual->mode |= TimeQualNewer;
- }
- if (AbsoluteTimeIsBackwardCompatiblyValid(endTime)) {
- qual->mode |= TimeQualOlder;
- }
-
- return ((TimeQual)qual);
+ InternalTimeQual qual;
+
+ qual = (InternalTimeQual) palloc(sizeof *qual);
+
+ qual->start = startTime;
+ qual->end = endTime;
+ qual->mode = TimeQualEvery;
+
+ if (AbsoluteTimeIsBackwardCompatiblyValid(startTime))
+ {
+ qual->mode |= TimeQualNewer;
+ }
+ if (AbsoluteTimeIsBackwardCompatiblyValid(endTime))
+ {
+ qual->mode |= TimeQualOlder;
+ }
+
+ return ((TimeQual) qual);
}
/*
* HeapTupleSatisfiesTimeQual --
- * True iff heap tuple satsifies a time qual.
+ * True iff heap tuple satsifies a time qual.
*
* Note:
- * Assumes heap tuple is valid.
- * Assumes time qual is valid.
- * XXX Many of the checks may be simplified and still remain correct.
- * XXX Partial answers to the checks may be cached in an ItemId.
+ * Assumes heap tuple is valid.
+ * Assumes time qual is valid.
+ * XXX Many of the checks may be simplified and still remain correct.
+ * XXX Partial answers to the checks may be cached in an ItemId.
*/
bool
HeapTupleSatisfiesTimeQual(HeapTuple tuple, TimeQual qual)
{
-/* extern TransactionId AmiTransactionId; */
-
- Assert(HeapTupleIsValid(tuple));
- Assert(TimeQualIsValid(qual));
-
- if (TransactionIdEquals(tuple->t_xmax, AmiTransactionId))
- return(false);
-
- if (qual == SelfTimeQual || heapisoverride()) {
- return (HeapTupleSatisfiesItself(tuple));
- }
-
- if (qual == NowTimeQual) {
- return (HeapTupleSatisfiesNow(tuple));
- }
-
- if (!TimeQualIsLegal(qual)) {
- elog(WARN, "HeapTupleSatisfiesTimeQual: illegal time qual");
- }
-
- if (TimeQualIndicatesDisableValidityChecking(qual)) {
- elog(WARN, "HeapTupleSatisfiesTimeQual: no disabled validity checking (yet)");
- }
-
- if (TimeQualIsSnapshot(qual)) {
- return (HeapTupleSatisfiesSnapshotInternalTimeQual(tuple,
- (InternalTimeQual)qual));
- }
-
- if (TimeQualIncludesNow(qual)) {
- return (HeapTupleSatisfiesUpperUnboundedInternalTimeQual(tuple,
- (InternalTimeQual)qual));
- }
-
- return (HeapTupleSatisfiesUpperBoundedInternalTimeQual(tuple,
- (InternalTimeQual)qual));
+/* extern TransactionId AmiTransactionId; */
+
+ Assert(HeapTupleIsValid(tuple));
+ Assert(TimeQualIsValid(qual));
+
+ if (TransactionIdEquals(tuple->t_xmax, AmiTransactionId))
+ return (false);
+
+ if (qual == SelfTimeQual || heapisoverride())
+ {
+ return (HeapTupleSatisfiesItself(tuple));
+ }
+
+ if (qual == NowTimeQual)
+ {
+ return (HeapTupleSatisfiesNow(tuple));
+ }
+
+ if (!TimeQualIsLegal(qual))
+ {
+ elog(WARN, "HeapTupleSatisfiesTimeQual: illegal time qual");
+ }
+
+ if (TimeQualIndicatesDisableValidityChecking(qual))
+ {
+ elog(WARN, "HeapTupleSatisfiesTimeQual: no disabled validity checking (yet)");
+ }
+
+ if (TimeQualIsSnapshot(qual))
+ {
+ return (HeapTupleSatisfiesSnapshotInternalTimeQual(tuple,
+ (InternalTimeQual) qual));
+ }
+
+ if (TimeQualIncludesNow(qual))
+ {
+ return (HeapTupleSatisfiesUpperUnboundedInternalTimeQual(tuple,
+ (InternalTimeQual) qual));
+ }
+
+ return (HeapTupleSatisfiesUpperBoundedInternalTimeQual(tuple,
+ (InternalTimeQual) qual));
}
/*
* HeapTupleSatisfiesItself --
- * True iff heap tuple is valid for "itself."
- * "{it}self" means valid as of everything that's happened
- * in the current transaction, _including_ the current command.
+ * True iff heap tuple is valid for "itself."
+ * "{it}self" means valid as of everything that's happened
+ * in the current transaction, _including_ the current command.
*
* Note:
- * Assumes heap tuple is valid.
+ * Assumes heap tuple is valid.
*/
/*
* The satisfaction of "itself" requires the following:
*
- * ((Xmin == my-transaction && the row was updated by the current transaction, and
- * (Xmax is null it was not deleted
- * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
+ * ((Xmin == my-transaction && the row was updated by the current transaction, and
+ * (Xmax is null it was not deleted
+ * [|| Xmax != my-transaction)]) [or it was deleted by another transaction]
* ||
*
- * (Xmin is committed && the row was modified by a committed transaction, and
- * (Xmax is null || the row has not been deleted, or
- * (Xmax != my-transaction && the row was deleted by another transaction
- * Xmax is not committed))) that has not been committed
+ * (Xmin is committed && the row was modified by a committed transaction, and
+ * (Xmax is null || the row has not been deleted, or
+ * (Xmax != my-transaction && the row was deleted by another transaction
+ * Xmax is not committed))) that has not been committed
*/
-static bool
+static bool
HeapTupleSatisfiesItself(HeapTuple tuple)
{
- /*
- * XXX Several evil casts are made in this routine. Casting XID to be
- * TransactionId works only because TransactionId->data is the first
- * (and only) field of the structure.
- */
- if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin)) {
- if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmin) &&
- !TransactionIdIsValid((TransactionId)tuple->t_xmax)) {
- return (true);
- }
-
- if (!TransactionIdDidCommit((TransactionId)tuple->t_xmin)) {
- return (false);
- }
-
- tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
- }
- /* the tuple was inserted validly */
-
- if (AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax)) {
- return (false);
- }
-
- if (!TransactionIdIsValid((TransactionId)tuple->t_xmax)) {
- return (true);
- }
-
- if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmax)) {
- return (false);
- }
- if (!TransactionIdDidCommit((TransactionId)tuple->t_xmax)) {
- return (true);
- }
-
- /* by here, deleting transaction has committed */
- tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
+ /*
+ * XXX Several evil casts are made in this routine. Casting XID to be
+ * TransactionId works only because TransactionId->data is the first
+ * (and only) field of the structure.
+ */
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin))
+ {
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmin) &&
+ !TransactionIdIsValid((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
+
+ if (!TransactionIdDidCommit((TransactionId) tuple->t_xmin))
+ {
+ return (false);
+ }
+
+ tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
+ }
+ /* the tuple was inserted validly */
- return (false);
+ if (AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax))
+ {
+ return (false);
+ }
+
+ if (!TransactionIdIsValid((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
+
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmax))
+ {
+ return (false);
+ }
+
+ if (!TransactionIdDidCommit((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
+
+ /* by here, deleting transaction has committed */
+ tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
+
+ return (false);
}
/*
* HeapTupleSatisfiesNow --
- * True iff heap tuple is valid "now."
- * "now" means valid including everything that's happened
- * in the current transaction _up to, but not including,_
- * the current command.
+ * True iff heap tuple is valid "now."
+ * "now" means valid including everything that's happened
+ * in the current transaction _up to, but not including,_
+ * the current command.
*
* Note:
- * Assumes heap tuple is valid.
+ * Assumes heap tuple is valid.
*/
/*
* The satisfaction of "now" requires the following:
*
- * ((Xmin == my-transaction && changed by the current transaction
- * Cmin != my-command && but not by this command, and
- * (Xmax is null || the row has not been deleted, or
- * (Xmax == my-transaction && it was deleted by the current transaction
- * Cmax != my-command))) but not by this command,
- * || or
+ * ((Xmin == my-transaction && changed by the current transaction
+ * Cmin != my-command && but not by this command, and
+ * (Xmax is null || the row has not been deleted, or
+ * (Xmax == my-transaction && it was deleted by the current transaction
+ * Cmax != my-command))) but not by this command,
+ * || or
*
- * (Xmin is committed && the row was modified by a committed transaction, and
- * (Xmax is null || the row has not been deleted, or
- * (Xmax == my-transaction && the row is being deleted by this command, or
- * Cmax == my-command) ||
- * (Xmax is not committed && the row was deleted by another transaction
- * Xmax != my-transaction)))) that has not been committed
+ * (Xmin is committed && the row was modified by a committed transaction, and
+ * (Xmax is null || the row has not been deleted, or
+ * (Xmax == my-transaction && the row is being deleted by this command, or
+ * Cmax == my-command) ||
+ * (Xmax is not committed && the row was deleted by another transaction
+ * Xmax != my-transaction)))) that has not been committed
*
* XXX
- * CommandId stuff didn't work properly if one used SQL-functions in
- * UPDATE/INSERT(fromSELECT)/DELETE scans: SQL-funcs call
- * CommandCounterIncrement and made tuples changed/inserted by
- * current command visible to command itself (so we had multiple
- * update of updated tuples, etc). - vadim 08/29/97
- *
- * mao says 17 march 1993: the tests in this routine are correct;
- * if you think they're not, you're wrong, and you should think
- * about it again. i know, it happened to me. we don't need to
- * check commit time against the start time of this transaction
- * because 2ph locking protects us from doing the wrong thing.
- * if you mess around here, you'll break serializability. the only
- * problem with this code is that it does the wrong thing for system
- * catalog updates, because the catalogs aren't subject to 2ph, so
- * the serializability guarantees we provide don't extend to xacts
- * that do catalog accesses. this is unfortunate, but not critical.
+ * CommandId stuff didn't work properly if one used SQL-functions in
+ * UPDATE/INSERT(fromSELECT)/DELETE scans: SQL-funcs call
+ * CommandCounterIncrement and made tuples changed/inserted by
+ * current command visible to command itself (so we had multiple
+ * update of updated tuples, etc). - vadim 08/29/97
+ *
+ * mao says 17 march 1993: the tests in this routine are correct;
+ * if you think they're not, you're wrong, and you should think
+ * about it again. i know, it happened to me. we don't need to
+ * check commit time against the start time of this transaction
+ * because 2ph locking protects us from doing the wrong thing.
+ * if you mess around here, you'll break serializability. the only
+ * problem with this code is that it does the wrong thing for system
+ * catalog updates, because the catalogs aren't subject to 2ph, so
+ * the serializability guarantees we provide don't extend to xacts
+ * that do catalog accesses. this is unfortunate, but not critical.
*/
-static bool
+static bool
HeapTupleSatisfiesNow(HeapTuple tuple)
{
- if (AMI_OVERRIDE)
- return true;
- /*
- * If the transaction system isn't yet initialized, then we assume
- * that transactions committed. We only look at system catalogs
- * during startup, so this is less awful than it seems, but it's
- * still pretty awful.
- */
-
- if (!PostgresIsInitialized)
- return ((bool)(TransactionIdIsValid((TransactionId)tuple->t_xmin) &&
- !TransactionIdIsValid((TransactionId)tuple->t_xmax)));
-
- /*
- * XXX Several evil casts are made in this routine. Casting XID to be
- * TransactionId works only because TransactionId->data is the first
- * (and only) field of the structure.
- */
- if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin)) {
-
- if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmin)
- && CommandIdGEScanCommandId(tuple->t_cmin)) {
-
- return (false);
- }
-
- if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmin)
- && !CommandIdGEScanCommandId(tuple->t_cmin)) {
-
- if (!TransactionIdIsValid((TransactionId)tuple->t_xmax)) {
- return (true);
- }
-
- Assert(TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmax));
-
- if (CommandIdGEScanCommandId(tuple->t_cmax)) {
- return (true);
- }
- }
-
+ if (AMI_OVERRIDE)
+ return true;
+
/*
- * this call is VERY expensive - requires a log table lookup.
+ * If the transaction system isn't yet initialized, then we assume
+ * that transactions committed. We only look at system catalogs
+ * during startup, so this is less awful than it seems, but it's still
+ * pretty awful.
*/
-
- if (!TransactionIdDidCommit((TransactionId)tuple->t_xmin)) {
- return (false);
- }
- /*
- * the transaction has been committed--store the commit time _now_
- * instead of waiting for a vacuum so we avoid the expensive call
- * next time.
+ if (!PostgresIsInitialized)
+ return ((bool) (TransactionIdIsValid((TransactionId) tuple->t_xmin) &&
+ !TransactionIdIsValid((TransactionId) tuple->t_xmax)));
+
+ /*
+ * XXX Several evil casts are made in this routine. Casting XID to be
+ * TransactionId works only because TransactionId->data is the first
+ * (and only) field of the structure.
*/
- tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
- }
-
- /* by here, the inserting transaction has committed */
- if (!TransactionIdIsValid((TransactionId)tuple->t_xmax)) {
- return (true);
- }
-
- if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmax)) {
- return (false);
- }
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin))
+ {
+
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmin)
+ && CommandIdGEScanCommandId(tuple->t_cmin))
+ {
+
+ return (false);
+ }
+
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmin)
+ && !CommandIdGEScanCommandId(tuple->t_cmin))
+ {
+
+ if (!TransactionIdIsValid((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
+
+ Assert(TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmax));
+
+ if (CommandIdGEScanCommandId(tuple->t_cmax))
+ {
+ return (true);
+ }
+ }
+
+ /*
+ * this call is VERY expensive - requires a log table lookup.
+ */
+
+ if (!TransactionIdDidCommit((TransactionId) tuple->t_xmin))
+ {
+ return (false);
+ }
+
+ /*
+ * the transaction has been committed--store the commit time _now_
+ * instead of waiting for a vacuum so we avoid the expensive call
+ * next time.
+ */
+ tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
+ }
- if (AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax)) {
- return (false);
- }
+ /* by here, the inserting transaction has committed */
+ if (!TransactionIdIsValid((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
- if (!TransactionIdDidCommit((TransactionId)tuple->t_xmax)) {
- return (true);
- }
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmax))
+ {
+ return (false);
+ }
+
+ if (AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax))
+ {
+ return (false);
+ }
- /* xmax transaction committed, but no tmax set. so set it. */
- tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
+ if (!TransactionIdDidCommit((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
+
+ /* xmax transaction committed, but no tmax set. so set it. */
+ tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
- return (false);
+ return (false);
}
/*
* HeapTupleSatisfiesSnapshotInternalTimeQual --
- * True iff heap tuple is valid at the snapshot time qualification.
+ * True iff heap tuple is valid at the snapshot time qualification.
*
* Note:
- * Assumes heap tuple is valid.
- * Assumes internal time qualification is valid snapshot qualification.
+ * Assumes heap tuple is valid.
+ * Assumes internal time qualification is valid snapshot qualification.
*/
/*
* The satisfaction of Rel[T] requires the following:
*
* (Xmin is committed && Tmin <= T &&
- * (Xmax is null || (Xmax is not committed && Xmax != my-transaction) ||
- * Tmax >= T))
+ * (Xmax is null || (Xmax is not committed && Xmax != my-transaction) ||
+ * Tmax >= T))
*/
-static bool
+static bool
HeapTupleSatisfiesSnapshotInternalTimeQual(HeapTuple tuple,
- InternalTimeQual qual)
+ InternalTimeQual qual)
{
- /*
- * XXX Several evil casts are made in this routine. Casting XID to be
- * TransactionId works only because TransactionId->data is the first
- * (and only) field of the structure.
- */
- if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin)) {
-
- if (!TransactionIdDidCommit((TransactionId)tuple->t_xmin)) {
- return (false);
- }
-
- tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
- }
-
- if (AbsoluteTimeIsBefore(TimeQualGetSnapshotTime((TimeQual)qual), tuple->t_tmin)) {
- return (false);
- }
- /* the tuple was inserted validly before the snapshot time */
-
- if (!AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax)) {
-
- if (!TransactionIdIsValid((TransactionId)tuple->t_xmax) ||
- !TransactionIdDidCommit((TransactionId)tuple->t_xmax)) {
-
- return (true);
- }
-
- tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
- }
-
- return ((bool)
- AbsoluteTimeIsAfter(tuple->t_tmax,
- TimeQualGetSnapshotTime((TimeQual)qual)));
+
+ /*
+ * XXX Several evil casts are made in this routine. Casting XID to be
+ * TransactionId works only because TransactionId->data is the first
+ * (and only) field of the structure.
+ */
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin))
+ {
+
+ if (!TransactionIdDidCommit((TransactionId) tuple->t_xmin))
+ {
+ return (false);
+ }
+
+ tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
+ }
+
+ if (AbsoluteTimeIsBefore(TimeQualGetSnapshotTime((TimeQual) qual), tuple->t_tmin))
+ {
+ return (false);
+ }
+ /* the tuple was inserted validly before the snapshot time */
+
+ if (!AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax))
+ {
+
+ if (!TransactionIdIsValid((TransactionId) tuple->t_xmax) ||
+ !TransactionIdDidCommit((TransactionId) tuple->t_xmax))
+ {
+
+ return (true);
+ }
+
+ tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
+ }
+
+ return ((bool)
+ AbsoluteTimeIsAfter(tuple->t_tmax,
+ TimeQualGetSnapshotTime((TimeQual) qual)));
}
/*
* HeapTupleSatisfiesUpperBoundedInternalTimeQual --
- * True iff heap tuple is valid within a upper bounded time qualification.
+ * True iff heap tuple is valid within a upper bounded time qualification.
*
* Note:
- * Assumes heap tuple is valid.
- * Assumes time qualification is valid ranged qualification with fixed
- * upper bound.
+ * Assumes heap tuple is valid.
+ * Assumes time qualification is valid ranged qualification with fixed
+ * upper bound.
*/
/*
* The satisfaction of [T1,T2] requires the following:
*
* (Xmin is committed && Tmin <= T2 &&
- * (Xmax is null || (Xmax is not committed && Xmax != my-transaction) ||
- * T1 is null || Tmax >= T1))
+ * (Xmax is null || (Xmax is not committed && Xmax != my-transaction) ||
+ * T1 is null || Tmax >= T1))
*/
-static bool
+static bool
HeapTupleSatisfiesUpperBoundedInternalTimeQual(HeapTuple tuple,
- InternalTimeQual qual)
+ InternalTimeQual qual)
{
- /*
- * XXX Several evil casts are made in this routine. Casting XID to be
- * TransactionId works only because TransactionId->data is the first
- * (and only) field of the structure.
- */
- if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin)) {
-
- if (!TransactionIdDidCommit((TransactionId)tuple->t_xmin)) {
- return (false);
- }
-
- tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
- }
-
- if (AbsoluteTimeIsBefore(TimeQualGetEndTime((TimeQual)qual), tuple->t_tmin)) {
- return (false);
- }
- /* the tuple was inserted validly before the range end */
-
- if (!AbsoluteTimeIsBackwardCompatiblyValid(TimeQualGetStartTime((TimeQual)qual))) {
- return (true);
- }
-
- if (!AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax)) {
-
- if (!TransactionIdIsValid((TransactionId)tuple->t_xmax) ||
- !TransactionIdDidCommit((TransactionId)tuple->t_xmax)) {
-
- return (true);
- }
-
- tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
- }
-
- return ((bool)AbsoluteTimeIsAfter(tuple->t_tmax,
- TimeQualGetStartTime((TimeQual)qual)));
+
+ /*
+ * XXX Several evil casts are made in this routine. Casting XID to be
+ * TransactionId works only because TransactionId->data is the first
+ * (and only) field of the structure.
+ */
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin))
+ {
+
+ if (!TransactionIdDidCommit((TransactionId) tuple->t_xmin))
+ {
+ return (false);
+ }
+
+ tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
+ }
+
+ if (AbsoluteTimeIsBefore(TimeQualGetEndTime((TimeQual) qual), tuple->t_tmin))
+ {
+ return (false);
+ }
+ /* the tuple was inserted validly before the range end */
+
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(TimeQualGetStartTime((TimeQual) qual)))
+ {
+ return (true);
+ }
+
+ if (!AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax))
+ {
+
+ if (!TransactionIdIsValid((TransactionId) tuple->t_xmax) ||
+ !TransactionIdDidCommit((TransactionId) tuple->t_xmax))
+ {
+
+ return (true);
+ }
+
+ tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
+ }
+
+ return ((bool) AbsoluteTimeIsAfter(tuple->t_tmax,
+ TimeQualGetStartTime((TimeQual) qual)));
}
/*
* HeapTupleSatisfiesUpperUnboundedInternalTimeQual --
- * True iff heap tuple is valid within a upper bounded time qualification.
+ * True iff heap tuple is valid within a upper bounded time qualification.
*
* Note:
- * Assumes heap tuple is valid.
- * Assumes time qualification is valid ranged qualification with no
- * upper bound.
+ * Assumes heap tuple is valid.
+ * Assumes time qualification is valid ranged qualification with no
+ * upper bound.
*/
/*
* The satisfaction of [T1,] requires the following:
*
* ((Xmin == my-transaction && Cmin != my-command &&
- * (Xmax is null || (Xmax == my-transaction && Cmax != my-command)))
+ * (Xmax is null || (Xmax == my-transaction && Cmax != my-command)))
* ||
*
* (Xmin is committed &&
- * (Xmax is null || (Xmax == my-transaction && Cmax == my-command) ||
- * (Xmax is not committed && Xmax != my-transaction) ||
- * T1 is null || Tmax >= T1)))
+ * (Xmax is null || (Xmax == my-transaction && Cmax == my-command) ||
+ * (Xmax is not committed && Xmax != my-transaction) ||
+ * T1 is null || Tmax >= T1)))
*/
-static bool
+static bool
HeapTupleSatisfiesUpperUnboundedInternalTimeQual(HeapTuple tuple,
- InternalTimeQual qual)
+ InternalTimeQual qual)
{
- if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin)) {
-
- if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmin) &&
- CommandIdGEScanCommandId(tuple->t_cmin)) {
-
- return (false);
- }
-
- if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmin) &&
- !CommandIdGEScanCommandId(tuple->t_cmin)) {
-
- if (!TransactionIdIsValid((TransactionId)tuple->t_xmax)) {
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(tuple->t_tmin))
+ {
+
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmin) &&
+ CommandIdGEScanCommandId(tuple->t_cmin))
+ {
+
+ return (false);
+ }
+
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmin) &&
+ !CommandIdGEScanCommandId(tuple->t_cmin))
+ {
+
+ if (!TransactionIdIsValid((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
+
+ Assert(TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmax));
+
+ return ((bool) ! CommandIdGEScanCommandId(tuple->t_cmax));
+ }
+
+ if (!TransactionIdDidCommit((TransactionId) tuple->t_xmin))
+ {
+ return (false);
+ }
+
+ tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
+ }
+ /* the tuple was inserted validly */
+
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(TimeQualGetStartTime((TimeQual) qual)))
+ {
return (true);
- }
-
- Assert(TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmax));
-
- return ((bool) !CommandIdGEScanCommandId(tuple->t_cmax));
- }
-
- if (!TransactionIdDidCommit((TransactionId)tuple->t_xmin)) {
- return (false);
- }
-
- tuple->t_tmin = TransactionIdGetCommitTime(tuple->t_xmin);
- }
- /* the tuple was inserted validly */
-
- if (!AbsoluteTimeIsBackwardCompatiblyValid(TimeQualGetStartTime((TimeQual)qual))) {
- return (true);
- }
-
- if (!AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax)) {
-
- if (!TransactionIdIsValid((TransactionId)tuple->t_xmax)) {
- return (true);
- }
-
- if (TransactionIdIsCurrentTransactionId((TransactionId)tuple->t_xmax)) {
- return (CommandIdGEScanCommandId(tuple->t_cmin));
- /* it looks like error ^^^^ */
- }
-
- if (!TransactionIdDidCommit((TransactionId)tuple->t_xmax)) {
- return (true);
- }
-
- tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
- }
-
- return ((bool)AbsoluteTimeIsAfter(tuple->t_tmax,
- TimeQualGetStartTime((TimeQual)qual)));
+ }
+
+ if (!AbsoluteTimeIsBackwardCompatiblyReal(tuple->t_tmax))
+ {
+
+ if (!TransactionIdIsValid((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
+
+ if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_xmax))
+ {
+ return (CommandIdGEScanCommandId(tuple->t_cmin));
+ /* it looks like error ^^^^ */
+ }
+
+ if (!TransactionIdDidCommit((TransactionId) tuple->t_xmax))
+ {
+ return (true);
+ }
+
+ tuple->t_tmax = TransactionIdGetCommitTime(tuple->t_xmax);
+ }
+
+ return ((bool) AbsoluteTimeIsAfter(tuple->t_tmax,
+ TimeQualGetStartTime((TimeQual) qual)));
}