xref: /openbsd-src/gnu/usr.bin/perl/cpan/DB_File/DB_File.xs (revision 3d61058aa5c692477b6d18acfbbdb653a9930ff9)
1b39c5158Smillert /*
2b39c5158Smillert 
3b39c5158Smillert  DB_File.xs -- Perl 5 interface to Berkeley DB
4b39c5158Smillert 
56fb12b70Safresh1  Written by Paul Marquess <pmqs@cpan.org>
6b39c5158Smillert 
7b39c5158Smillert  All comments/suggestions/problems are welcome
8b39c5158Smillert 
9*3d61058aSafresh1      Copyright (c) 1995-2023 Paul Marquess. All rights reserved.
10b39c5158Smillert      This program is free software; you can redistribute it and/or
11b39c5158Smillert      modify it under the same terms as Perl itself.
12b39c5158Smillert 
13b39c5158Smillert  Changes:
14b39c5158Smillert     0.1 -   Initial Release
15b39c5158Smillert     0.2 -   No longer bombs out if dbopen returns an error.
16b39c5158Smillert     0.3 -   Added some support for multiple btree compares
17b39c5158Smillert     1.0 -   Complete support for multiple callbacks added.
18b39c5158Smillert             Fixed a problem with pushing a value onto an empty list.
19b39c5158Smillert     1.01 -  Fixed a SunOS core dump problem.
20b39c5158Smillert             The return value from TIEHASH wasn't set to NULL when
21b39c5158Smillert             dbopen returned an error.
22b39c5158Smillert     1.02 -  Use ALIAS to define TIEARRAY.
23b39c5158Smillert             Removed some redundant commented code.
24b39c5158Smillert             Merged OS2 code into the main distribution.
25b39c5158Smillert             Allow negative subscripts with RECNO interface.
26b39c5158Smillert             Changed the default flags to O_CREAT|O_RDWR
27b39c5158Smillert     1.03 -  Added EXISTS
28b39c5158Smillert     1.04 -  fixed a couple of bugs in hash_cb. Patches supplied by
29b39c5158Smillert             Dave Hammen, hammen@gothamcity.jsc.nasa.gov
30b39c5158Smillert     1.05 -  Added logic to allow prefix & hash types to be specified via
31b39c5158Smillert             Makefile.PL
32b39c5158Smillert     1.06 -  Minor namespace cleanup: Localized PrintBtree.
33b39c5158Smillert     1.07 -  Fixed bug with RECNO, where bval wasn't defaulting to "\n".
34b39c5158Smillert     1.08 -  No change to DB_File.xs
35b39c5158Smillert     1.09 -  Default mode for dbopen changed to 0666
36b39c5158Smillert     1.10 -  Fixed fd method so that it still returns -1 for
37b39c5158Smillert             in-memory files when db 1.86 is used.
38b39c5158Smillert     1.11 -  No change to DB_File.xs
39b39c5158Smillert     1.12 -  No change to DB_File.xs
40b39c5158Smillert     1.13 -  Tidied up a few casts.
41b39c5158Smillert     1.14 -  Made it illegal to tie an associative array to a RECNO
42b39c5158Smillert             database and an ordinary array to a HASH or BTREE database.
43b39c5158Smillert     1.50 -  Make work with both DB 1.x or DB 2.x
44b39c5158Smillert     1.51 -  Fixed a bug in mapping 1.x O_RDONLY flag to 2.x DB_RDONLY equivalent
45b39c5158Smillert     1.52 -  Patch from Gisle Aas <gisle@aas.no> to suppress "use of
46b39c5158Smillert             undefined value" warning with db_get and db_seq.
47b39c5158Smillert     1.53 -  Added DB_RENUMBER to flags for recno.
48b39c5158Smillert     1.54 -  Fixed bug in the fd method
49b39c5158Smillert     1.55 -  Fix for AIX from Jarkko Hietaniemi
50b39c5158Smillert     1.56 -  No change to DB_File.xs
51b39c5158Smillert     1.57 -  added the #undef op to allow building with Threads support.
52b39c5158Smillert     1.58 -  Fixed a problem with the use of sv_setpvn. When the
53b39c5158Smillert             size is specified as 0, it does a strlen on the data.
54b39c5158Smillert             This was ok for DB 1.x, but isn't for DB 2.x.
55b39c5158Smillert     1.59 -  No change to DB_File.xs
56b39c5158Smillert     1.60 -  Some code tidy up
57b39c5158Smillert     1.61 -  added flagSet macro for DB 2.5.x
58b39c5158Smillert             fixed typo in O_RDONLY test.
59b39c5158Smillert     1.62 -  No change to DB_File.xs
60b39c5158Smillert     1.63 -  Fix to alllow DB 2.6.x to build.
61b39c5158Smillert     1.64 -  Tidied up the 1.x to 2.x flags mapping code.
62b39c5158Smillert             Added a patch from Mark Kettenis <kettenis@wins.uva.nl>
63b39c5158Smillert             to fix a flag mapping problem with O_RDONLY on the Hurd
64b39c5158Smillert     1.65 -  Fixed a bug in the PUSH logic.
65b39c5158Smillert             Added BOOT check that using 2.3.4 or greater
66b39c5158Smillert     1.66 -  Added DBM filter code
67b39c5158Smillert     1.67 -  Backed off the use of newSVpvn.
68b39c5158Smillert             Fixed DBM Filter code for Perl 5.004.
69b39c5158Smillert             Fixed a small memory leak in the filter code.
70898184e3Ssthen     1.68 -  fixed backward compatibility bug with R_IAFTER & R_IBEFORE
71b39c5158Smillert             merged in the 5.005_58 changes
72b39c5158Smillert     1.69 -  fixed a bug in push -- DB_APPEND wasn't working properly.
73b39c5158Smillert             Fixed the R_SETCURSOR bug introduced in 1.68
74b39c5158Smillert             Added a new Perl variable $DB_File::db_ver
75b39c5158Smillert     1.70 -  Initialise $DB_File::db_ver and $DB_File::db_version with
76b39c5158Smillert             GV_ADD|GV_ADDMULT -- bug spotted by Nick Ing-Simmons.
77b39c5158Smillert             Added a BOOT check to test for equivalent versions of db.h &
78b39c5158Smillert             libdb.a/so.
79b39c5158Smillert     1.71 -  Support for Berkeley DB version 3.
80898184e3Ssthen             Support for Berkeley DB 2/3's backward compatibility mode.
81b39c5158Smillert             Rewrote push
82b39c5158Smillert     1.72 -  No change to DB_File.xs
83b39c5158Smillert     1.73 -  No change to DB_File.xs
84b39c5158Smillert     1.74 -  A call to open needed parenthesised to stop it clashing
85b39c5158Smillert             with a win32 macro.
86b39c5158Smillert             Added Perl core patches 7703 & 7801.
87b39c5158Smillert     1.75 -  Fixed Perl core patch 7703.
88898184e3Ssthen             Added support to allow DB_File to be built with
89b39c5158Smillert             Berkeley DB 3.2 -- btree_compare, btree_prefix and hash_cb
90b39c5158Smillert             needed to be changed.
91b39c5158Smillert     1.76 -  No change to DB_File.xs
92b39c5158Smillert     1.77 -  Tidied up a few types used in calling newSVpvn.
93b39c5158Smillert     1.78 -  Core patch 10335, 10372, 10534, 10549, 11051 included.
94b39c5158Smillert     1.79 -  NEXTKEY ignores the input key.
95b39c5158Smillert             Added lots of casts
96898184e3Ssthen     1.800 - Moved backward compatibility code into ppport.h.
97b39c5158Smillert             Use the new constants code.
98b39c5158Smillert     1.801 - No change to DB_File.xs
99b39c5158Smillert     1.802 - No change to DB_File.xs
100b39c5158Smillert     1.803 - FETCH, STORE & DELETE don't map the flags parameter
101b39c5158Smillert             into the equivalent Berkeley DB function anymore.
102b39c5158Smillert     1.804 - no change.
103b39c5158Smillert     1.805 - recursion detection added to the callbacks
104b39c5158Smillert             Support for 4.1.X added.
105b39c5158Smillert             Filter code can now cope with read-only $_
106b39c5158Smillert     1.806 - recursion detection beefed up.
107b39c5158Smillert     1.807 - no change
108b39c5158Smillert     1.808 - leak fixed in ParseOpenInfo
109b39c5158Smillert     1.809 - no change
110b39c5158Smillert     1.810 - no change
111b39c5158Smillert     1.811 - no change
112b39c5158Smillert     1.812 - no change
113b39c5158Smillert     1.813 - no change
114b39c5158Smillert     1.814 - no change
115b39c5158Smillert     1.814 - C++ casting fixes
116b39c5158Smillert 
117b39c5158Smillert */
118b39c5158Smillert 
119b39c5158Smillert #define PERL_NO_GET_CONTEXT
120b39c5158Smillert #include "EXTERN.h"
121b39c5158Smillert #include "perl.h"
122b39c5158Smillert #include "XSUB.h"
123b39c5158Smillert 
124b39c5158Smillert #ifdef _NOT_CORE
125b39c5158Smillert #  include "ppport.h"
126b39c5158Smillert #endif
127b39c5158Smillert 
128b8851fccSafresh1 int DB_File___unused() { return 0; }
129b8851fccSafresh1 
130b39c5158Smillert /* Mention DB_VERSION_MAJOR_CFG, DB_VERSION_MINOR_CFG, and
131b39c5158Smillert    DB_VERSION_PATCH_CFG here so that Configure pulls them all in. */
132b39c5158Smillert 
133b39c5158Smillert /* Being the Berkeley DB we prefer the <sys/cdefs.h> (which will be
134b39c5158Smillert  * shortly #included by the <db.h>) __attribute__ to the possibly
135b39c5158Smillert  * already defined __attribute__, for example by GNUC or by Perl. */
136b39c5158Smillert 
137b39c5158Smillert /* #if DB_VERSION_MAJOR_CFG < 2  */
138b39c5158Smillert #ifndef DB_VERSION_MAJOR
139b39c5158Smillert #    undef __attribute__
140b39c5158Smillert #endif
141b39c5158Smillert 
142b39c5158Smillert #ifdef COMPAT185
143b39c5158Smillert #    include <db_185.h>
144b39c5158Smillert #else
1456fb12b70Safresh1 
1466fb12b70Safresh1 /* Uncomment one of the lines below */
1476fb12b70Safresh1 /* See the section "At least one secondary cursor must be specified to DB->join"
1486fb12b70Safresh1    in the README file for the circumstances where you need to uncomment one
1496fb12b70Safresh1    of the two lines below.
1506fb12b70Safresh1 */
1516fb12b70Safresh1 
1526fb12b70Safresh1 /* #define time_t __time64_t */
1536fb12b70Safresh1 /* #define time_t __time32_t */
1546fb12b70Safresh1 
155b39c5158Smillert #    include <db.h>
156b39c5158Smillert #endif
157b39c5158Smillert 
158b8851fccSafresh1 #ifndef PERL_UNUSED_ARG
159b8851fccSafresh1 #  define PERL_UNUSED_ARG(x) ((void)x)
160b8851fccSafresh1 #endif
161b8851fccSafresh1 
162b39c5158Smillert /* Wall starts with 5.7.x */
163b39c5158Smillert 
164b39c5158Smillert #if PERL_REVISION > 5 || (PERL_REVISION == 5 && PERL_VERSION >= 7)
165b39c5158Smillert 
166b39c5158Smillert /* Since we dropped the gccish definition of __attribute__ we will want
167b39c5158Smillert  * to redefine dNOOP, however (so that dTHX continues to work).  Yes,
168b39c5158Smillert  * all this means that we can't do attribute checking on the DB_File,
169b39c5158Smillert  * boo, hiss. */
170b39c5158Smillert #  ifndef DB_VERSION_MAJOR
171b39c5158Smillert 
172b39c5158Smillert #    undef  dNOOP
173b8851fccSafresh1 #    ifdef __cplusplus
174b8851fccSafresh1 #        define dNOOP (void)0
175b8851fccSafresh1 #    else
176b8851fccSafresh1 #        define dNOOP extern int DB_File___notused()
177b8851fccSafresh1 #    endif
178b39c5158Smillert 
179b39c5158Smillert     /* Ditto for dXSARGS. */
180b39c5158Smillert #    undef  dXSARGS
181b39c5158Smillert #    define dXSARGS             \
182b39c5158Smillert     dSP; dMARK;         \
183b39c5158Smillert     I32 ax = mark - PL_stack_base + 1;  \
184b39c5158Smillert     I32 items = sp - mark
185b39c5158Smillert 
186b39c5158Smillert #  endif
187b39c5158Smillert 
188b39c5158Smillert /* avoid -Wall; DB_File xsubs never make use of `ix' setup for ALIASes */
189b39c5158Smillert #  undef dXSI32
190b39c5158Smillert #  define dXSI32 dNOOP
191b39c5158Smillert 
192b39c5158Smillert #endif /* Perl >= 5.7 */
193b39c5158Smillert 
194b39c5158Smillert #include <fcntl.h>
195b39c5158Smillert 
196b39c5158Smillert /* #define TRACE */
197b39c5158Smillert 
198b39c5158Smillert #ifdef TRACE
199b39c5158Smillert #    define Trace(x)        printf x
200b39c5158Smillert #else
201b39c5158Smillert #    define Trace(x)
202b39c5158Smillert #endif
203b39c5158Smillert 
204b39c5158Smillert 
205b39c5158Smillert #define DBT_clear(x)    Zero(&x, 1, DBT) ;
206b39c5158Smillert 
207b39c5158Smillert #ifdef DB_VERSION_MAJOR
208b39c5158Smillert 
209b39c5158Smillert #if DB_VERSION_MAJOR == 2
210b39c5158Smillert #    define BERKELEY_DB_1_OR_2
211b39c5158Smillert #endif
212b39c5158Smillert 
213b39c5158Smillert #if DB_VERSION_MAJOR > 3 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
214b39c5158Smillert #    define AT_LEAST_DB_3_2
215b39c5158Smillert #endif
216b39c5158Smillert 
217b39c5158Smillert #if DB_VERSION_MAJOR > 3 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 3)
218b39c5158Smillert #    define AT_LEAST_DB_3_3
219b39c5158Smillert #endif
220b39c5158Smillert 
221b39c5158Smillert #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
222b39c5158Smillert #    define AT_LEAST_DB_4_1
223b39c5158Smillert #endif
224b39c5158Smillert 
225b39c5158Smillert #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
226b39c5158Smillert #    define AT_LEAST_DB_4_3
227b39c5158Smillert #endif
228b39c5158Smillert 
2296fb12b70Safresh1 #if DB_VERSION_MAJOR >= 6
2306fb12b70Safresh1 #    define AT_LEAST_DB_6_0
2316fb12b70Safresh1 #endif
2326fb12b70Safresh1 
233b39c5158Smillert #ifdef AT_LEAST_DB_3_3
234b39c5158Smillert #   define WANT_ERROR
235b39c5158Smillert #endif
236b39c5158Smillert 
237b39c5158Smillert /* map version 2 features & constants onto their version 1 equivalent */
238b39c5158Smillert 
239b39c5158Smillert #ifdef DB_Prefix_t
240b39c5158Smillert #    undef DB_Prefix_t
241b39c5158Smillert #endif
242b39c5158Smillert #define DB_Prefix_t size_t
243b39c5158Smillert 
244b39c5158Smillert #ifdef DB_Hash_t
245b39c5158Smillert #    undef DB_Hash_t
246b39c5158Smillert #endif
247b39c5158Smillert #define DB_Hash_t   u_int32_t
248b39c5158Smillert 
249b39c5158Smillert /* DBTYPE stays the same */
250b39c5158Smillert /* HASHINFO, RECNOINFO and BTREEINFO  map to DB_INFO */
251b39c5158Smillert #if DB_VERSION_MAJOR == 2
252b39c5158Smillert     typedef DB_INFO INFO ;
253b39c5158Smillert #else /* DB_VERSION_MAJOR > 2 */
254b39c5158Smillert #    define DB_FIXEDLEN (0x8000)
255b39c5158Smillert #endif /* DB_VERSION_MAJOR == 2 */
256b39c5158Smillert 
257b39c5158Smillert /* version 2 has db_recno_t in place of recno_t */
258b39c5158Smillert typedef db_recno_t  recno_t;
259b39c5158Smillert 
260b39c5158Smillert 
261b39c5158Smillert #define R_CURSOR        DB_SET_RANGE
262b39c5158Smillert #define R_FIRST         DB_FIRST
263b39c5158Smillert #define R_IAFTER        DB_AFTER
264b39c5158Smillert #define R_IBEFORE       DB_BEFORE
265b39c5158Smillert #define R_LAST          DB_LAST
266b39c5158Smillert #define R_NEXT          DB_NEXT
267b39c5158Smillert #define R_NOOVERWRITE   DB_NOOVERWRITE
268b39c5158Smillert #define R_PREV          DB_PREV
269b39c5158Smillert 
270b39c5158Smillert #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
271b39c5158Smillert #  define R_SETCURSOR   0x800000
272b39c5158Smillert #else
2739f11ffb7Safresh1 #  define R_SETCURSOR   (DB_OPFLAGS_MASK)
274b39c5158Smillert #endif
275b39c5158Smillert 
276b39c5158Smillert #define R_RECNOSYNC     0
277b39c5158Smillert #define R_FIXEDLEN  DB_FIXEDLEN
278b39c5158Smillert #define R_DUP       DB_DUP
279b39c5158Smillert 
280b39c5158Smillert 
281b39c5158Smillert #define db_HA_hash  h_hash
282b39c5158Smillert #define db_HA_ffactor   h_ffactor
283b39c5158Smillert #define db_HA_nelem h_nelem
284b39c5158Smillert #define db_HA_bsize db_pagesize
285b39c5158Smillert #define db_HA_cachesize db_cachesize
286b39c5158Smillert #define db_HA_lorder    db_lorder
287b39c5158Smillert 
288b39c5158Smillert #define db_BT_compare   bt_compare
289b39c5158Smillert #define db_BT_prefix    bt_prefix
290b39c5158Smillert #define db_BT_flags flags
291b39c5158Smillert #define db_BT_psize db_pagesize
292b39c5158Smillert #define db_BT_cachesize db_cachesize
293b39c5158Smillert #define db_BT_lorder    db_lorder
294b39c5158Smillert #define db_BT_maxkeypage
295b39c5158Smillert #define db_BT_minkeypage
296b39c5158Smillert 
297b39c5158Smillert 
298b39c5158Smillert #define db_RE_reclen    re_len
299b39c5158Smillert #define db_RE_flags flags
300b39c5158Smillert #define db_RE_bval  re_pad
301b39c5158Smillert #define db_RE_bfname    re_source
302b39c5158Smillert #define db_RE_psize db_pagesize
303b39c5158Smillert #define db_RE_cachesize db_cachesize
304b39c5158Smillert #define db_RE_lorder    db_lorder
305b39c5158Smillert 
306b39c5158Smillert #define TXN NULL,
307b39c5158Smillert 
308b39c5158Smillert #define do_SEQ(db, key, value, flag)    (db->cursor->c_get)(db->cursor, &key, &value, flag)
309b39c5158Smillert 
310b39c5158Smillert 
311b39c5158Smillert #define DBT_flags(x)    x.flags = 0
312b39c5158Smillert #define DB_flags(x, v)  x |= v
313b39c5158Smillert 
314b39c5158Smillert #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
315b39c5158Smillert #    define flagSet(flags, bitmask) ((flags) & (bitmask))
316b39c5158Smillert #else
317b8851fccSafresh1 #    define flagSet(flags, bitmask) (((flags) & DB_OPFLAGS_MASK) == (u_int)(bitmask))
318b39c5158Smillert #endif
319b39c5158Smillert 
320b39c5158Smillert #else /* db version 1.x */
321b39c5158Smillert 
322b39c5158Smillert #define BERKELEY_DB_1
323b39c5158Smillert #define BERKELEY_DB_1_OR_2
324b39c5158Smillert 
325b39c5158Smillert typedef union INFO {
326b39c5158Smillert         HASHINFO    hash ;
327b39c5158Smillert         RECNOINFO   recno ;
328b39c5158Smillert         BTREEINFO   btree ;
329b39c5158Smillert       } INFO ;
330b39c5158Smillert 
331b39c5158Smillert 
332b39c5158Smillert #ifdef mDB_Prefix_t
333b39c5158Smillert #  ifdef DB_Prefix_t
334b39c5158Smillert #    undef DB_Prefix_t
335b39c5158Smillert #  endif
336b39c5158Smillert #  define DB_Prefix_t   mDB_Prefix_t
337b39c5158Smillert #endif
338b39c5158Smillert 
339b39c5158Smillert #ifdef mDB_Hash_t
340b39c5158Smillert #  ifdef DB_Hash_t
341b39c5158Smillert #    undef DB_Hash_t
342b39c5158Smillert #  endif
343b39c5158Smillert #  define DB_Hash_t mDB_Hash_t
344b39c5158Smillert #endif
345b39c5158Smillert 
346b39c5158Smillert #define db_HA_hash  hash.hash
347b39c5158Smillert #define db_HA_ffactor   hash.ffactor
348b39c5158Smillert #define db_HA_nelem hash.nelem
349b39c5158Smillert #define db_HA_bsize hash.bsize
350b39c5158Smillert #define db_HA_cachesize hash.cachesize
351b39c5158Smillert #define db_HA_lorder    hash.lorder
352b39c5158Smillert 
353b39c5158Smillert #define db_BT_compare   btree.compare
354b39c5158Smillert #define db_BT_prefix    btree.prefix
355b39c5158Smillert #define db_BT_flags btree.flags
356b39c5158Smillert #define db_BT_psize btree.psize
357b39c5158Smillert #define db_BT_cachesize btree.cachesize
358b39c5158Smillert #define db_BT_lorder    btree.lorder
359b39c5158Smillert #define db_BT_maxkeypage btree.maxkeypage
360b39c5158Smillert #define db_BT_minkeypage btree.minkeypage
361b39c5158Smillert 
362b39c5158Smillert #define db_RE_reclen    recno.reclen
363b39c5158Smillert #define db_RE_flags recno.flags
364b39c5158Smillert #define db_RE_bval  recno.bval
365b39c5158Smillert #define db_RE_bfname    recno.bfname
366b39c5158Smillert #define db_RE_psize recno.psize
367b39c5158Smillert #define db_RE_cachesize recno.cachesize
368b39c5158Smillert #define db_RE_lorder    recno.lorder
369b39c5158Smillert 
370b39c5158Smillert #define TXN
371b39c5158Smillert 
372b39c5158Smillert #define do_SEQ(db, key, value, flag)    (db->dbp->seq)(db->dbp, &key, &value, flag)
373b39c5158Smillert #define DBT_flags(x)
374b39c5158Smillert #define DB_flags(x, v)
375b39c5158Smillert #define flagSet(flags, bitmask)        ((flags) & (bitmask))
376b39c5158Smillert 
377b39c5158Smillert #endif /* db version 1 */
378b39c5158Smillert 
379b39c5158Smillert 
380b39c5158Smillert 
381b39c5158Smillert #define db_DELETE(db, key, flags)       ((db->dbp)->del)(db->dbp, TXN &key, 0)
382b39c5158Smillert #define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, TXN &key, &value, 0)
383b39c5158Smillert #define db_FETCH(db, key, flags)        ((db->dbp)->get)(db->dbp, TXN &key, &value, 0)
384b39c5158Smillert 
385b39c5158Smillert #define db_sync(db, flags)              ((db->dbp)->sync)(db->dbp, flags)
386b39c5158Smillert #define db_get(db, key, value, flags)   ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
387b39c5158Smillert 
388b39c5158Smillert #ifdef DB_VERSION_MAJOR
389b39c5158Smillert #define db_DESTROY(db)                  (!db->aborted && ( db->cursor->c_close(db->cursor),\
390b39c5158Smillert                       (db->dbp->close)(db->dbp, 0) ))
391b39c5158Smillert #define db_close(db)            ((db->dbp)->close)(db->dbp, 0)
392b39c5158Smillert #define db_del(db, key, flags)          (flagSet(flags, R_CURSOR)                   \
393b39c5158Smillert                         ? ((db->cursor)->c_del)(db->cursor, 0)      \
394b39c5158Smillert                         : ((db->dbp)->del)(db->dbp, NULL, &key, flags) )
395b39c5158Smillert 
396b39c5158Smillert #else /* ! DB_VERSION_MAJOR */
397b39c5158Smillert 
398b39c5158Smillert #define db_DESTROY(db)                  (!db->aborted && ((db->dbp)->close)(db->dbp))
399b39c5158Smillert #define db_close(db)            ((db->dbp)->close)(db->dbp)
400b39c5158Smillert #define db_del(db, key, flags)          ((db->dbp)->del)(db->dbp, &key, flags)
401b39c5158Smillert #define db_put(db, key, value, flags)   ((db->dbp)->put)(db->dbp, &key, &value, flags)
402b39c5158Smillert 
403b39c5158Smillert #endif /* ! DB_VERSION_MAJOR */
404b39c5158Smillert 
405b39c5158Smillert 
406b39c5158Smillert #define db_seq(db, key, value, flags)   do_SEQ(db, key, value, flags)
407b39c5158Smillert 
408b39c5158Smillert typedef struct {
409b39c5158Smillert     DBTYPE  type ;
410b39c5158Smillert     DB *    dbp ;
411b39c5158Smillert     SV *    compare ;
412b39c5158Smillert     bool    in_compare ;
413b39c5158Smillert     SV *    prefix ;
414b39c5158Smillert     bool    in_prefix ;
415b39c5158Smillert     SV *    hash ;
416b39c5158Smillert     bool    in_hash ;
417b39c5158Smillert     bool    aborted ;
418b39c5158Smillert     int in_memory ;
419b39c5158Smillert #ifdef BERKELEY_DB_1_OR_2
420b39c5158Smillert     INFO    info ;
421b39c5158Smillert #endif
422b39c5158Smillert #ifdef DB_VERSION_MAJOR
423b39c5158Smillert     DBC *   cursor ;
424b39c5158Smillert #endif
425b39c5158Smillert     SV *    filter_fetch_key ;
426b39c5158Smillert     SV *    filter_store_key ;
427b39c5158Smillert     SV *    filter_fetch_value ;
428b39c5158Smillert     SV *    filter_store_value ;
429b39c5158Smillert     int     filtering ;
430b39c5158Smillert 
431b39c5158Smillert     } DB_File_type;
432b39c5158Smillert 
433b39c5158Smillert typedef DB_File_type * DB_File ;
434b39c5158Smillert typedef DBT DBTKEY ;
435b39c5158Smillert 
436b39c5158Smillert #define my_sv_setpvn(sv, d, s) sv_setpvn(sv, (s ? d : (const char *)""), s)
437b39c5158Smillert 
438b39c5158Smillert #define OutputValue(arg, name)                                              \
439b39c5158Smillert     { if (RETVAL == 0) {                                                    \
440b39c5158Smillert           SvGETMAGIC(arg) ;                                                 \
441b39c5158Smillert           my_sv_setpvn(arg, (const char *)name.data, name.size) ;           \
442b39c5158Smillert           TAINT;                                                            \
443b39c5158Smillert           SvTAINTED_on(arg);                                                \
444b39c5158Smillert           SvUTF8_off(arg);                                                  \
445b39c5158Smillert           DBM_ckFilter(arg, filter_fetch_value,"filter_fetch_value") ;      \
446b39c5158Smillert       }                                                                     \
447b39c5158Smillert     }
448b39c5158Smillert 
449b39c5158Smillert #define OutputKey(arg, name)                                          \
450b39c5158Smillert     { if (RETVAL == 0)                                                \
451b39c5158Smillert       {                                                               \
452b39c5158Smillert           SvGETMAGIC(arg) ;                                           \
453b39c5158Smillert           if (db->type != DB_RECNO) {                                 \
454b39c5158Smillert               my_sv_setpvn(arg, (const char *)name.data, name.size);  \
455b39c5158Smillert           }                                                           \
456b39c5158Smillert           else                                                        \
457b39c5158Smillert               sv_setiv(arg, (I32)*(I32*)name.data - 1);               \
458b39c5158Smillert           TAINT;                                                      \
459b39c5158Smillert           SvTAINTED_on(arg);                                          \
460b39c5158Smillert           SvUTF8_off(arg);                                            \
461b39c5158Smillert           DBM_ckFilter(arg, filter_fetch_key,"filter_fetch_key") ;    \
462b39c5158Smillert       }                                                               \
463b39c5158Smillert     }
464b39c5158Smillert 
46556d68f1eSafresh1 /* Macro err_close only for use in croak_and_free */
46656d68f1eSafresh1 #ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1  or 2 */
46756d68f1eSafresh1 #  define err_close(r)
46856d68f1eSafresh1 #else
46956d68f1eSafresh1 #  define err_close(r) db_close(r)
47056d68f1eSafresh1 #endif
47156d68f1eSafresh1 
47256d68f1eSafresh1 /* Macro croak_and_free only for use in ParseOpenInfo */
47356d68f1eSafresh1 #define croak_and_free(x)                                             \
47456d68f1eSafresh1     do                                                                \
47556d68f1eSafresh1     {                                                                 \
476eac174f2Safresh1         if (RETVAL->dbp) { err_close(RETVAL) ; }                      \
47756d68f1eSafresh1         Safefree(RETVAL);                                             \
47856d68f1eSafresh1         croak(x);                                                     \
47956d68f1eSafresh1     } while (0)
48056d68f1eSafresh1 
481b39c5158Smillert #define my_SvUV32(sv) ((u_int32_t)SvUV(sv))
482b39c5158Smillert 
483b39c5158Smillert #ifdef CAN_PROTOTYPE
484b39c5158Smillert extern void __getBerkeleyDBInfo(void);
485b39c5158Smillert #endif
486b39c5158Smillert 
487b39c5158Smillert /* Internal Global Data */
488b39c5158Smillert 
489b39c5158Smillert #define MY_CXT_KEY "DB_File::_guts" XS_VERSION
490b39c5158Smillert 
491b39c5158Smillert typedef struct {
492b39c5158Smillert     recno_t x_Value;
493b39c5158Smillert     recno_t x_zero;
494b39c5158Smillert     DB_File x_CurrentDB;
495b39c5158Smillert     DBTKEY  x_empty;
496b39c5158Smillert } my_cxt_t;
497b39c5158Smillert 
498b39c5158Smillert START_MY_CXT
499b39c5158Smillert 
500b39c5158Smillert #define Value       (MY_CXT.x_Value)
501b39c5158Smillert #define zero        (MY_CXT.x_zero)
502b39c5158Smillert #define CurrentDB   (MY_CXT.x_CurrentDB)
503b39c5158Smillert #define empty       (MY_CXT.x_empty)
504b39c5158Smillert 
505b39c5158Smillert #define ERR_BUFF "DB_File::Error"
506b39c5158Smillert 
507b39c5158Smillert #ifdef DB_VERSION_MAJOR
508b39c5158Smillert 
509b39c5158Smillert static int
510b39c5158Smillert #ifdef CAN_PROTOTYPE
511b39c5158Smillert db_put(DB_File db, DBTKEY key, DBT value, u_int flags)
512b39c5158Smillert #else
513b39c5158Smillert db_put(db, key, value, flags)
514b39c5158Smillert DB_File     db ;
515b39c5158Smillert DBTKEY      key ;
516b39c5158Smillert DBT         value ;
517b39c5158Smillert u_int       flags ;
518b39c5158Smillert #endif
519b39c5158Smillert {
520b39c5158Smillert     int status ;
521b39c5158Smillert 
522b39c5158Smillert     if (flagSet(flags, R_IAFTER) || flagSet(flags, R_IBEFORE)) {
523b39c5158Smillert         DBC * temp_cursor ;
524b39c5158Smillert         DBT l_key, l_value;
525b39c5158Smillert 
526b39c5158Smillert #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
527b39c5158Smillert         if (((db->dbp)->cursor)(db->dbp, NULL, &temp_cursor) != 0)
528b39c5158Smillert #else
529b39c5158Smillert         if (((db->dbp)->cursor)(db->dbp, NULL, &temp_cursor, 0) != 0)
530b39c5158Smillert #endif
531b39c5158Smillert             return (-1) ;
532b39c5158Smillert 
533b39c5158Smillert         memset(&l_key, 0, sizeof(l_key));
534b39c5158Smillert         l_key.data = key.data;
535b39c5158Smillert         l_key.size = key.size;
536b39c5158Smillert         memset(&l_value, 0, sizeof(l_value));
537b39c5158Smillert         l_value.data = value.data;
538b39c5158Smillert         l_value.size = value.size;
539b39c5158Smillert 
540b39c5158Smillert         if ( temp_cursor->c_get(temp_cursor, &l_key, &l_value, DB_SET) != 0) {
541b39c5158Smillert             (void)temp_cursor->c_close(temp_cursor);
542b39c5158Smillert             return (-1);
543b39c5158Smillert         }
544b39c5158Smillert 
545b39c5158Smillert         status = temp_cursor->c_put(temp_cursor, &key, &value, flags);
546b39c5158Smillert         (void)temp_cursor->c_close(temp_cursor);
547b39c5158Smillert 
548b39c5158Smillert         return (status) ;
549b39c5158Smillert     }
550b39c5158Smillert 
551b39c5158Smillert 
552b39c5158Smillert     if (flagSet(flags, R_CURSOR)) {
553b39c5158Smillert         return ((db->cursor)->c_put)(db->cursor, &key, &value, DB_CURRENT);
554b39c5158Smillert     }
555b39c5158Smillert     if (flagSet(flags, R_SETCURSOR)) {
556b39c5158Smillert         if ((db->dbp)->put(db->dbp, NULL, &key, &value, 0) != 0)
557b39c5158Smillert             return -1 ;
558b39c5158Smillert         return ((db->cursor)->c_get)(db->cursor, &key, &value, DB_SET_RANGE);
559b39c5158Smillert     }
560b39c5158Smillert 
561b39c5158Smillert     return ((db->dbp)->put)(db->dbp, NULL, &key, &value, flags) ;
562b39c5158Smillert 
563b39c5158Smillert }
564b39c5158Smillert 
565b39c5158Smillert #endif /* DB_VERSION_MAJOR */
566b39c5158Smillert 
567b39c5158Smillert static void
568b39c5158Smillert tidyUp(DB_File db)
569b39c5158Smillert {
570b39c5158Smillert     db->aborted = TRUE ;
571b39c5158Smillert }
572b39c5158Smillert 
573b39c5158Smillert 
574b39c5158Smillert static int
5756fb12b70Safresh1 
5766fb12b70Safresh1 #ifdef AT_LEAST_DB_6_0
5776fb12b70Safresh1 #ifdef CAN_PROTOTYPE
5786fb12b70Safresh1 btree_compare(DB * db, const DBT *key1, const DBT *key2, size_t* locp)
5796fb12b70Safresh1 #else
5806fb12b70Safresh1 btree_compare(db, key1, key2, locp)
5816fb12b70Safresh1 DB * db ;
5826fb12b70Safresh1 const DBT * key1 ;
5836fb12b70Safresh1 const DBT * key2 ;
5846fb12b70Safresh1 size_t* locp;
5856fb12b70Safresh1 #endif /* CAN_PROTOTYPE */
5866fb12b70Safresh1 
5876fb12b70Safresh1 #else /* Berkeley DB < 6.0 */
588b39c5158Smillert #ifdef AT_LEAST_DB_3_2
589b39c5158Smillert 
590b39c5158Smillert #ifdef CAN_PROTOTYPE
591b39c5158Smillert btree_compare(DB * db, const DBT *key1, const DBT *key2)
592b39c5158Smillert #else
593b39c5158Smillert btree_compare(db, key1, key2)
594b39c5158Smillert DB        * db ;
595b39c5158Smillert const DBT * key1 ;
596b39c5158Smillert const DBT * key2 ;
597b39c5158Smillert #endif /* CAN_PROTOTYPE */
598b39c5158Smillert 
599b39c5158Smillert #else /* Berkeley DB < 3.2 */
600b39c5158Smillert 
601b39c5158Smillert #ifdef CAN_PROTOTYPE
602b39c5158Smillert btree_compare(const DBT *key1, const DBT *key2)
603b39c5158Smillert #else
604b39c5158Smillert btree_compare(key1, key2)
605b39c5158Smillert const DBT * key1 ;
606b39c5158Smillert const DBT * key2 ;
607b39c5158Smillert #endif
608b39c5158Smillert 
609b39c5158Smillert #endif
6106fb12b70Safresh1 #endif
611b39c5158Smillert 
612b39c5158Smillert {
613b39c5158Smillert #ifdef dTHX
614b39c5158Smillert     dTHX;
615b39c5158Smillert #endif
616b39c5158Smillert     dSP ;
617b39c5158Smillert     dMY_CXT ;
618b39c5158Smillert     void * data1, * data2 ;
619b39c5158Smillert     int retval ;
620b39c5158Smillert     int count ;
621b39c5158Smillert 
622b8851fccSafresh1 #ifdef AT_LEAST_DB_3_2
623b8851fccSafresh1     PERL_UNUSED_ARG(db);
624b8851fccSafresh1 #endif
6259f11ffb7Safresh1 #ifdef AT_LEAST_DB_6_0
6269f11ffb7Safresh1     PERL_UNUSED_ARG(locp);
6279f11ffb7Safresh1 #endif
628b39c5158Smillert 
629b39c5158Smillert     if (CurrentDB->in_compare) {
630b39c5158Smillert         tidyUp(CurrentDB);
631b39c5158Smillert         croak ("DB_File btree_compare: recursion detected\n") ;
632b39c5158Smillert     }
633b39c5158Smillert 
634b39c5158Smillert     data1 = (char *) key1->data ;
635b39c5158Smillert     data2 = (char *) key2->data ;
636b39c5158Smillert 
637b39c5158Smillert #ifndef newSVpvn
638b39c5158Smillert     /* As newSVpv will assume that the data pointer is a null terminated C
639b39c5158Smillert        string if the size parameter is 0, make sure that data points to an
640b39c5158Smillert        empty string if the length is 0
641b39c5158Smillert     */
642b39c5158Smillert     if (key1->size == 0)
643b39c5158Smillert         data1 = "" ;
644b39c5158Smillert     if (key2->size == 0)
645b39c5158Smillert         data2 = "" ;
646b39c5158Smillert #endif
647b39c5158Smillert 
648b39c5158Smillert     ENTER ;
649b39c5158Smillert     SAVETMPS;
650b39c5158Smillert     SAVESPTR(CurrentDB);
651b39c5158Smillert     CurrentDB->in_compare = FALSE;
652b39c5158Smillert     SAVEINT(CurrentDB->in_compare);
653b39c5158Smillert     CurrentDB->in_compare = TRUE;
654b39c5158Smillert 
655b39c5158Smillert     PUSHMARK(SP) ;
656b39c5158Smillert     EXTEND(SP,2) ;
657b39c5158Smillert     PUSHs(sv_2mortal(newSVpvn((const char*)data1,key1->size)));
658b39c5158Smillert     PUSHs(sv_2mortal(newSVpvn((const char*)data2,key2->size)));
659b39c5158Smillert     PUTBACK ;
660b39c5158Smillert 
661b39c5158Smillert     count = perl_call_sv(CurrentDB->compare, G_SCALAR);
662b39c5158Smillert 
663b39c5158Smillert     SPAGAIN ;
664b39c5158Smillert 
665b39c5158Smillert     if (count != 1){
666b39c5158Smillert         tidyUp(CurrentDB);
667b39c5158Smillert         croak ("DB_File btree_compare: expected 1 return value from compare sub, got %d\n", count) ;
668b39c5158Smillert     }
669b39c5158Smillert 
670b39c5158Smillert     retval = POPi ;
671b39c5158Smillert 
672b39c5158Smillert     PUTBACK ;
673b39c5158Smillert     FREETMPS ;
674b39c5158Smillert     LEAVE ;
675b39c5158Smillert 
676b39c5158Smillert     return (retval) ;
677b39c5158Smillert 
678b39c5158Smillert }
679b39c5158Smillert 
680b39c5158Smillert static DB_Prefix_t
681b39c5158Smillert #ifdef AT_LEAST_DB_3_2
682b39c5158Smillert 
683b39c5158Smillert #ifdef CAN_PROTOTYPE
684b39c5158Smillert btree_prefix(DB * db, const DBT *key1, const DBT *key2)
685b39c5158Smillert #else
686b39c5158Smillert btree_prefix(db, key1, key2)
687b39c5158Smillert Db * db ;
688b39c5158Smillert const DBT * key1 ;
689b39c5158Smillert const DBT * key2 ;
690b39c5158Smillert #endif
691b39c5158Smillert 
692b39c5158Smillert #else /* Berkeley DB < 3.2 */
693b39c5158Smillert 
694b39c5158Smillert #ifdef CAN_PROTOTYPE
695b39c5158Smillert btree_prefix(const DBT *key1, const DBT *key2)
696b39c5158Smillert #else
697b39c5158Smillert btree_prefix(key1, key2)
698b39c5158Smillert const DBT * key1 ;
699b39c5158Smillert const DBT * key2 ;
700b39c5158Smillert #endif
701b39c5158Smillert 
702b39c5158Smillert #endif
703b39c5158Smillert {
704b39c5158Smillert #ifdef dTHX
705b39c5158Smillert     dTHX;
706b39c5158Smillert #endif
707b39c5158Smillert     dSP ;
708b39c5158Smillert     dMY_CXT ;
709b39c5158Smillert     char * data1, * data2 ;
710b39c5158Smillert     int retval ;
711b39c5158Smillert     int count ;
712b39c5158Smillert 
713b8851fccSafresh1 #ifdef AT_LEAST_DB_3_2
714b8851fccSafresh1     PERL_UNUSED_ARG(db);
715b8851fccSafresh1 #endif
716b8851fccSafresh1 
717b39c5158Smillert     if (CurrentDB->in_prefix){
718b39c5158Smillert         tidyUp(CurrentDB);
719b39c5158Smillert         croak ("DB_File btree_prefix: recursion detected\n") ;
720b39c5158Smillert     }
721b39c5158Smillert 
722b39c5158Smillert     data1 = (char *) key1->data ;
723b39c5158Smillert     data2 = (char *) key2->data ;
724b39c5158Smillert 
725b39c5158Smillert #ifndef newSVpvn
726b39c5158Smillert     /* As newSVpv will assume that the data pointer is a null terminated C
727b39c5158Smillert        string if the size parameter is 0, make sure that data points to an
728b39c5158Smillert        empty string if the length is 0
729b39c5158Smillert     */
730b39c5158Smillert     if (key1->size == 0)
731b39c5158Smillert         data1 = "" ;
732b39c5158Smillert     if (key2->size == 0)
733b39c5158Smillert         data2 = "" ;
734b39c5158Smillert #endif
735b39c5158Smillert 
736b39c5158Smillert     ENTER ;
737b39c5158Smillert     SAVETMPS;
738b39c5158Smillert     SAVESPTR(CurrentDB);
739b39c5158Smillert     CurrentDB->in_prefix = FALSE;
740b39c5158Smillert     SAVEINT(CurrentDB->in_prefix);
741b39c5158Smillert     CurrentDB->in_prefix = TRUE;
742b39c5158Smillert 
743b39c5158Smillert     PUSHMARK(SP) ;
744b39c5158Smillert     EXTEND(SP,2) ;
745b39c5158Smillert     PUSHs(sv_2mortal(newSVpvn(data1,key1->size)));
746b39c5158Smillert     PUSHs(sv_2mortal(newSVpvn(data2,key2->size)));
747b39c5158Smillert     PUTBACK ;
748b39c5158Smillert 
749b39c5158Smillert     count = perl_call_sv(CurrentDB->prefix, G_SCALAR);
750b39c5158Smillert 
751b39c5158Smillert     SPAGAIN ;
752b39c5158Smillert 
753b39c5158Smillert     if (count != 1){
754b39c5158Smillert         tidyUp(CurrentDB);
755b39c5158Smillert         croak ("DB_File btree_prefix: expected 1 return value from prefix sub, got %d\n", count) ;
756b39c5158Smillert     }
757b39c5158Smillert 
758b39c5158Smillert     retval = POPi ;
759b39c5158Smillert 
760b39c5158Smillert     PUTBACK ;
761b39c5158Smillert     FREETMPS ;
762b39c5158Smillert     LEAVE ;
763b39c5158Smillert 
764b39c5158Smillert     return (retval) ;
765b39c5158Smillert }
766b39c5158Smillert 
767b39c5158Smillert 
768b39c5158Smillert #ifdef BERKELEY_DB_1
769b39c5158Smillert #    define HASH_CB_SIZE_TYPE size_t
770b39c5158Smillert #else
771b39c5158Smillert #    define HASH_CB_SIZE_TYPE u_int32_t
772b39c5158Smillert #endif
773b39c5158Smillert 
774b39c5158Smillert static DB_Hash_t
775b39c5158Smillert #ifdef AT_LEAST_DB_3_2
776b39c5158Smillert 
777b39c5158Smillert #ifdef CAN_PROTOTYPE
778b39c5158Smillert hash_cb(DB * db, const void *data, u_int32_t size)
779b39c5158Smillert #else
780b39c5158Smillert hash_cb(db, data, size)
781b39c5158Smillert DB * db ;
782b39c5158Smillert const void * data ;
783b39c5158Smillert HASH_CB_SIZE_TYPE size ;
784b39c5158Smillert #endif
785b39c5158Smillert 
786b39c5158Smillert #else /* Berkeley DB < 3.2 */
787b39c5158Smillert 
788b39c5158Smillert #ifdef CAN_PROTOTYPE
789b39c5158Smillert hash_cb(const void *data, HASH_CB_SIZE_TYPE size)
790b39c5158Smillert #else
791b39c5158Smillert hash_cb(data, size)
792b39c5158Smillert const void * data ;
793b39c5158Smillert HASH_CB_SIZE_TYPE size ;
794b39c5158Smillert #endif
795b39c5158Smillert 
796b39c5158Smillert #endif
797b39c5158Smillert {
798b39c5158Smillert #ifdef dTHX
799b39c5158Smillert     dTHX;
800b39c5158Smillert #endif
801b39c5158Smillert     dSP ;
802b39c5158Smillert     dMY_CXT;
803b39c5158Smillert     int retval = 0;
804b39c5158Smillert     int count ;
805b39c5158Smillert 
806b8851fccSafresh1 #ifdef AT_LEAST_DB_3_2
807b8851fccSafresh1     PERL_UNUSED_ARG(db);
808b8851fccSafresh1 #endif
809b8851fccSafresh1 
810b39c5158Smillert     if (CurrentDB->in_hash){
811b39c5158Smillert         tidyUp(CurrentDB);
812b39c5158Smillert         croak ("DB_File hash callback: recursion detected\n") ;
813b39c5158Smillert     }
814b39c5158Smillert 
815b39c5158Smillert #ifndef newSVpvn
816b39c5158Smillert     if (size == 0)
817b39c5158Smillert         data = "" ;
818b39c5158Smillert #endif
819b39c5158Smillert 
820b39c5158Smillert      /* DGH - Next two lines added to fix corrupted stack problem */
821b39c5158Smillert     ENTER ;
822b39c5158Smillert     SAVETMPS;
823b39c5158Smillert     SAVESPTR(CurrentDB);
824b39c5158Smillert     CurrentDB->in_hash = FALSE;
825b39c5158Smillert     SAVEINT(CurrentDB->in_hash);
826b39c5158Smillert     CurrentDB->in_hash = TRUE;
827b39c5158Smillert 
828b39c5158Smillert     PUSHMARK(SP) ;
829b39c5158Smillert 
830b39c5158Smillert 
831b39c5158Smillert     XPUSHs(sv_2mortal(newSVpvn((char*)data,size)));
832b39c5158Smillert     PUTBACK ;
833b39c5158Smillert 
834b39c5158Smillert     count = perl_call_sv(CurrentDB->hash, G_SCALAR);
835b39c5158Smillert 
836b39c5158Smillert     SPAGAIN ;
837b39c5158Smillert 
838b39c5158Smillert     if (count != 1){
839b39c5158Smillert         tidyUp(CurrentDB);
840b39c5158Smillert         croak ("DB_File hash_cb: expected 1 return value from hash sub, got %d\n", count) ;
841b39c5158Smillert     }
842b39c5158Smillert 
843b39c5158Smillert     retval = POPi ;
844b39c5158Smillert 
845b39c5158Smillert     PUTBACK ;
846b39c5158Smillert     FREETMPS ;
847b39c5158Smillert     LEAVE ;
848b39c5158Smillert 
849b39c5158Smillert     return (retval) ;
850b39c5158Smillert }
851b39c5158Smillert 
852b39c5158Smillert #ifdef WANT_ERROR
853b39c5158Smillert 
854b39c5158Smillert static void
855b39c5158Smillert #ifdef AT_LEAST_DB_4_3
856b39c5158Smillert db_errcall_cb(const DB_ENV* dbenv, const char * db_errpfx, const char * buffer)
857b39c5158Smillert #else
858b39c5158Smillert db_errcall_cb(const char * db_errpfx, char * buffer)
859b39c5158Smillert #endif
860b39c5158Smillert {
861b39c5158Smillert #ifdef dTHX
862b39c5158Smillert     dTHX;
863b39c5158Smillert #endif
864b39c5158Smillert     SV * sv = perl_get_sv(ERR_BUFF, FALSE) ;
865b8851fccSafresh1 #ifdef AT_LEAST_DB_4_3
866b8851fccSafresh1     PERL_UNUSED_ARG(dbenv);
867b8851fccSafresh1 #endif
868b39c5158Smillert     if (sv) {
869b39c5158Smillert         if (db_errpfx)
870b39c5158Smillert             sv_setpvf(sv, "%s: %s", db_errpfx, buffer) ;
871b39c5158Smillert         else
872b39c5158Smillert             sv_setpv(sv, buffer) ;
873b39c5158Smillert     }
874b39c5158Smillert }
875b39c5158Smillert #endif
876b39c5158Smillert 
877b39c5158Smillert #if defined(TRACE) && defined(BERKELEY_DB_1_OR_2)
878b39c5158Smillert 
879b39c5158Smillert static void
880b39c5158Smillert #ifdef CAN_PROTOTYPE
881b39c5158Smillert PrintHash(INFO *hash)
882b39c5158Smillert #else
883b39c5158Smillert PrintHash(hash)
884b39c5158Smillert INFO * hash ;
885b39c5158Smillert #endif
886b39c5158Smillert {
887b39c5158Smillert     printf ("HASH Info\n") ;
888b39c5158Smillert     printf ("  hash      = %s\n",
889b39c5158Smillert             (hash->db_HA_hash != NULL ? "redefined" : "default")) ;
890b39c5158Smillert     printf ("  bsize     = %d\n", hash->db_HA_bsize) ;
891b39c5158Smillert     printf ("  ffactor   = %d\n", hash->db_HA_ffactor) ;
892b39c5158Smillert     printf ("  nelem     = %d\n", hash->db_HA_nelem) ;
893b39c5158Smillert     printf ("  cachesize = %d\n", hash->db_HA_cachesize) ;
894b39c5158Smillert     printf ("  lorder    = %d\n", hash->db_HA_lorder) ;
895b39c5158Smillert 
896b39c5158Smillert }
897b39c5158Smillert 
898b39c5158Smillert static void
899b39c5158Smillert #ifdef CAN_PROTOTYPE
900b39c5158Smillert PrintRecno(INFO *recno)
901b39c5158Smillert #else
902b39c5158Smillert PrintRecno(recno)
903b39c5158Smillert INFO * recno ;
904b39c5158Smillert #endif
905b39c5158Smillert {
906b39c5158Smillert     printf ("RECNO Info\n") ;
907b39c5158Smillert     printf ("  flags     = %d\n", recno->db_RE_flags) ;
908b39c5158Smillert     printf ("  cachesize = %d\n", recno->db_RE_cachesize) ;
909b39c5158Smillert     printf ("  psize     = %d\n", recno->db_RE_psize) ;
910b39c5158Smillert     printf ("  lorder    = %d\n", recno->db_RE_lorder) ;
911b39c5158Smillert     printf ("  reclen    = %lu\n", (unsigned long)recno->db_RE_reclen) ;
912b39c5158Smillert     printf ("  bval      = %d 0x%x\n", recno->db_RE_bval, recno->db_RE_bval) ;
913b39c5158Smillert     printf ("  bfname    = %d [%s]\n", recno->db_RE_bfname, recno->db_RE_bfname) ;
914b39c5158Smillert }
915b39c5158Smillert 
916b39c5158Smillert static void
917b39c5158Smillert #ifdef CAN_PROTOTYPE
918b39c5158Smillert PrintBtree(INFO *btree)
919b39c5158Smillert #else
920b39c5158Smillert PrintBtree(btree)
921b39c5158Smillert INFO * btree ;
922b39c5158Smillert #endif
923b39c5158Smillert {
924b39c5158Smillert     printf ("BTREE Info\n") ;
925b39c5158Smillert     printf ("  compare    = %s\n",
926b39c5158Smillert             (btree->db_BT_compare ? "redefined" : "default")) ;
927b39c5158Smillert     printf ("  prefix     = %s\n",
928b39c5158Smillert             (btree->db_BT_prefix ? "redefined" : "default")) ;
929b39c5158Smillert     printf ("  flags      = %d\n", btree->db_BT_flags) ;
930b39c5158Smillert     printf ("  cachesize  = %d\n", btree->db_BT_cachesize) ;
931b39c5158Smillert     printf ("  psize      = %d\n", btree->db_BT_psize) ;
932b39c5158Smillert #ifndef DB_VERSION_MAJOR
933b39c5158Smillert     printf ("  maxkeypage = %d\n", btree->db_BT_maxkeypage) ;
934b39c5158Smillert     printf ("  minkeypage = %d\n", btree->db_BT_minkeypage) ;
935b39c5158Smillert #endif
936b39c5158Smillert     printf ("  lorder     = %d\n", btree->db_BT_lorder) ;
937b39c5158Smillert }
938b39c5158Smillert 
939b39c5158Smillert #else
940b39c5158Smillert 
941b39c5158Smillert #define PrintRecno(recno)
942b39c5158Smillert #define PrintHash(hash)
943b39c5158Smillert #define PrintBtree(btree)
944b39c5158Smillert 
945b39c5158Smillert #endif /* TRACE */
946b39c5158Smillert 
947b39c5158Smillert 
948b39c5158Smillert static I32
949b39c5158Smillert #ifdef CAN_PROTOTYPE
950b39c5158Smillert GetArrayLength(pTHX_ DB_File db)
951b39c5158Smillert #else
952b39c5158Smillert GetArrayLength(db)
953b39c5158Smillert DB_File db ;
954b39c5158Smillert #endif
955b39c5158Smillert {
956b39c5158Smillert     DBT     key ;
957b39c5158Smillert     DBT     value ;
958b39c5158Smillert     int     RETVAL ;
959b39c5158Smillert 
960b39c5158Smillert     DBT_clear(key) ;
961b39c5158Smillert     DBT_clear(value) ;
962b39c5158Smillert     RETVAL = do_SEQ(db, key, value, R_LAST) ;
963b39c5158Smillert     if (RETVAL == 0)
964b39c5158Smillert         RETVAL = *(I32 *)key.data ;
965b39c5158Smillert     else /* No key means empty file */
966b39c5158Smillert         RETVAL = 0 ;
967b39c5158Smillert 
968b39c5158Smillert     return ((I32)RETVAL) ;
969b39c5158Smillert }
970b39c5158Smillert 
971b39c5158Smillert static recno_t
972b39c5158Smillert #ifdef CAN_PROTOTYPE
973b39c5158Smillert GetRecnoKey(pTHX_ DB_File db, I32 value)
974b39c5158Smillert #else
975b39c5158Smillert GetRecnoKey(db, value)
976b39c5158Smillert DB_File  db ;
977b39c5158Smillert I32      value ;
978b39c5158Smillert #endif
979b39c5158Smillert {
980b39c5158Smillert     if (value < 0) {
981b39c5158Smillert         /* Get the length of the array */
982b39c5158Smillert         I32 length = GetArrayLength(aTHX_ db) ;
983b39c5158Smillert 
984b39c5158Smillert         /* check for attempt to write before start of array */
985b39c5158Smillert         if (length + value + 1 <= 0) {
986b39c5158Smillert             tidyUp(db);
987b39c5158Smillert             croak("Modification of non-creatable array value attempted, subscript %ld", (long)value) ;
988b39c5158Smillert         }
989b39c5158Smillert 
990b39c5158Smillert         value = length + value + 1 ;
991b39c5158Smillert     }
992b39c5158Smillert     else
993b39c5158Smillert         ++ value ;
994b39c5158Smillert 
995b39c5158Smillert     return value ;
996b39c5158Smillert }
997b39c5158Smillert 
998b39c5158Smillert 
999b39c5158Smillert static DB_File
1000b39c5158Smillert #ifdef CAN_PROTOTYPE
1001b39c5158Smillert ParseOpenInfo(pTHX_ int isHASH, char *name, int flags, int mode, SV *sv)
1002b39c5158Smillert #else
1003b39c5158Smillert ParseOpenInfo(isHASH, name, flags, mode, sv)
1004b39c5158Smillert int    isHASH ;
1005b39c5158Smillert char * name ;
1006b39c5158Smillert int    flags ;
1007b39c5158Smillert int    mode ;
1008b39c5158Smillert SV *   sv ;
1009b39c5158Smillert #endif
1010b39c5158Smillert {
1011b39c5158Smillert 
1012b39c5158Smillert #ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1  or 2 */
1013b39c5158Smillert 
1014b39c5158Smillert     SV **   svp;
1015b39c5158Smillert     HV *    action ;
1016b39c5158Smillert     DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
1017b39c5158Smillert     void *  openinfo = NULL ;
1018b39c5158Smillert     INFO    * info  = &RETVAL->info ;
1019b39c5158Smillert     STRLEN  n_a;
1020b39c5158Smillert     dMY_CXT;
1021b39c5158Smillert 
1022b39c5158Smillert #ifdef TRACE
1023b39c5158Smillert     printf("In ParseOpenInfo name=[%s] flags=[%d] mode=[%d] SV NULL=[%d]\n",
1024b39c5158Smillert             name, flags, mode, sv == NULL) ;
1025b39c5158Smillert #endif
1026b39c5158Smillert     Zero(RETVAL, 1, DB_File_type) ;
1027b39c5158Smillert 
1028b39c5158Smillert     /* Default to HASH */
1029b39c5158Smillert     RETVAL->filtering = 0 ;
1030b39c5158Smillert     RETVAL->filter_fetch_key = RETVAL->filter_store_key =
1031b39c5158Smillert     RETVAL->filter_fetch_value = RETVAL->filter_store_value =
1032b39c5158Smillert     RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
1033b39c5158Smillert     RETVAL->type = DB_HASH ;
1034b39c5158Smillert 
1035b39c5158Smillert      /* DGH - Next line added to avoid SEGV on existing hash DB */
1036b39c5158Smillert     CurrentDB = RETVAL;
1037b39c5158Smillert 
1038b39c5158Smillert     /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */
1039b39c5158Smillert     RETVAL->in_memory = (name == NULL) ;
1040b39c5158Smillert 
1041b39c5158Smillert     if (sv)
1042b39c5158Smillert     {
1043b39c5158Smillert         if (! SvROK(sv) )
104456d68f1eSafresh1             croak_and_free("type parameter is not a reference") ;
1045b39c5158Smillert 
1046b39c5158Smillert         svp  = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
1047b39c5158Smillert         if (svp && SvOK(*svp))
1048b39c5158Smillert             action  = (HV*) SvRV(*svp) ;
1049b39c5158Smillert         else
105056d68f1eSafresh1             croak_and_free("internal error") ;
1051b39c5158Smillert 
1052b39c5158Smillert         if (sv_isa(sv, "DB_File::HASHINFO"))
1053b39c5158Smillert         {
1054b39c5158Smillert 
1055b39c5158Smillert             if (!isHASH)
105656d68f1eSafresh1                 croak_and_free("DB_File can only tie an associative array to a DB_HASH database") ;
1057b39c5158Smillert 
1058b39c5158Smillert             RETVAL->type = DB_HASH ;
1059b39c5158Smillert             openinfo = (void*)info ;
1060b39c5158Smillert 
1061b39c5158Smillert             svp = hv_fetch(action, "hash", 4, FALSE);
1062b39c5158Smillert 
1063b39c5158Smillert             if (svp && SvOK(*svp))
1064b39c5158Smillert             {
1065b39c5158Smillert                 info->db_HA_hash = hash_cb ;
1066b39c5158Smillert                 RETVAL->hash = newSVsv(*svp) ;
1067b39c5158Smillert             }
1068b39c5158Smillert             else
1069b39c5158Smillert                 info->db_HA_hash = NULL ;
1070b39c5158Smillert 
1071b39c5158Smillert             svp = hv_fetch(action, "ffactor", 7, FALSE);
1072b39c5158Smillert             info->db_HA_ffactor = svp ? SvIV(*svp) : 0;
1073b39c5158Smillert 
1074b39c5158Smillert             svp = hv_fetch(action, "nelem", 5, FALSE);
1075b39c5158Smillert             info->db_HA_nelem = svp ? SvIV(*svp) : 0;
1076b39c5158Smillert 
1077b39c5158Smillert             svp = hv_fetch(action, "bsize", 5, FALSE);
1078b39c5158Smillert             info->db_HA_bsize = svp ? SvIV(*svp) : 0;
1079b39c5158Smillert 
1080b39c5158Smillert             svp = hv_fetch(action, "cachesize", 9, FALSE);
1081b39c5158Smillert             info->db_HA_cachesize = svp ? SvIV(*svp) : 0;
1082b39c5158Smillert 
1083b39c5158Smillert             svp = hv_fetch(action, "lorder", 6, FALSE);
1084b39c5158Smillert             info->db_HA_lorder = svp ? SvIV(*svp) : 0;
1085b39c5158Smillert 
1086b39c5158Smillert             PrintHash(info) ;
1087b39c5158Smillert         }
1088b39c5158Smillert         else if (sv_isa(sv, "DB_File::BTREEINFO"))
1089b39c5158Smillert         {
1090b39c5158Smillert             if (!isHASH)
109156d68f1eSafresh1                 croak_and_free("DB_File can only tie an associative array to a DB_BTREE database");
1092b39c5158Smillert 
1093b39c5158Smillert             RETVAL->type = DB_BTREE ;
1094b39c5158Smillert             openinfo = (void*)info ;
1095b39c5158Smillert 
1096b39c5158Smillert             svp = hv_fetch(action, "compare", 7, FALSE);
1097b39c5158Smillert             if (svp && SvOK(*svp))
1098b39c5158Smillert             {
1099b39c5158Smillert                 info->db_BT_compare = btree_compare ;
1100b39c5158Smillert                 RETVAL->compare = newSVsv(*svp) ;
1101b39c5158Smillert             }
1102b39c5158Smillert             else
1103b39c5158Smillert                 info->db_BT_compare = NULL ;
1104b39c5158Smillert 
1105b39c5158Smillert             svp = hv_fetch(action, "prefix", 6, FALSE);
1106b39c5158Smillert             if (svp && SvOK(*svp))
1107b39c5158Smillert             {
1108b39c5158Smillert                 info->db_BT_prefix = btree_prefix ;
1109b39c5158Smillert                 RETVAL->prefix = newSVsv(*svp) ;
1110b39c5158Smillert             }
1111b39c5158Smillert             else
1112b39c5158Smillert                 info->db_BT_prefix = NULL ;
1113b39c5158Smillert 
1114b39c5158Smillert             svp = hv_fetch(action, "flags", 5, FALSE);
1115b39c5158Smillert             info->db_BT_flags = svp ? SvIV(*svp) : 0;
1116b39c5158Smillert 
1117b39c5158Smillert             svp = hv_fetch(action, "cachesize", 9, FALSE);
1118b39c5158Smillert             info->db_BT_cachesize = svp ? SvIV(*svp) : 0;
1119b39c5158Smillert 
1120b39c5158Smillert #ifndef DB_VERSION_MAJOR
1121b39c5158Smillert             svp = hv_fetch(action, "minkeypage", 10, FALSE);
1122b39c5158Smillert             info->btree.minkeypage = svp ? SvIV(*svp) : 0;
1123b39c5158Smillert 
1124b39c5158Smillert             svp = hv_fetch(action, "maxkeypage", 10, FALSE);
1125b39c5158Smillert             info->btree.maxkeypage = svp ? SvIV(*svp) : 0;
1126b39c5158Smillert #endif
1127b39c5158Smillert 
1128b39c5158Smillert             svp = hv_fetch(action, "psize", 5, FALSE);
1129b39c5158Smillert             info->db_BT_psize = svp ? SvIV(*svp) : 0;
1130b39c5158Smillert 
1131b39c5158Smillert             svp = hv_fetch(action, "lorder", 6, FALSE);
1132b39c5158Smillert             info->db_BT_lorder = svp ? SvIV(*svp) : 0;
1133b39c5158Smillert 
1134b39c5158Smillert             PrintBtree(info) ;
1135b39c5158Smillert 
1136b39c5158Smillert         }
1137b39c5158Smillert         else if (sv_isa(sv, "DB_File::RECNOINFO"))
1138b39c5158Smillert         {
1139b39c5158Smillert             if (isHASH)
114056d68f1eSafresh1                 croak_and_free("DB_File can only tie an array to a DB_RECNO database");
1141b39c5158Smillert 
1142b39c5158Smillert             RETVAL->type = DB_RECNO ;
1143b39c5158Smillert             openinfo = (void *)info ;
1144b39c5158Smillert 
1145b39c5158Smillert             info->db_RE_flags = 0 ;
1146b39c5158Smillert 
1147b39c5158Smillert             svp = hv_fetch(action, "flags", 5, FALSE);
1148b39c5158Smillert             info->db_RE_flags = (u_long) (svp ? SvIV(*svp) : 0);
1149b39c5158Smillert 
1150b39c5158Smillert             svp = hv_fetch(action, "reclen", 6, FALSE);
1151b39c5158Smillert             info->db_RE_reclen = (size_t) (svp ? SvIV(*svp) : 0);
1152b39c5158Smillert 
1153b39c5158Smillert             svp = hv_fetch(action, "cachesize", 9, FALSE);
1154b39c5158Smillert             info->db_RE_cachesize = (u_int) (svp ? SvIV(*svp) : 0);
1155b39c5158Smillert 
1156b39c5158Smillert             svp = hv_fetch(action, "psize", 5, FALSE);
1157b39c5158Smillert             info->db_RE_psize = (u_int) (svp ? SvIV(*svp) : 0);
1158b39c5158Smillert 
1159b39c5158Smillert             svp = hv_fetch(action, "lorder", 6, FALSE);
1160b39c5158Smillert             info->db_RE_lorder = (int) (svp ? SvIV(*svp) : 0);
1161b39c5158Smillert 
1162b39c5158Smillert #ifdef DB_VERSION_MAJOR
1163b39c5158Smillert             info->re_source = name ;
1164b39c5158Smillert             name = NULL ;
1165b39c5158Smillert #endif
1166b39c5158Smillert             svp = hv_fetch(action, "bfname", 6, FALSE);
1167b39c5158Smillert             if (svp && SvOK(*svp)) {
1168b39c5158Smillert                 char * ptr = SvPV(*svp,n_a) ;
1169b39c5158Smillert #ifdef DB_VERSION_MAJOR
1170b39c5158Smillert                 name = (char*) n_a ? ptr : NULL ;
1171b39c5158Smillert #else
1172b39c5158Smillert                 info->db_RE_bfname = (char*) (n_a ? ptr : NULL) ;
1173b39c5158Smillert #endif
1174b39c5158Smillert             }
1175b39c5158Smillert             else
1176b39c5158Smillert #ifdef DB_VERSION_MAJOR
1177b39c5158Smillert                name = NULL ;
1178b39c5158Smillert #else
1179b39c5158Smillert                info->db_RE_bfname = NULL ;
1180b39c5158Smillert #endif
1181b39c5158Smillert 
1182b39c5158Smillert             svp = hv_fetch(action, "bval", 4, FALSE);
1183b39c5158Smillert #ifdef DB_VERSION_MAJOR
1184b39c5158Smillert             if (svp && SvOK(*svp))
1185b39c5158Smillert             {
1186b39c5158Smillert                 int value ;
1187b39c5158Smillert                 if (SvPOK(*svp))
1188b39c5158Smillert                     value = (int)*SvPV(*svp, n_a) ;
1189b39c5158Smillert                 else
1190b39c5158Smillert                     value = SvIV(*svp) ;
1191b39c5158Smillert 
1192b39c5158Smillert                 if (info->flags & DB_FIXEDLEN) {
1193b39c5158Smillert                     info->re_pad = value ;
1194b39c5158Smillert                     info->flags |= DB_PAD ;
1195b39c5158Smillert                 }
1196b39c5158Smillert                 else {
1197b39c5158Smillert                     info->re_delim = value ;
1198b39c5158Smillert                     info->flags |= DB_DELIMITER ;
1199b39c5158Smillert                 }
1200b39c5158Smillert 
1201b39c5158Smillert             }
1202b39c5158Smillert #else
1203b39c5158Smillert             if (svp && SvOK(*svp))
1204b39c5158Smillert             {
1205b39c5158Smillert                 if (SvPOK(*svp))
1206b39c5158Smillert                     info->db_RE_bval = (u_char)*SvPV(*svp, n_a) ;
1207b39c5158Smillert                 else
1208b39c5158Smillert                     info->db_RE_bval = (u_char)(unsigned long) SvIV(*svp) ;
1209b39c5158Smillert                 DB_flags(info->flags, DB_DELIMITER) ;
1210b39c5158Smillert 
1211b39c5158Smillert             }
1212b39c5158Smillert             else
1213b39c5158Smillert             {
1214b39c5158Smillert                 if (info->db_RE_flags & R_FIXEDLEN)
1215b39c5158Smillert                     info->db_RE_bval = (u_char) ' ' ;
1216b39c5158Smillert                 else
1217b39c5158Smillert                     info->db_RE_bval = (u_char) '\n' ;
1218b39c5158Smillert                 DB_flags(info->flags, DB_DELIMITER) ;
1219b39c5158Smillert             }
1220b39c5158Smillert #endif
1221b39c5158Smillert 
1222b39c5158Smillert #ifdef DB_RENUMBER
1223b39c5158Smillert             info->flags |= DB_RENUMBER ;
1224b39c5158Smillert #endif
1225b39c5158Smillert 
1226b39c5158Smillert             PrintRecno(info) ;
1227b39c5158Smillert         }
1228b39c5158Smillert         else
122956d68f1eSafresh1             croak_and_free("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
1230b39c5158Smillert     }
1231b39c5158Smillert 
1232b39c5158Smillert 
1233b39c5158Smillert     /* OS2 Specific Code */
1234b39c5158Smillert #ifdef OS2
1235b39c5158Smillert #ifdef __EMX__
1236b39c5158Smillert     flags |= O_BINARY;
1237b39c5158Smillert #endif /* __EMX__ */
1238b39c5158Smillert #endif /* OS2 */
1239b39c5158Smillert 
1240b39c5158Smillert #ifdef DB_VERSION_MAJOR
1241b39c5158Smillert 
1242b39c5158Smillert     {
1243b39c5158Smillert         int     Flags = 0 ;
1244b39c5158Smillert         int     status ;
1245b39c5158Smillert 
1246b39c5158Smillert         /* Map 1.x flags to 2.x flags */
1247b39c5158Smillert         if ((flags & O_CREAT) == O_CREAT)
1248b39c5158Smillert             Flags |= DB_CREATE ;
1249b39c5158Smillert 
1250b39c5158Smillert #if O_RDONLY == 0
1251b39c5158Smillert         if (flags == O_RDONLY)
1252b39c5158Smillert #else
1253b39c5158Smillert         if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR)
1254b39c5158Smillert #endif
1255b39c5158Smillert             Flags |= DB_RDONLY ;
1256b39c5158Smillert 
1257b39c5158Smillert #ifdef O_TRUNC
1258b39c5158Smillert         if ((flags & O_TRUNC) == O_TRUNC)
1259b39c5158Smillert             Flags |= DB_TRUNCATE ;
1260b39c5158Smillert #endif
1261b39c5158Smillert 
1262b39c5158Smillert         status = db_open(name, RETVAL->type, Flags, mode, NULL, (DB_INFO*)openinfo, &RETVAL->dbp) ;
1263b39c5158Smillert         if (status == 0)
1264b39c5158Smillert #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
1265b39c5158Smillert             status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor) ;
1266b39c5158Smillert #else
126756d68f1eSafresh1             status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor, 0) ;
1268b39c5158Smillert #endif
1269b39c5158Smillert 
1270b39c5158Smillert         if (status)
1271b39c5158Smillert              RETVAL->dbp = NULL ;
1272b39c5158Smillert     }
1273b39c5158Smillert #else
1274b39c5158Smillert 
1275b39c5158Smillert #if defined(DB_LIBRARY_COMPATIBILITY_API) && DB_VERSION_MAJOR > 2
1276b39c5158Smillert     RETVAL->dbp = __db185_open(name, flags, mode, RETVAL->type, openinfo) ;
1277b39c5158Smillert #else
1278b39c5158Smillert     RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ;
1279b39c5158Smillert #endif /* DB_LIBRARY_COMPATIBILITY_API */
1280b39c5158Smillert 
1281b39c5158Smillert #endif
1282b39c5158Smillert 
1283b39c5158Smillert     return (RETVAL) ;
1284b39c5158Smillert 
1285b39c5158Smillert #else /* Berkeley DB Version > 2 */
1286b39c5158Smillert 
1287b39c5158Smillert     SV **   svp;
1288b39c5158Smillert     HV *    action ;
1289b39c5158Smillert     DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
1290b39c5158Smillert     DB *    dbp ;
1291b39c5158Smillert     STRLEN  n_a;
1292b39c5158Smillert     int     status ;
1293b39c5158Smillert     dMY_CXT;
1294b39c5158Smillert 
129556d68f1eSafresh1     Trace(("In ParseOpenInfo name=[%s] flags=[%d] mode=[%d] SV NULL=[%d]\n",\
129656d68f1eSafresh1             name, flags, mode, sv == NULL)) ;
1297b39c5158Smillert     Zero(RETVAL, 1, DB_File_type) ;
1298b39c5158Smillert 
1299b39c5158Smillert     /* Default to HASH */
1300b39c5158Smillert     RETVAL->filtering = 0 ;
1301b39c5158Smillert     RETVAL->filter_fetch_key = RETVAL->filter_store_key =
1302b39c5158Smillert     RETVAL->filter_fetch_value = RETVAL->filter_store_value =
1303b39c5158Smillert     RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
1304b39c5158Smillert     RETVAL->type = DB_HASH ;
1305b39c5158Smillert 
1306b39c5158Smillert      /* DGH - Next line added to avoid SEGV on existing hash DB */
1307b39c5158Smillert     CurrentDB = RETVAL;
1308b39c5158Smillert 
1309b39c5158Smillert     /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */
1310b39c5158Smillert     RETVAL->in_memory = (name == NULL) ;
1311b39c5158Smillert 
1312b39c5158Smillert     status = db_create(&RETVAL->dbp, NULL,0) ;
131356d68f1eSafresh1     Trace(("db_create returned %d %s\n", status, db_strerror(status))) ;
1314b39c5158Smillert     if (status) {
1315b39c5158Smillert         RETVAL->dbp = NULL ;
1316b39c5158Smillert         return (RETVAL) ;
1317b39c5158Smillert     }
1318b39c5158Smillert     dbp = RETVAL->dbp ;
1319b39c5158Smillert 
1320b39c5158Smillert #ifdef WANT_ERROR
1321b39c5158Smillert     RETVAL->dbp->set_errcall(RETVAL->dbp, db_errcall_cb) ;
1322b39c5158Smillert #endif
1323b39c5158Smillert     if (sv)
1324b39c5158Smillert     {
1325b39c5158Smillert         if (! SvROK(sv) )
132656d68f1eSafresh1             croak_and_free("type parameter is not a reference") ;
1327b39c5158Smillert 
1328b39c5158Smillert         svp  = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
1329b39c5158Smillert         if (svp && SvOK(*svp))
1330b39c5158Smillert             action  = (HV*) SvRV(*svp) ;
1331b39c5158Smillert         else
133256d68f1eSafresh1             croak_and_free("internal error") ;
1333b39c5158Smillert 
1334b39c5158Smillert         if (sv_isa(sv, "DB_File::HASHINFO"))
1335b39c5158Smillert         {
1336b39c5158Smillert 
1337b39c5158Smillert             if (!isHASH)
133856d68f1eSafresh1                 croak_and_free("DB_File can only tie an associative array to a DB_HASH database") ;
1339b39c5158Smillert 
1340b39c5158Smillert             RETVAL->type = DB_HASH ;
1341b39c5158Smillert 
1342b39c5158Smillert             svp = hv_fetch(action, "hash", 4, FALSE);
1343b39c5158Smillert 
1344b39c5158Smillert             if (svp && SvOK(*svp))
1345b39c5158Smillert             {
1346b39c5158Smillert                 (void)dbp->set_h_hash(dbp, hash_cb) ;
1347b39c5158Smillert                 RETVAL->hash = newSVsv(*svp) ;
1348b39c5158Smillert             }
1349b39c5158Smillert 
1350b39c5158Smillert            svp = hv_fetch(action, "ffactor", 7, FALSE);
1351b39c5158Smillert            if (svp)
1352b39c5158Smillert                (void)dbp->set_h_ffactor(dbp, my_SvUV32(*svp)) ;
1353b39c5158Smillert 
1354b39c5158Smillert            svp = hv_fetch(action, "nelem", 5, FALSE);
1355b39c5158Smillert            if (svp)
1356b39c5158Smillert                (void)dbp->set_h_nelem(dbp, my_SvUV32(*svp)) ;
1357b39c5158Smillert 
1358b39c5158Smillert            svp = hv_fetch(action, "bsize", 5, FALSE);
1359b39c5158Smillert            if (svp)
1360b39c5158Smillert                (void)dbp->set_pagesize(dbp, my_SvUV32(*svp));
1361b39c5158Smillert 
1362b39c5158Smillert            svp = hv_fetch(action, "cachesize", 9, FALSE);
1363b39c5158Smillert            if (svp)
1364b39c5158Smillert                (void)dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
1365b39c5158Smillert 
1366b39c5158Smillert            svp = hv_fetch(action, "lorder", 6, FALSE);
1367b39c5158Smillert            if (svp)
1368b39c5158Smillert                (void)dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
1369b39c5158Smillert 
1370b39c5158Smillert            PrintHash(info) ;
1371b39c5158Smillert         }
1372b39c5158Smillert         else if (sv_isa(sv, "DB_File::BTREEINFO"))
1373b39c5158Smillert         {
1374b39c5158Smillert             if (!isHASH)
137556d68f1eSafresh1                 croak_and_free("DB_File can only tie an associative array to a DB_BTREE database");
1376b39c5158Smillert 
1377b39c5158Smillert             RETVAL->type = DB_BTREE ;
1378b39c5158Smillert 
1379b39c5158Smillert             svp = hv_fetch(action, "compare", 7, FALSE);
1380b39c5158Smillert             if (svp && SvOK(*svp))
1381b39c5158Smillert             {
1382b39c5158Smillert                 (void)dbp->set_bt_compare(dbp, btree_compare) ;
1383b39c5158Smillert                 RETVAL->compare = newSVsv(*svp) ;
1384b39c5158Smillert             }
1385b39c5158Smillert 
1386b39c5158Smillert             svp = hv_fetch(action, "prefix", 6, FALSE);
1387b39c5158Smillert             if (svp && SvOK(*svp))
1388b39c5158Smillert             {
1389b39c5158Smillert                 (void)dbp->set_bt_prefix(dbp, btree_prefix) ;
1390b39c5158Smillert                 RETVAL->prefix = newSVsv(*svp) ;
1391b39c5158Smillert             }
1392b39c5158Smillert 
1393b39c5158Smillert            svp = hv_fetch(action, "flags", 5, FALSE);
1394b39c5158Smillert            if (svp)
1395b39c5158Smillert                (void)dbp->set_flags(dbp, my_SvUV32(*svp)) ;
1396b39c5158Smillert 
1397b39c5158Smillert            svp = hv_fetch(action, "cachesize", 9, FALSE);
1398b39c5158Smillert            if (svp)
1399b39c5158Smillert                (void)dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
1400b39c5158Smillert 
1401b39c5158Smillert            svp = hv_fetch(action, "psize", 5, FALSE);
1402b39c5158Smillert            if (svp)
1403b39c5158Smillert                (void)dbp->set_pagesize(dbp, my_SvUV32(*svp)) ;
1404b39c5158Smillert 
1405b39c5158Smillert            svp = hv_fetch(action, "lorder", 6, FALSE);
1406b39c5158Smillert            if (svp)
1407b39c5158Smillert                (void)dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
1408b39c5158Smillert 
1409b39c5158Smillert            PrintBtree(info) ;
1410b39c5158Smillert 
1411b39c5158Smillert         }
1412b39c5158Smillert         else if (sv_isa(sv, "DB_File::RECNOINFO"))
1413b39c5158Smillert         {
1414b39c5158Smillert             int fixed = FALSE ;
1415b39c5158Smillert 
1416b39c5158Smillert             if (isHASH)
141756d68f1eSafresh1                 croak_and_free("DB_File can only tie an array to a DB_RECNO database");
1418b39c5158Smillert 
1419b39c5158Smillert             RETVAL->type = DB_RECNO ;
1420b39c5158Smillert 
1421b39c5158Smillert             svp = hv_fetch(action, "flags", 5, FALSE);
1422b39c5158Smillert             if (svp) {
1423b39c5158Smillert                 int flags = SvIV(*svp) ;
1424b39c5158Smillert                 /* remove FIXDLEN, if present */
1425b39c5158Smillert                 if (flags & DB_FIXEDLEN) {
1426b39c5158Smillert                     fixed = TRUE ;
1427b39c5158Smillert                     flags &= ~DB_FIXEDLEN ;
1428b39c5158Smillert                 }
1429b39c5158Smillert             }
1430b39c5158Smillert 
1431b39c5158Smillert             svp = hv_fetch(action, "cachesize", 9, FALSE);
1432b39c5158Smillert             if (svp) {
1433b39c5158Smillert                 status = dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
1434b39c5158Smillert             }
1435b39c5158Smillert 
1436b39c5158Smillert             svp = hv_fetch(action, "psize", 5, FALSE);
1437b39c5158Smillert             if (svp) {
1438b39c5158Smillert                 status = dbp->set_pagesize(dbp, my_SvUV32(*svp)) ;
1439b39c5158Smillert             }
1440b39c5158Smillert 
1441b39c5158Smillert             svp = hv_fetch(action, "lorder", 6, FALSE);
1442b39c5158Smillert             if (svp) {
1443b39c5158Smillert                 status = dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
1444b39c5158Smillert             }
1445b39c5158Smillert 
1446b39c5158Smillert             svp = hv_fetch(action, "bval", 4, FALSE);
1447b39c5158Smillert             if (svp && SvOK(*svp))
1448b39c5158Smillert             {
1449b39c5158Smillert                 int value ;
1450b39c5158Smillert                 if (SvPOK(*svp))
1451b39c5158Smillert                     value = (int)*SvPV(*svp, n_a) ;
1452b39c5158Smillert                 else
1453b39c5158Smillert                     value = (int)SvIV(*svp) ;
1454b39c5158Smillert 
1455b39c5158Smillert                 if (fixed) {
14569f11ffb7Safresh1                     (void)dbp->set_re_pad(dbp, value) ;
1457b39c5158Smillert                 }
1458b39c5158Smillert                 else {
14599f11ffb7Safresh1                     (void)dbp->set_re_delim(dbp, value) ;
1460b39c5158Smillert                 }
1461b39c5158Smillert 
1462b39c5158Smillert             }
1463b39c5158Smillert 
1464b39c5158Smillert             if (fixed) {
1465b39c5158Smillert                 svp = hv_fetch(action, "reclen", 6, FALSE);
1466b39c5158Smillert                 if (svp) {
1467b39c5158Smillert                     u_int32_t len =  my_SvUV32(*svp) ;
14689f11ffb7Safresh1                     (void)dbp->set_re_len(dbp, len) ;
1469b39c5158Smillert                 }
1470b39c5158Smillert             }
1471b39c5158Smillert 
1472b39c5158Smillert             if (name != NULL) {
14739f11ffb7Safresh1                 (void)dbp->set_re_source(dbp, name) ;
1474b39c5158Smillert                 name = NULL ;
1475b39c5158Smillert             }
1476b39c5158Smillert 
1477b39c5158Smillert             svp = hv_fetch(action, "bfname", 6, FALSE);
1478b39c5158Smillert             if (svp && SvOK(*svp)) {
1479b39c5158Smillert                 char * ptr = SvPV(*svp,n_a) ;
1480b39c5158Smillert                 name = (char*) n_a ? ptr : NULL ;
1481b39c5158Smillert             }
1482b39c5158Smillert             else
1483b39c5158Smillert                 name = NULL ;
1484b39c5158Smillert 
1485b39c5158Smillert 
14869f11ffb7Safresh1             (void)dbp->set_flags(dbp, (u_int32_t)DB_RENUMBER) ;
1487b39c5158Smillert 
1488b39c5158Smillert             if (flags){
1489b39c5158Smillert                 (void)dbp->set_flags(dbp, (u_int32_t)flags) ;
1490b39c5158Smillert             }
1491b39c5158Smillert             PrintRecno(info) ;
1492b39c5158Smillert         }
1493b39c5158Smillert         else
149456d68f1eSafresh1             croak_and_free("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
1495b39c5158Smillert     }
1496b39c5158Smillert 
1497b39c5158Smillert     {
1498b39c5158Smillert         u_int32_t   Flags = 0 ;
1499b39c5158Smillert         int     status ;
1500b39c5158Smillert 
1501b39c5158Smillert         /* Map 1.x flags to 3.x flags */
1502b39c5158Smillert         if ((flags & O_CREAT) == O_CREAT)
1503b39c5158Smillert             Flags |= DB_CREATE ;
1504b39c5158Smillert 
1505b39c5158Smillert #if O_RDONLY == 0
1506b39c5158Smillert         if (flags == O_RDONLY)
1507b39c5158Smillert #else
1508b39c5158Smillert         if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR)
1509b39c5158Smillert #endif
1510b39c5158Smillert             Flags |= DB_RDONLY ;
1511b39c5158Smillert 
1512b39c5158Smillert #ifdef O_TRUNC
1513b39c5158Smillert         if ((flags & O_TRUNC) == O_TRUNC)
1514b39c5158Smillert             Flags |= DB_TRUNCATE ;
1515b39c5158Smillert #endif
1516b39c5158Smillert 
1517b39c5158Smillert #ifdef AT_LEAST_DB_4_4
1518b39c5158Smillert         /* need this for recno */
1519b39c5158Smillert         if ((flags & O_TRUNC) == O_TRUNC)
1520b39c5158Smillert             Flags |= DB_CREATE ;
1521b39c5158Smillert #endif
1522b39c5158Smillert 
1523b39c5158Smillert #ifdef AT_LEAST_DB_4_1
1524b39c5158Smillert         status = (RETVAL->dbp->open)(RETVAL->dbp, NULL, name, NULL, RETVAL->type,
1525b39c5158Smillert                     Flags, mode) ;
1526b39c5158Smillert #else
1527b39c5158Smillert         status = (RETVAL->dbp->open)(RETVAL->dbp, name, NULL, RETVAL->type,
1528b39c5158Smillert                     Flags, mode) ;
1529b39c5158Smillert #endif
153056d68f1eSafresh1         Trace(("open returned %d %s\n", status, db_strerror(status))) ;
1531b39c5158Smillert 
1532b39c5158Smillert         if (status == 0) {
1533b39c5158Smillert 
153456d68f1eSafresh1             status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor, 0) ;
153556d68f1eSafresh1             Trace(("cursor returned %d %s\n", status, db_strerror(status))) ;
1536b39c5158Smillert         }
1537b39c5158Smillert 
1538b39c5158Smillert         if (status)
15396fb12b70Safresh1         {
15406fb12b70Safresh1             db_close(RETVAL); /* close **dbp handle to prevent mem.leak */
1541b39c5158Smillert             RETVAL->dbp = NULL ;
15426fb12b70Safresh1         }
1543b39c5158Smillert     }
1544b39c5158Smillert 
1545b39c5158Smillert     return (RETVAL) ;
1546b39c5158Smillert 
1547b39c5158Smillert #endif /* Berkeley DB Version > 2 */
1548b39c5158Smillert 
1549b39c5158Smillert } /* ParseOpenInfo */
1550b39c5158Smillert 
1551b39c5158Smillert 
1552b39c5158Smillert #include "constants.h"
1553b39c5158Smillert 
1554b39c5158Smillert MODULE = DB_File    PACKAGE = DB_File   PREFIX = db_
1555b39c5158Smillert 
1556b39c5158Smillert INCLUDE: constants.xs
1557b39c5158Smillert 
1558b39c5158Smillert BOOT:
1559b39c5158Smillert   {
1560b39c5158Smillert #ifdef dTHX
1561b39c5158Smillert     dTHX;
1562b39c5158Smillert #endif
1563b39c5158Smillert #ifdef WANT_ERROR
1564b39c5158Smillert     SV * sv_err = perl_get_sv(ERR_BUFF, GV_ADD|GV_ADDMULTI) ;
1565b39c5158Smillert #endif
1566b39c5158Smillert     MY_CXT_INIT;
1567b8851fccSafresh1 #ifdef WANT_ERROR
1568b8851fccSafresh1     PERL_UNUSED_VAR(sv_err); /* huh? we just retrieved it... */
1569b8851fccSafresh1 #endif
1570b39c5158Smillert     __getBerkeleyDBInfo() ;
1571b39c5158Smillert 
1572b39c5158Smillert     DBT_clear(empty) ;
1573b39c5158Smillert     empty.data = &zero ;
1574b39c5158Smillert     empty.size =  sizeof(recno_t) ;
1575b39c5158Smillert   }
1576b39c5158Smillert 
1577b39c5158Smillert 
1578b39c5158Smillert 
1579b39c5158Smillert DB_File
1580b39c5158Smillert db_DoTie_(isHASH, dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_HASH)
1581b39c5158Smillert     int     isHASH
1582b39c5158Smillert     char *      dbtype
1583b39c5158Smillert     int     flags
1584b39c5158Smillert     int     mode
1585b39c5158Smillert     CODE:
1586b39c5158Smillert     {
1587b39c5158Smillert         char *  name = (char *) NULL ;
1588b39c5158Smillert         SV *    sv = (SV *) NULL ;
1589b39c5158Smillert         STRLEN  n_a;
159056d68f1eSafresh1         Trace(("In db_DoTie_\n"));
1591b39c5158Smillert 
1592b39c5158Smillert         if (items >= 3 && SvOK(ST(2)))
1593b39c5158Smillert             name = (char*) SvPV(ST(2), n_a) ;
1594b39c5158Smillert 
1595b39c5158Smillert         if (items == 6)
1596b39c5158Smillert             sv = ST(5) ;
1597b39c5158Smillert 
1598b39c5158Smillert         RETVAL = ParseOpenInfo(aTHX_ isHASH, name, flags, mode, sv) ;
15996fb12b70Safresh1         Trace(("db_DoTie_ %p\n", RETVAL));
1600b39c5158Smillert         if (RETVAL->dbp == NULL) {
1601b39c5158Smillert             Safefree(RETVAL);
1602b39c5158Smillert             RETVAL = NULL ;
1603b39c5158Smillert         }
1604b39c5158Smillert     }
1605b39c5158Smillert     OUTPUT:
1606b39c5158Smillert         RETVAL
1607b39c5158Smillert 
1608b39c5158Smillert int
1609b39c5158Smillert db_DESTROY(db)
1610b39c5158Smillert     DB_File     db
1611b39c5158Smillert     PREINIT:
1612b39c5158Smillert       dMY_CXT;
1613b39c5158Smillert     INIT:
1614b39c5158Smillert       CurrentDB = db ;
1615b39c5158Smillert       Trace(("DESTROY %p\n", db));
1616b39c5158Smillert     CLEANUP:
1617b39c5158Smillert       Trace(("DESTROY %p done\n", db));
1618b39c5158Smillert       if (db->hash)
1619b39c5158Smillert         SvREFCNT_dec(db->hash) ;
1620b39c5158Smillert       if (db->compare)
1621b39c5158Smillert         SvREFCNT_dec(db->compare) ;
1622b39c5158Smillert       if (db->prefix)
1623b39c5158Smillert         SvREFCNT_dec(db->prefix) ;
1624b39c5158Smillert       if (db->filter_fetch_key)
1625b39c5158Smillert         SvREFCNT_dec(db->filter_fetch_key) ;
1626b39c5158Smillert       if (db->filter_store_key)
1627b39c5158Smillert         SvREFCNT_dec(db->filter_store_key) ;
1628b39c5158Smillert       if (db->filter_fetch_value)
1629b39c5158Smillert         SvREFCNT_dec(db->filter_fetch_value) ;
1630b39c5158Smillert       if (db->filter_store_value)
1631b39c5158Smillert         SvREFCNT_dec(db->filter_store_value) ;
1632b39c5158Smillert       safefree(db) ;
1633b39c5158Smillert #ifdef DB_VERSION_MAJOR
1634b39c5158Smillert       if (RETVAL > 0)
1635b39c5158Smillert         RETVAL = -1 ;
1636b39c5158Smillert #endif
1637b39c5158Smillert 
1638b39c5158Smillert 
1639b39c5158Smillert int
1640b39c5158Smillert db_DELETE(db, key, flags=0)
1641b39c5158Smillert     DB_File     db
1642b39c5158Smillert     DBTKEY      key
1643b39c5158Smillert     u_int       flags
1644b39c5158Smillert     PREINIT:
1645b39c5158Smillert       dMY_CXT;
1646b39c5158Smillert     INIT:
1647b8851fccSafresh1       (void)flags;
1648b39c5158Smillert       CurrentDB = db ;
1649b39c5158Smillert 
1650b39c5158Smillert 
1651b39c5158Smillert int
1652b39c5158Smillert db_EXISTS(db, key)
1653b39c5158Smillert     DB_File     db
1654b39c5158Smillert     DBTKEY      key
1655b39c5158Smillert     PREINIT:
1656b39c5158Smillert       dMY_CXT;
1657b39c5158Smillert     CODE:
1658b39c5158Smillert     {
1659b39c5158Smillert       DBT       value ;
1660b39c5158Smillert 
1661b39c5158Smillert       DBT_clear(value) ;
1662b39c5158Smillert       CurrentDB = db ;
1663b39c5158Smillert       RETVAL = (((db->dbp)->get)(db->dbp, TXN &key, &value, 0) == 0) ;
1664b39c5158Smillert     }
1665b39c5158Smillert     OUTPUT:
1666b39c5158Smillert       RETVAL
1667b39c5158Smillert 
1668b39c5158Smillert void
1669b39c5158Smillert db_FETCH(db, key, flags=0)
1670b39c5158Smillert     DB_File     db
1671b39c5158Smillert     DBTKEY      key
1672b39c5158Smillert     u_int       flags
1673b39c5158Smillert     PREINIT:
1674b39c5158Smillert       dMY_CXT ;
1675b39c5158Smillert       int RETVAL ;
1676b39c5158Smillert     CODE:
1677b39c5158Smillert     {
1678b39c5158Smillert         DBT     value ;
1679b39c5158Smillert 
1680b39c5158Smillert         DBT_clear(value) ;
1681b39c5158Smillert         CurrentDB = db ;
1682b39c5158Smillert         RETVAL = db_get(db, key, value, flags) ;
1683b39c5158Smillert         ST(0) = sv_newmortal();
1684b39c5158Smillert         OutputValue(ST(0), value)
1685b39c5158Smillert     }
1686b39c5158Smillert 
1687b39c5158Smillert int
1688b39c5158Smillert db_STORE(db, key, value, flags=0)
1689b39c5158Smillert     DB_File     db
1690b39c5158Smillert     DBTKEY      key
1691b39c5158Smillert     DBT     value
1692b39c5158Smillert     u_int       flags
1693b39c5158Smillert     PREINIT:
1694b39c5158Smillert       dMY_CXT;
1695b39c5158Smillert     INIT:
1696b8851fccSafresh1       (void)flags;
1697b39c5158Smillert       CurrentDB = db ;
1698b39c5158Smillert 
1699b39c5158Smillert 
1700b39c5158Smillert void
1701b39c5158Smillert db_FIRSTKEY(db)
1702b39c5158Smillert     DB_File     db
1703b39c5158Smillert     PREINIT:
1704b39c5158Smillert       dMY_CXT ;
1705b39c5158Smillert       int RETVAL ;
1706b39c5158Smillert     CODE:
1707b39c5158Smillert     {
1708b39c5158Smillert         DBTKEY  key ;
1709b39c5158Smillert         DBT     value ;
1710b39c5158Smillert 
1711b39c5158Smillert         DBT_clear(key) ;
1712b39c5158Smillert         DBT_clear(value) ;
1713b39c5158Smillert         CurrentDB = db ;
1714b39c5158Smillert         RETVAL = do_SEQ(db, key, value, R_FIRST) ;
1715b39c5158Smillert         ST(0) = sv_newmortal();
1716b39c5158Smillert         OutputKey(ST(0), key) ;
1717b39c5158Smillert     }
1718b39c5158Smillert 
1719b39c5158Smillert void
1720b39c5158Smillert db_NEXTKEY(db, key)
1721b39c5158Smillert     DB_File     db
1722b39c5158Smillert     DBTKEY      key = NO_INIT
1723b39c5158Smillert     PREINIT:
1724b39c5158Smillert       dMY_CXT ;
1725b39c5158Smillert       int RETVAL ;
1726b39c5158Smillert     CODE:
1727b39c5158Smillert     {
1728b39c5158Smillert         DBT     value ;
1729b39c5158Smillert 
1730b39c5158Smillert         DBT_clear(key) ;
1731b39c5158Smillert         DBT_clear(value) ;
1732b39c5158Smillert         CurrentDB = db ;
1733b39c5158Smillert         RETVAL = do_SEQ(db, key, value, R_NEXT) ;
1734b39c5158Smillert         ST(0) = sv_newmortal();
1735b39c5158Smillert         OutputKey(ST(0), key) ;
1736b39c5158Smillert     }
1737b39c5158Smillert 
1738b39c5158Smillert #
1739b39c5158Smillert # These would be nice for RECNO
1740b39c5158Smillert #
1741b39c5158Smillert 
1742b39c5158Smillert int
1743b39c5158Smillert unshift(db, ...)
1744b39c5158Smillert     DB_File     db
1745b39c5158Smillert     ALIAS:      UNSHIFT = 1
1746b39c5158Smillert     PREINIT:
1747b39c5158Smillert       dMY_CXT;
1748b39c5158Smillert     CODE:
1749b39c5158Smillert     {
1750b39c5158Smillert         DBTKEY  key ;
1751b39c5158Smillert         DBT     value ;
1752b39c5158Smillert         int     i ;
1753b39c5158Smillert         int     One ;
1754b39c5158Smillert         STRLEN  n_a;
1755b39c5158Smillert 
1756b39c5158Smillert         DBT_clear(key) ;
1757b39c5158Smillert         DBT_clear(value) ;
1758b39c5158Smillert         CurrentDB = db ;
1759b39c5158Smillert #ifdef DB_VERSION_MAJOR
1760b39c5158Smillert         /* get the first value */
1761b39c5158Smillert         RETVAL = do_SEQ(db, key, value, DB_FIRST) ;
1762b39c5158Smillert         RETVAL = 0 ;
1763b39c5158Smillert #else
1764b39c5158Smillert         RETVAL = -1 ;
1765b39c5158Smillert #endif
1766b39c5158Smillert         for (i = items-1 ; i > 0 ; --i)
1767b39c5158Smillert         {
1768b39c5158Smillert             DBM_ckFilter(ST(i), filter_store_value, "filter_store_value");
1769b39c5158Smillert             value.data = SvPVbyte(ST(i), n_a) ;
1770b39c5158Smillert             value.size = n_a ;
1771b39c5158Smillert             One = 1 ;
1772b39c5158Smillert             key.data = &One ;
1773b39c5158Smillert             key.size = sizeof(int) ;
1774b39c5158Smillert #ifdef DB_VERSION_MAJOR
1775b39c5158Smillert             RETVAL = (db->cursor->c_put)(db->cursor, &key, &value, DB_BEFORE) ;
1776b39c5158Smillert #else
1777b39c5158Smillert             RETVAL = (db->dbp->put)(db->dbp, &key, &value, R_IBEFORE) ;
1778b39c5158Smillert #endif
1779b39c5158Smillert             if (RETVAL != 0)
1780b39c5158Smillert                 break;
1781b39c5158Smillert         }
1782b39c5158Smillert     }
1783b39c5158Smillert     OUTPUT:
1784b39c5158Smillert         RETVAL
1785b39c5158Smillert 
1786b39c5158Smillert void
1787b39c5158Smillert pop(db)
1788b39c5158Smillert     DB_File     db
1789b39c5158Smillert     PREINIT:
1790b39c5158Smillert       dMY_CXT;
1791b39c5158Smillert     ALIAS:      POP = 1
1792b39c5158Smillert     PREINIT:
1793b39c5158Smillert       I32 RETVAL;
1794b39c5158Smillert     CODE:
1795b39c5158Smillert     {
1796b39c5158Smillert         DBTKEY  key ;
1797b39c5158Smillert         DBT     value ;
1798b39c5158Smillert 
1799b39c5158Smillert         DBT_clear(key) ;
1800b39c5158Smillert         DBT_clear(value) ;
1801b39c5158Smillert         CurrentDB = db ;
1802b39c5158Smillert 
1803b39c5158Smillert         /* First get the final value */
1804b39c5158Smillert         RETVAL = do_SEQ(db, key, value, R_LAST) ;
1805b39c5158Smillert         ST(0) = sv_newmortal();
1806b39c5158Smillert         /* Now delete it */
1807b39c5158Smillert         if (RETVAL == 0)
1808b39c5158Smillert         {
1809b39c5158Smillert             /* the call to del will trash value, so take a copy now */
1810b39c5158Smillert             OutputValue(ST(0), value) ;
1811b39c5158Smillert             RETVAL = db_del(db, key, R_CURSOR) ;
1812b39c5158Smillert             if (RETVAL != 0)
1813b39c5158Smillert                 sv_setsv(ST(0), &PL_sv_undef);
1814b39c5158Smillert         }
1815b39c5158Smillert     }
1816b39c5158Smillert 
1817b39c5158Smillert void
1818b39c5158Smillert shift(db)
1819b39c5158Smillert     DB_File     db
1820b39c5158Smillert     PREINIT:
1821b39c5158Smillert       dMY_CXT;
1822b39c5158Smillert     ALIAS:      SHIFT = 1
1823b39c5158Smillert     PREINIT:
1824b39c5158Smillert       I32 RETVAL;
1825b39c5158Smillert     CODE:
1826b39c5158Smillert     {
1827b39c5158Smillert         DBT     value ;
1828b39c5158Smillert         DBTKEY  key ;
1829b39c5158Smillert 
1830b39c5158Smillert         DBT_clear(key) ;
1831b39c5158Smillert         DBT_clear(value) ;
1832b39c5158Smillert         CurrentDB = db ;
1833b39c5158Smillert         /* get the first value */
1834b39c5158Smillert         RETVAL = do_SEQ(db, key, value, R_FIRST) ;
1835b39c5158Smillert         ST(0) = sv_newmortal();
1836b39c5158Smillert         /* Now delete it */
1837b39c5158Smillert         if (RETVAL == 0)
1838b39c5158Smillert         {
1839b39c5158Smillert             /* the call to del will trash value, so take a copy now */
1840b39c5158Smillert             OutputValue(ST(0), value) ;
1841b39c5158Smillert             RETVAL = db_del(db, key, R_CURSOR) ;
1842b39c5158Smillert             if (RETVAL != 0)
1843b39c5158Smillert                 sv_setsv (ST(0), &PL_sv_undef) ;
1844b39c5158Smillert         }
1845b39c5158Smillert     }
1846b39c5158Smillert 
1847b39c5158Smillert 
1848b39c5158Smillert I32
1849b39c5158Smillert push(db, ...)
1850b39c5158Smillert     DB_File     db
1851b39c5158Smillert     PREINIT:
1852b39c5158Smillert       dMY_CXT;
1853b39c5158Smillert     ALIAS:      PUSH = 1
1854b39c5158Smillert     CODE:
1855b39c5158Smillert     {
1856b39c5158Smillert         DBTKEY  key ;
1857b39c5158Smillert         DBT     value ;
1858b39c5158Smillert         DB *    Db = db->dbp ;
1859b39c5158Smillert         int     i ;
1860b39c5158Smillert         STRLEN  n_a;
1861b39c5158Smillert         int     keyval ;
1862b39c5158Smillert 
1863b39c5158Smillert         DBT_flags(key) ;
1864b39c5158Smillert         DBT_flags(value) ;
1865b39c5158Smillert         CurrentDB = db ;
1866b39c5158Smillert         /* Set the Cursor to the Last element */
1867b39c5158Smillert         RETVAL = do_SEQ(db, key, value, R_LAST) ;
1868b39c5158Smillert #ifndef DB_VERSION_MAJOR
1869b39c5158Smillert         if (RETVAL >= 0)
1870b39c5158Smillert #endif
1871b39c5158Smillert         {
1872b39c5158Smillert             if (RETVAL == 0)
1873b39c5158Smillert                 keyval = *(int*)key.data ;
1874b39c5158Smillert             else
1875b39c5158Smillert                 keyval = 0 ;
1876b39c5158Smillert             for (i = 1 ; i < items ; ++i)
1877b39c5158Smillert             {
1878b39c5158Smillert                 DBM_ckFilter(ST(i), filter_store_value, "filter_store_value");
1879b39c5158Smillert                 value.data = SvPVbyte(ST(i), n_a) ;
1880b39c5158Smillert                 value.size = n_a ;
1881b39c5158Smillert                 ++ keyval ;
1882b39c5158Smillert                 key.data = &keyval ;
1883b39c5158Smillert                 key.size = sizeof(int) ;
1884b39c5158Smillert                 RETVAL = (Db->put)(Db, TXN &key, &value, 0) ;
1885b39c5158Smillert                 if (RETVAL != 0)
1886b39c5158Smillert                     break;
1887b39c5158Smillert             }
1888b39c5158Smillert         }
1889b39c5158Smillert     }
1890b39c5158Smillert     OUTPUT:
1891b39c5158Smillert         RETVAL
1892b39c5158Smillert 
1893b39c5158Smillert I32
1894b39c5158Smillert length(db)
1895b39c5158Smillert     DB_File     db
1896b39c5158Smillert     PREINIT:
1897b39c5158Smillert       dMY_CXT;
1898b39c5158Smillert     ALIAS:      FETCHSIZE = 1
1899b39c5158Smillert     CODE:
1900b39c5158Smillert         CurrentDB = db ;
1901b39c5158Smillert         RETVAL = GetArrayLength(aTHX_ db) ;
1902b39c5158Smillert     OUTPUT:
1903b39c5158Smillert         RETVAL
1904b39c5158Smillert 
1905b39c5158Smillert 
1906b39c5158Smillert #
1907b39c5158Smillert # Now provide an interface to the rest of the DB functionality
1908b39c5158Smillert #
1909b39c5158Smillert 
1910b39c5158Smillert int
1911b39c5158Smillert db_del(db, key, flags=0)
1912b39c5158Smillert     DB_File     db
1913b39c5158Smillert     DBTKEY      key
1914b39c5158Smillert     u_int       flags
1915b39c5158Smillert     PREINIT:
1916b39c5158Smillert       dMY_CXT;
1917b39c5158Smillert     CODE:
1918b39c5158Smillert       CurrentDB = db ;
1919b39c5158Smillert       RETVAL = db_del(db, key, flags) ;
1920b39c5158Smillert #ifdef DB_VERSION_MAJOR
1921b39c5158Smillert       if (RETVAL > 0)
1922b39c5158Smillert         RETVAL = -1 ;
1923b39c5158Smillert       else if (RETVAL == DB_NOTFOUND)
1924b39c5158Smillert         RETVAL = 1 ;
1925b39c5158Smillert #endif
1926b39c5158Smillert     OUTPUT:
1927b39c5158Smillert       RETVAL
1928b39c5158Smillert 
1929b39c5158Smillert 
1930b39c5158Smillert int
1931b39c5158Smillert db_get(db, key, value, flags=0)
1932b39c5158Smillert     DB_File     db
1933b39c5158Smillert     DBTKEY      key
1934b39c5158Smillert     DBT     value = NO_INIT
1935b39c5158Smillert     u_int       flags
1936b39c5158Smillert     PREINIT:
1937b39c5158Smillert       dMY_CXT;
1938b39c5158Smillert     CODE:
1939b39c5158Smillert       CurrentDB = db ;
1940b39c5158Smillert       DBT_clear(value) ;
1941b39c5158Smillert       RETVAL = db_get(db, key, value, flags) ;
1942b39c5158Smillert #ifdef DB_VERSION_MAJOR
1943b39c5158Smillert       if (RETVAL > 0)
1944b39c5158Smillert         RETVAL = -1 ;
1945b39c5158Smillert       else if (RETVAL == DB_NOTFOUND)
1946b39c5158Smillert         RETVAL = 1 ;
1947b39c5158Smillert #endif
1948b39c5158Smillert     OUTPUT:
1949b39c5158Smillert       RETVAL
1950b39c5158Smillert       value
1951b39c5158Smillert 
1952b39c5158Smillert int
1953b39c5158Smillert db_put(db, key, value, flags=0)
1954b39c5158Smillert     DB_File     db
1955b39c5158Smillert     DBTKEY      key
1956b39c5158Smillert     DBT     value
1957b39c5158Smillert     u_int       flags
1958b39c5158Smillert     PREINIT:
1959b39c5158Smillert       dMY_CXT;
1960b39c5158Smillert     CODE:
1961b39c5158Smillert       CurrentDB = db ;
1962b39c5158Smillert       RETVAL = db_put(db, key, value, flags) ;
1963b39c5158Smillert #ifdef DB_VERSION_MAJOR
1964b39c5158Smillert       if (RETVAL > 0)
1965b39c5158Smillert         RETVAL = -1 ;
1966b39c5158Smillert       else if (RETVAL == DB_KEYEXIST)
1967b39c5158Smillert         RETVAL = 1 ;
1968b39c5158Smillert #endif
1969b39c5158Smillert     OUTPUT:
1970b39c5158Smillert       RETVAL
1971b39c5158Smillert       key       if (flagSet(flags, R_IAFTER) || flagSet(flags, R_IBEFORE)) OutputKey(ST(1), key);
1972b39c5158Smillert 
1973b39c5158Smillert int
1974b39c5158Smillert db_fd(db)
1975b39c5158Smillert     DB_File     db
1976b39c5158Smillert     PREINIT:
1977b39c5158Smillert       dMY_CXT ;
1978b39c5158Smillert     CODE:
1979b39c5158Smillert       CurrentDB = db ;
1980b39c5158Smillert #ifdef DB_VERSION_MAJOR
1981b39c5158Smillert       RETVAL = -1 ;
1982b39c5158Smillert       {
1983b39c5158Smillert         int status = 0 ;
1984b39c5158Smillert         status = (db->in_memory
1985b39c5158Smillert                   ? -1
1986b39c5158Smillert                   : ((db->dbp)->fd)(db->dbp, &RETVAL) ) ;
1987b39c5158Smillert         if (status != 0)
1988b39c5158Smillert           RETVAL = -1 ;
1989b39c5158Smillert       }
1990b39c5158Smillert #else
1991b39c5158Smillert       RETVAL = (db->in_memory
1992b39c5158Smillert                 ? -1
1993b39c5158Smillert                 : ((db->dbp)->fd)(db->dbp) ) ;
1994b39c5158Smillert #endif
1995b39c5158Smillert     OUTPUT:
1996b39c5158Smillert       RETVAL
1997b39c5158Smillert 
1998b39c5158Smillert int
1999b39c5158Smillert db_sync(db, flags=0)
2000b39c5158Smillert     DB_File     db
2001b39c5158Smillert     u_int       flags
2002b39c5158Smillert     PREINIT:
2003b39c5158Smillert       dMY_CXT;
2004b39c5158Smillert     CODE:
2005b39c5158Smillert       CurrentDB = db ;
2006b39c5158Smillert       RETVAL = db_sync(db, flags) ;
2007b39c5158Smillert #ifdef DB_VERSION_MAJOR
2008b39c5158Smillert       if (RETVAL > 0)
2009b39c5158Smillert         RETVAL = -1 ;
2010b39c5158Smillert #endif
2011b39c5158Smillert     OUTPUT:
2012b39c5158Smillert       RETVAL
2013b39c5158Smillert 
2014b39c5158Smillert 
2015b39c5158Smillert int
2016b39c5158Smillert db_seq(db, key, value, flags)
2017b39c5158Smillert     DB_File     db
2018b39c5158Smillert     DBTKEY      key
2019b39c5158Smillert     DBT     value = NO_INIT
2020b39c5158Smillert     u_int       flags
2021b39c5158Smillert     PREINIT:
2022b39c5158Smillert       dMY_CXT;
2023b39c5158Smillert     CODE:
2024b39c5158Smillert       CurrentDB = db ;
2025b39c5158Smillert       DBT_clear(value) ;
2026b39c5158Smillert       RETVAL = db_seq(db, key, value, flags);
2027b39c5158Smillert #ifdef DB_VERSION_MAJOR
2028b39c5158Smillert       if (RETVAL > 0)
2029b39c5158Smillert         RETVAL = -1 ;
2030b39c5158Smillert       else if (RETVAL == DB_NOTFOUND)
2031b39c5158Smillert         RETVAL = 1 ;
2032b39c5158Smillert #endif
2033b39c5158Smillert     OUTPUT:
2034b39c5158Smillert       RETVAL
2035b39c5158Smillert       key
2036b39c5158Smillert       value
2037b39c5158Smillert 
2038b39c5158Smillert SV *
2039b39c5158Smillert filter_fetch_key(db, code)
2040b39c5158Smillert     DB_File     db
2041b39c5158Smillert     SV *        code
2042b39c5158Smillert     SV *        RETVAL = &PL_sv_undef ;
2043b39c5158Smillert     CODE:
2044b39c5158Smillert         DBM_setFilter(db->filter_fetch_key, code) ;
2045b39c5158Smillert 
2046b39c5158Smillert SV *
2047b39c5158Smillert filter_store_key(db, code)
2048b39c5158Smillert     DB_File     db
2049b39c5158Smillert     SV *        code
2050b39c5158Smillert     SV *        RETVAL = &PL_sv_undef ;
2051b39c5158Smillert     CODE:
2052b39c5158Smillert         DBM_setFilter(db->filter_store_key, code) ;
2053b39c5158Smillert 
2054b39c5158Smillert SV *
2055b39c5158Smillert filter_fetch_value(db, code)
2056b39c5158Smillert     DB_File     db
2057b39c5158Smillert     SV *        code
2058b39c5158Smillert     SV *        RETVAL = &PL_sv_undef ;
2059b39c5158Smillert     CODE:
2060b39c5158Smillert         DBM_setFilter(db->filter_fetch_value, code) ;
2061b39c5158Smillert 
2062b39c5158Smillert SV *
2063b39c5158Smillert filter_store_value(db, code)
2064b39c5158Smillert     DB_File     db
2065b39c5158Smillert     SV *        code
2066b39c5158Smillert     SV *        RETVAL = &PL_sv_undef ;
2067b39c5158Smillert     CODE:
2068b39c5158Smillert         DBM_setFilter(db->filter_store_value, code) ;
2069