COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/eds.e444597.78%965108489.02%119
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
db_dump()12113192.37%10
compress()142360.87%9
db_open()213070.00%9
db_delete_record()495785.96%8
db_compress()435086.00%7
db_create()364383.72%7
db_record_key()51241.67%7
db_select()111861.11%7
check_free_list()222878.57%6
db_replace_data()71353.85%6
db_fetch_record()050.00%5
db_get_recid()172277.27%5
decompress()172277.27%5
db_clear_table()394390.70%4
db_find_key()202483.33%4
db_record_data()131776.47%4
db_table_size()5955.56%4
safe_seek()4850.00%4
equal_string()111478.57%3
get_string()111478.57%3
db_create_table()414297.62%1
db_delete_table()495098.00%1
db_allocate()3232100.00%0
db_cache_clear()44100.00%0
db_close()1818100.00%0
db_current()55100.00%0
db_current_table()22100.00%0
db_free()6363100.00%0
db_get_errors()55100.00%0
db_insert()7979100.00%0
db_record_recid()77100.00%0
db_rename_table()1515100.00%0
db_replace_recid()1717100.00%0
db_select_table()3333100.00%0
db_set_caching()66100.00%0
db_table_list()1414100.00%0
fatal()55100.00%0
get1()22100.00%0
get4()66100.00%0
key_value()33100.00%0
put1()33100.00%0
put4()44100.00%0
putn()33100.00%0
save_keys()99100.00%0
table_find()1616100.00%0
LINE COVERAGE DETAIL
#Executed
1
-- (c) Copyright - See License.txt
2
--
3
--****
4
-- == Euphoria Database (EDS)
5
--
6
-- <>
7
namespace eds
8
9
include std/error.e
10
include std/convert.e
11
include std/io.e
12
include std/filesys.e
13
include std/get.e
14
include std/pretty.e
15
include std/machine.e
16
include std/sequence.e
17
include std/datetime.e
18
include std/text.e
19
include std/math.e
20
21
--****
22
-- === Database File Format
23
--
24
-- ==== Header
25
-- * byte 0: magic number for this file-type: 77
26
-- * byte 1: version number (major)
27
-- * byte 2: version number (minor)
28
-- * byte 3: 4-byte pointer to block of table headers
29
-- * byte 7: number of free blocks
30
-- * byte 11: 4-byte pointer to block of free blocks
31
--
32
-- ==== Block of table headers
33
-- * -4: allocated size of this block (for possible reallocation)
34
-- * 0: number of table headers currently in use
35
-- * 4: table header1
36
-- * 16: table header2
37
-- * 28: etc.
38
--
39
-- ==== Table header
40
-- * 0: pointer to the name of this table
41
-- * 4: total number of records in this table
42
-- * 8: number of blocks of records
43
-- * 12: pointer to the index block for this table
44
--
45
-- There are two levels of pointers. The logical array of key pointers
46
-- is split up across many physical blocks. A single index block
47
-- is used to select the correct small block. This allows
48
-- inserts and deletes to be made without having to shift a
49
-- large number of key pointers. Only one small block needs to
50
-- be adjusted. This is particularly helpful when the table contains
51
-- many thousands of records.
52
--
53
-- ==== Index block
54
-- one per table
55
--
56
-- * -4: allocated size of index block
57
-- * 0: number of records in 1st block of key pointers
58
-- * 4: pointer to 1st block
59
-- * 8: number of records in 2nd " "
60
-- * 12: pointer to 2nd block
61
-- * 16: etc.
62
--
63
-- ==== Block of key pointers
64
-- many per table
65
--
66
-- * -4: allocated size of this block in bytes
67
-- * 0: key pointer 1
68
-- * 4: key pointer 2
69
-- * 8: etc.
70
--
71
-- ==== Free list
72
-- in ascending order of address
73
--
74
-- * -4: allocated size of block of free blocks
75
-- * 0: address of 1st free block
76
-- * 4: size of 1st free block
77
-- * 8: address of 2nd free block
78
-- * 12: size of 2nd free block
79
-- * 16: etc.
80
--
81
-- The key value and the data value for a record are allocated space
82
-- as needed. A pointer to the data value is stored just before the
83
-- key value. Euphoria objects, key and data, are stored in a compact form.
84
--
85
-- All allocated blocks have the size of the block in bytes, stored in the
86
-- four bytes just before the address.
87
88
--****
89
-- === Error Status Constants
90
91
public constant
92
--** Database is OK, not error has occurred.
93101
DB_OK = 0,
94
--** The database could not be opened.
95101
DB_OPEN_FAIL = -1,
96
--** The database could not be created, it already exists.
97101
DB_EXISTS_ALREADY = -2,
98
--** A lock could not be gained on the database.
99101
DB_LOCK_FAIL = -3,
100
--** A fatal error has occurred.
101101
DB_FATAL_FAIL = -404
102
103
--****
104
-- === Lock Type Constants
105
106
public enum
107
--** Do not lock the file.
108101
DB_LOCK_NO = 0,
109
--** Open the database with read-only access.
110101
DB_LOCK_SHARED,
111
--** Open the database with read and write access.
112101
DB_LOCK_EXCLUSIVE
113
114
--****
115
-- === Error Code Constants
116
117
public enum
118
--** Missing 0 terminator
119101
MISSING_END = 900,
120
--** current_db is not set
121101
NO_DATABASE,
122
--** seek() failed.
123101
BAD_SEEK,
124
--** no table was found.
125101
NO_TABLE,
126
--** this table already exists.
127101
DUP_TABLE,
128
--** unknown key_location index was supplied.
129101
BAD_RECNO,
130
--** couldn't insert a new record.
131101
INSERT_FAILED,
132
--** last error code
133101
LAST_ERROR_CODE,
134
--** bad file
135101
BAD_FILE
136
137101
constant DB_MAGIC = 77
138101
constant DB_MAJOR = 4, DB_MINOR = 0 -- database created with Euphoria v4.0
139101
constant SIZEOF_TABLE_HEADER = 16
140101
constant TABLE_HEADERS = 3, FREE_COUNT = 7, FREE_LIST = 11 --, SIZEOF_DATABASE_HEADER = 14
141
142
143
-- initial sizes for various things:
144101
constant INIT_FREE = 5,
145101
INIT_TABLES = 5,
146101
INIT_INDEX = 10,
147101
INIT_RECORDS = 50
148
149101
constant TRUE = 1
150
151101
integer current_db = -1
152101
atom current_table_pos = -1
153101
sequence current_table_name = ""
154101
sequence db_names = {}
155101
sequence db_file_nums = {}
156101
sequence db_lock_methods = {}
157101
integer current_lock = 0
158101
sequence key_pointers = {}
159101
sequence key_cache = {}
160101
sequence cache_index = {}
161101
integer caching_option = 1
162
163
atom void
164
165
166
--****
167
-- === Variables
168
--
169
170
--**
171
-- **Exception handler**\\
172
-- Set this to a valid routine_id value for a procedure that
173
-- will be called whenever the library detects a serious error. You procedure
174
-- will be passed a single text string that describes the error. It may also
175
-- call [[:db_get_errors]] to get more detail about the cause of the error.
176
177
public integer db_fatal_id
178
179101
db_fatal_id = DB_FATAL_FAIL -- Initialized separately from declaration so
180
-- the initial value doesn't show up in docs.
181
182
183101
sequence vLastErrors = {}
184
185
1866
1876
vLastErrors = append(vLastErrors, {errcode, msg, routine_name, parms})
1886
if db_fatal_id >= 0 then
1895
call_proc(db_fatal_id, {sprintf("Error Code %d: %s, from %s", {errcode, msg, routine_name})})
190
end if
1916
end procedure
192
1936
194
-- read 1-byte value at current position in database file
1956
return getc(current_db)
196
end function
197
198
atom mem0, mem1, mem2, mem3
199101
mem0 = allocate(4)
200101
mem1 = mem0 + 1
201101
mem2 = mem0 + 2
202101
mem3 = mem0 + 3
203
20447338
205
-- read 4-byte value at current position in database file
20647338
poke(mem0, getc(current_db))
20747338
poke(mem1, getc(current_db))
20847338
poke(mem2, getc(current_db))
20947338
poke(mem3, getc(current_db))
21047338
return peek4u(mem0)
211
end function
212
21317
214
-- read a 0-terminated string at current position in database file
215
sequence s
216
integer c
217
integer i
218
21917
s = repeat(0, 256)
22017
i = 0
22117
while c with entry do
222109
if c = -1 then
2230
fatal(MISSING_END, "string is missing 0 terminator", "get_string", {where(current_db)})
2240
exit
225
end if
226109
i += 1
227109
if i > length(s) then
2280
s &= repeat(0, 256)
229
end if
230109
s[i] = c
231
entry
232126
c = getc(current_db)
233126
end while
23417
return s[1..i]
235
end function
236
237274
238
-- test if string at current position in database file equals given string
239
integer c
240
integer i
241
242274
i = 0
243274
while c with entry do
2442193
if c = -1 then
2450
fatal(MISSING_END, "string is missing 0 terminator", "equal_string", {where(current_db)})
2460
return DB_FATAL_FAIL
247
end if
2482193
i += 1
2492193
if i > length(target) then
2500
return 0
251
end if
2522193
if target[i] != c then
253199
return 0
254
end if
255
entry
2562268
c = getc(current_db)
2572268
end while
25875
return (i = length(target))
259
end function
260
261
-- Compressed format of Euphoria objects on disk
262
--
263
-- First byte:
264
-- 0..248 -- immediate small integer, -9 to 239
265
-- since small negative integers -9..-1 might be common
266101
constant I2B = 249, -- 2-byte signed integer follows
267101
I3B = 250, -- 3-byte signed integer follows
268101
I4B = 251, -- 4-byte signed integer follows
269101
F4B = 252, -- 4-byte f.p. number follows
270101
F8B = 253, -- 8-byte f.p. number follows
271101
S1B = 254, -- sequence, 1-byte length follows, then elements
272101
S4B = 255 -- sequence, 4-byte length follows, then elements
273
274101
constant MIN1B = -9,
275101
MAX1B = 239,
276101
MIN2B = -power(2, 15),
277101
MAX2B = power(2, 15)-1,
278101
MIN3B = -power(2, 23),
279101
MAX3B = power(2, 23)-1,
280101
MIN4B = -power(2, 31)
281
2825621
283
-- read a compressed Euphoria object from disk
284
-- if c is set, then c is not <= 248
285
sequence s
286
integer len
287
2885621
if c = 0 then
2895619
c = getc(current_db)
2905619
if c < I2B then
2913552
return c + MIN1B
292
end if
293
end if
294
2952069
switch c with fallthru do
296
case I2B then
2971946
return getc(current_db) +
298
#100 * getc(current_db) +
299
MIN2B
300
301
case I3B then
3020
return getc(current_db) +
303
#100 * getc(current_db) +
304
#10000 * getc(current_db) +
305
MIN3B
306
307
case I4B then
3080
return get4() + MIN4B
309
310
case F4B then
3110
return float32_to_atom({getc(current_db), getc(current_db),
312
getc(current_db), getc(current_db)})
313
314
case F8B then
3150
return float64_to_atom({getc(current_db), getc(current_db),
316
getc(current_db), getc(current_db),
317
getc(current_db), getc(current_db),
318
getc(current_db), getc(current_db)})
319
320
case else
321
-- sequence
322123
if c = S1B then
323123
len = getc(current_db)
324
else
3250
len = get4()
326
end if
327123
s = repeat(0, len)
328123
for i = 1 to len do
329
-- in-line small integer for greater speed on strings
3301198
c = getc(current_db)
3311198
if c < I2B then
3321196
s[i] = c + MIN1B
333
else
3342
s[i] = decompress(c)
335
end if
3361198
end for
337123
return s
338
end switch
339
end function
340
3419876
342
-- return the compressed representation of a Euphoria object
343
-- as a sequence of bytes
344
sequence x4, s
345
3469876
if integer(x) then
3479142
if x >= MIN1B and x <= MAX1B then
3488881
return {x - MIN1B}
349
350261
elsif x >= MIN2B and x <= MAX2B then
351261
x -= MIN2B
352261
return {I2B, and_bits(x, #FF), floor(x / #100)}
353
3540
elsif x >= MIN3B and x <= MAX3B then
3550
x -= MIN3B
3560
return {I3B, and_bits(x, #FF), and_bits(floor(x / #100), #FF), floor(x / #10000)}
357
358
else
3590
return I4B & int_to_bytes(x-MIN4B)
360
361
end if
362
363734
elsif atom(x) then
364
-- floating point
3650
x4 = atom_to_float32(x)
3660
if x = float32_to_atom(x4) then
367
-- can represent as 4-byte float
3680
return F4B & x4
369
else
3700
return F8B & atom_to_float64(x)
371
end if
372
373
else
374
-- sequence
375734
if length(x) <= 255 then
376734
s = {S1B, length(x)}
377
else
3780
s = S4B & int_to_bytes(length(x))
379
end if
380734
for i = 1 to length(x) do
3818461
s &= compress(x[i])
3828461
end for
383734
return s
384
end if
385
end function
386
38715
388
-- write 1 byte to current database file
38915
puts(current_db, x)
39015
end procedure
391
392
sequence memseq
393101
memseq = {mem0, 4}
394
3956672
396
-- write 4 bytes to current database file
397
-- x is 32-bits max
3986672
poke4(mem0, x) -- faster than doing divides etc.
3996672
puts(current_db, peek(memseq))
4006672
end procedure
401
4021657
403
-- write a sequence of bytes to current database file
4041657
puts(current_db, s)
4051657
end procedure
406
407222
408
-- seek to a position in the current db file
409222
if current_db = -1 then
4100
fatal(NO_DATABASE, "no current database defined", "safe_seek", {pos})
4110
return
412
end if
413222
if seek(current_db, pos) != 0 then
4140
fatal(BAD_SEEK, "seek to position failed", "safe_seek", {pos})
4150
return
416
end if
417222
end procedure
418
419
--****
420
-- === Routines
421
422
--**
423
-- Fetches the most recent set of errors recorded by the library.
424
--
425
-- Parameters:
426
-- # ##clearing## : if zero the set of errors is not reset, otherwise
427
-- it will be cleared out. The default is to clear the set.
428
--
429
-- Returns:
430
-- A **sequence**, each element is a set of four fields.
431
-- # Error Code.
432
-- # Error Text.
433
-- # Name of library routine that recorded the error.
434
-- # Parameters passed to that routine.
435
--
436
-- Comments:
437
-- * A number of library routines can detect errors. If the routine is a
438
-- function, it usually returns an error code. However, procedures that
439
-- detect an error can't do that. Instead, they record the error details
440
-- and you can query that after calling the library routine.
441
-- * Both functions and procedures that detect errors record the details
442
-- in the ##Last Error Set##, which is fetched by this function.
443
--
444
--
445
-- Example 1:
446
--
447
-- db_replace_data(recno, new_data)
448
-- errs = db_get_errors()
449
-- if length(errs) != 0 then
450
-- display_errors(errs)
451
-- abort(1)
452
-- end if
453
--
454
4557
456
sequence lErrors
457
4587
lErrors = vLastErrors
4597
if clearing then
4607
vLastErrors = {}
461
end if
462
4637
return lErrors
464
end function
465
466
--**
467
-- print the current database in readable form to file fn
468
--
469
-- Parameters:
470
-- # ##fn## : the destination file for printing the current Euphoria database;
471
-- # ##low_level_too## : a boolean. If true, a byte-by-byte binary dump
472
-- is presented as well; otherwise this step is skipped. If omitted,
473
-- //false// is assumed.
474
--
475
-- Errors:
476
-- If the current database is not defined, an error will occur.
477
--
478
-- Comments:
479
-- * All records in all tables are shown.
480
-- * If low_level_too is non-zero,
481
-- then a low-level byte-by-byte dump is also shown. The low-level
482
-- dump will only be meaningful to someone who is familiar
483
-- with the internal format of a Euphoria database.
484
--
485
-- Example 1:
486
--
487
-- if db_open("mydata", DB_LOCK_SHARED) != DB_OK then
488
-- puts(2, "Couldn't open the database!\n")
489
-- abort(1)
490
-- end if
491
-- fn = open("db.txt", "w")
492
-- db_dump(fn) -- Simple output
493
-- db_dump("lowlvl_db.txt", 1) -- Full low-level dump created.
494
--
495
4962
497
-- print an open database in readable form to file fn
498
-- (Note: If you turn database.e into a .dll or .so, you will
499
-- have to use a file name, rather than an open file number.
500
-- All other database.e routines are ok as they are.)
501
integer magic, minor, major
502
integer fn
503
atom tables, ntables, tname, trecords, t_header, tnrecs,
504
key_ptr, data_ptr, size, addr, tindex, fbp
505
object key, data
506
integer c, n, tblocks
507
atom a
508
sequence ll_line
509
integer hi, ci
510
5112
if sequence(file_id) then
5121
fn = open(file_id, "w")
5131
elsif file_id > 0 then
5140
fn = file_id
5150
puts(fn, '\n')
516
else
5171
fn = file_id
518
end if
5192
if fn <= 0 then
5201
fatal( BAD_FILE, "bad file", "db_dump", {file_id, low_level_too})
5211
return
522
end if
523
5241
printf(fn, "Database dump as at %s\n", {datetime:format(now(), "%Y-%m-%d %H:%M:%S")})
5251
safe_seek(0)
5261
if length(vLastErrors) > 0 then return end if
5271
magic = get1()
5281
if magic != DB_MAGIC then
5290
puts(fn, "This is not a Euphoria Database file.\n")
530
else
5311
major = get1()
5321
minor = get1()
5331
printf(fn, "Euphoria Database System Version %d.%d\n\n", {major, minor})
5341
tables = get4()
5351
void = seek(current_db, tables)
5361
ntables = get4()
5371
printf(fn, "The \"%s\" database has %d table",
538
{db_names[eu:find(current_db, db_file_nums)], ntables})
5391
if ntables = 1 then
5400
puts(fn, "\n")
541
else
5421
puts(fn, "s\n")
543
end if
544
end if
545
5461
if low_level_too then
547
-- low level dump: show all bytes in the file
5481
puts(fn, " Disk Dump\nDiskAddr " & repeat('-', 58))
5491
void = seek(current_db, 0)
5501
a = 0
5511
while c >= 0 with entry do
552
553789
if c = -1 then
5540
exit
555
end if
556789
if remainder(a, 16) = 0 then
55750
if a > 0 then
55849
printf(fn, "%s\n", {ll_line})
559
else
5601
puts(fn, '\n')
561
end if
56250
ll_line = repeat(' ', 67)
56350
ll_line[9] = ':'
56450
ll_line[48] = '|'
56550
ll_line[67] = '|'
56650
hi = 11
56750
ci = 50
56850
ll_line[1..8] = sprintf("%08x", a)
569
end if
570789
ll_line[hi .. hi + 1] = sprintf("%02x", c)
571789
hi += 2
572789
if eu:find(hi, {19, 28, 38}) then
573148
hi += 1
574148
if hi = 29 then
57549
hi = 30
576
end if
577
end if
578789
if c > ' ' and c < '~' then
57921
ll_line[ci] = c
580
else
581768
ll_line[ci] = '.'
582
end if
583789
ci += 1
584
585789
a += 1
586
entry
587790
c = getc(current_db)
588790
end while
5891
printf(fn, "%s\n", {ll_line})
5901
puts(fn, repeat('-', 67) & "\n\n")
591
end if
592
593
-- high level dump
5941
void = seek(current_db, 0)
5951
magic = get1()
5961
if magic != DB_MAGIC then
5970
if sequence(file_id) then
5980
close(fn)
599
end if
6000
return
601
end if
602
6031
major = get1()
6041
minor = get1()
605
6061
tables = get4()
6071
if low_level_too then printf(fn, "[tables:#%08x]\n", tables) end if
6081
void = seek(current_db, tables)
6091
ntables = get4()
6101
t_header = where(current_db)
6111
for t = 1 to ntables do
6122
if low_level_too then printf(fn, "\n---------------\n[table header:#%08x]\n", t_header) end if
613
-- display the next table
6142
tname = get4()
6152
tnrecs = get4()
6162
tblocks = get4()
6172
tindex = get4()
6182
if low_level_too then printf(fn, "[table name:#%08x]\n", tname) end if
6192
void = seek(current_db, tname)
6202
printf(fn, "\ntable \"%s\", records:%d indexblks: %d\n\n\n", {get_string(), tnrecs, tblocks})
6212
if tnrecs > 0 then
6221
for b = 1 to tblocks do
6231
if low_level_too then printf(fn, "[table block %d:#%08x]\n", {b, tindex+(b-1)*8}) end if
6241
void = seek(current_db, tindex+(b-1)*8)
6251
tnrecs = get4()
6261
trecords = get4()
6271
if tnrecs > 0 then
6281
printf(fn, "\n--------------------------\nblock #%d, ptrs:%d\n--------------------------\n", {b, tnrecs})
6291
for r = 1 to tnrecs do
630
-- display the next record
6312
if low_level_too then printf(fn, "[record %d:#%08x]\n", {r, trecords+(r-1)*4}) end if
6322
void = seek(current_db, trecords+(r-1)*4)
6332
key_ptr = get4()
6342
if low_level_too then printf(fn, "[key %d:#%08x]\n", {r, key_ptr}) end if
6352
void = seek(current_db, key_ptr)
6362
data_ptr = get4()
6372
key = decompress(0)
6382
puts(fn, " key: ")
6392
pretty_print(fn, key, {2, 2, 8})
6402
puts(fn, '\n')
6412
if low_level_too then printf(fn, "[data %d:#%08x]\n", {r, data_ptr}) end if
6422
void = seek(current_db, data_ptr)
6432
data = decompress(0)
6442
puts(fn, " data: ")
6452
pretty_print(fn, data, {2, 2, 9})
6462
puts(fn, "\n\n")
6472
end for
648
else
6490
printf(fn, "\nblock #%d (empty)\n\n", b)
650
end if
6511
end for
652
end if
6532
t_header += SIZEOF_TABLE_HEADER
6542
void = seek(current_db, t_header)
6552
end for
656
-- show the free list
6571
if low_level_too then printf(fn, "[free blocks:#%08x]\n", FREE_COUNT) end if
6581
void = seek(current_db, FREE_COUNT)
6591
n = get4()
6601
puts(fn, '\n')
6611
if n > 0 then
6621
fbp = get4()
6631
printf(fn, "Number of Free blocks: %d ", n)
6641
if low_level_too then printf(fn, " [#%08x]:", fbp) end if
6651
puts(fn, '\n')
6661
void = seek(current_db, fbp)
6671
for i = 1 to n do
6682
addr = get4()
6692
size = get4()
6702
printf(fn, "%08x: %6d bytes\n", {addr, size})
6712
end for
672
else
6730
puts(fn, "No free blocks available.\n")
674
end if
6751
if sequence(file_id) then
6761
close(fn)
677
end if
678
6791
end procedure
680
681
--**
682
-- Detects corruption of the free list in a Euphoria database.
683
--
684
-- Comments:
685
-- This is a debug routine used by RDS to detect corruption of the free list.
686
-- Users do not normally call this.
687
--
6884
689
atom free_count, free_list, addr, size, free_list_space
690
atom max
691
6924
safe_seek(-1)
6934
if length(vLastErrors) > 0 then return end if
6944
max = where(current_db)
6954
void = seek(current_db, FREE_COUNT)
6964
free_count = get4()
6974
if free_count > max/13 then
6980
crash("free count is too high")
699
end if
7004
free_list = get4()
7014
if free_list > max then
7020
crash("bad free list pointer")
703
end if
7044
void = seek(current_db, free_list - 4)
7054
free_list_space = get4()
7064
if free_list_space > max or free_list_space < 0 then
7070
crash("free list space is bad")
708
end if
7094
for i = 0 to free_count - 1 do
71051
void = seek(current_db, free_list + i * 8)
71151
addr = get4()
71251
if addr > max then
7130
crash("bad block address")
714
end if
71551
size = get4()
71651
if size > max then
7170
crash("block size too big")
718
end if
71951
void = seek(current_db, addr - 4)
72051
if get4() > size then
7210
crash("bad size in front of free block")
722
end if
72351
end for
7244
end procedure
725
7261508
727
-- Allocate (at least) n bytes of space in the database file.
728
-- The usable size + 4 is stored in the 4 bytes before the returned address.
729
-- Upon return, the file pointer points at the allocated space, so data
730
-- can be stored into the space immediately without a seek.
731
-- When space is allocated at the end of the file, it will be exactly
732
-- n bytes in size, and the caller must fill up all the space immediately.
733
atom free_list, size, size_ptr, addr
734
integer free_count
735
sequence remaining
736
7371508
void = seek(current_db, FREE_COUNT)
7381508
free_count = get4()
7391508
if free_count > 0 then
740280
free_list = get4()
741280
void = seek(current_db, free_list)
742280
size_ptr = free_list + 4
743280
for i = 1 to free_count do
744312
addr = get4()
745312
size = get4()
746312
if size >= n+4 then
747
-- found a big enough block
748275
if size >= n+16 then
749
-- loose fit: shrink first part, return 2nd part
750250
void = seek(current_db, addr - 4)
751250
put4(size-n-4) -- shrink the block
752250
void = seek(current_db, size_ptr)
753250
put4(size-n-4) -- update size on free list too
754250
addr += size-n-4
755250
void = seek(current_db, addr - 4)
756250
put4(n+4)
757
else
758
-- close fit: remove whole block from list and return it
75925
remaining = get_bytes(current_db, (free_count-i) * 8)
76025
void = seek(current_db, free_list+8*(i-1))
76125
putn(remaining)
76225
void = seek(current_db, FREE_COUNT)
76325
put4(free_count-1)
76425
void = seek(current_db, addr - 4)
76525
put4(size) -- in case size was not updated by db_free()
766
end if
767275
return addr
768
end if
76937
size_ptr += 8
77037
end for
771
end if
772
-- no free block available - point to end of file
7731233
void = seek(current_db, -1)
7741233
put4(n+4)
7751233
return where(current_db)
776
end function
777
7781094
779
-- Put a block of storage onto the free list in order of address.
780
-- Combine the new free block with any adjacent free blocks.
781
atom psize, i, size, addr, free_list, free_list_space
782
atom new_space, to_be_freed, prev_addr, prev_size
783
integer free_count
784
sequence remaining
785
7861094
void = seek(current_db, p-4)
7871094
psize = get4()
788
7891094
void = seek(current_db, FREE_COUNT)
7901094
free_count = get4()
7911094
free_list = get4()
7921094
void = seek(current_db, free_list - 4)
7931094
free_list_space = get4()-4
7941094
if free_list_space < 8 * (free_count+1) then
795
-- need more space for free list
7964
new_space = floor(free_list_space + free_list_space / 2)
7974
to_be_freed = free_list
7984
free_list = db_allocate(new_space)
7994
void = seek(current_db, FREE_COUNT)
8004
free_count = get4() -- db_allocate may have changed it
8014
void = seek(current_db, FREE_LIST)
8024
put4(free_list)
8034
void = seek(current_db, to_be_freed)
8044
remaining = get_bytes(current_db, 8*free_count)
8054
void = seek(current_db, free_list)
8064
putn(remaining)
8074
putn(repeat(0, new_space-length(remaining)))
8084
void = seek(current_db, free_list)
809
else
8101090
new_space = 0
811
end if
812
8131094
i = 1
8141094
prev_addr = 0
8151094
prev_size = 0
8161094
while i <= free_count do
81713913
addr = get4()
81813913
size = get4()
81913913
if p < addr then
820119
exit
821
end if
82213794
prev_addr = addr
82313794
prev_size = size
82413794
i += 1
82513794
end while
826
8271094
if i > 1 and prev_addr + prev_size = p then
828
-- combine with previous block
829998
void = seek(current_db, free_list+(i-2)*8+4)
830998
if i < free_count and p + psize = addr then
831
-- combine space for all 3, delete the following block
8329
put4(prev_size+psize+size) -- update size on free list (only)
8339
void = seek(current_db, free_list+i*8)
8349
remaining = get_bytes(current_db, (free_count-i)*8)
8359
void = seek(current_db, free_list+(i-1)*8)
8369
putn(remaining)
8379
free_count -= 1
8389
void = seek(current_db, FREE_COUNT)
8399
put4(free_count)
840
else
841989
put4(prev_size+psize) -- increase previous size on free list (only)
842
end if
84396
elsif i < free_count and p + psize = addr then
844
-- combine with following block - only size on free list is updated
84535
void = seek(current_db, free_list+(i-1)*8)
84635
put4(p)
84735
put4(psize+size)
848
else
849
-- insert a new block, shift the others down
85061
void = seek(current_db, free_list+(i-1)*8)
85161
remaining = get_bytes(current_db, (free_count-i+1)*8)
85261
free_count += 1
85361
void = seek(current_db, FREE_COUNT)
85461
put4(free_count)
85561
void = seek(current_db, free_list+(i-1)*8)
85661
put4(p)
85761
put4(psize)
85861
putn(remaining)
859
end if
860
8611094
if new_space then
8624
db_free(to_be_freed) -- free the old space
863
end if
8641094
end procedure
865
86691
867
integer k
86891
if caching_option = 1 then
86985
if current_table_pos > 0 then
87058
k = eu:find({current_db, current_table_pos}, cache_index)
87158
if k != 0 then
87234
key_cache[k] = key_pointers
873
else
87424
key_cache = append(key_cache, key_pointers)
87524
cache_index = append(cache_index, {current_db, current_table_pos})
876
end if
877
end if
878
end if
87991
end procedure
880
881
--****
882
-- === Managing databases
883
884
--**
885
-- Create a new database, given a file path and a lock method.
886
--
887
-- Parameters:
888
-- # ##path## : a sequence, the path to the file that will contain the database.
889
-- # ##lock_method## : an integer specifying which type of access can be
890
-- granted to the database. The value of ##lock_method##
891
-- can be either ##DB_LOCK_NO## (no lock) or
892
-- ##DB_LOCK_EXCLUSIVE## (exclusive lock).
893
-- # ##init_tables## : an integer giving the initial number of tables to
894
-- reserve space for. The default is 5 and the minimum is 1.
895
-- # ##init_free## : an integer giving the initial amount of free space pointers to
896
-- reserve space for. The default is 5 and the minimum is 0.
897
--
898
-- Returns:
899
-- An **integer**, status code, either DB_OK if creation successful or anything else on an error.
900
--
901
-- Comments:
902
--
903
-- On success, the newly created database
904
-- becomes the **current database** to which
905
-- all other database operations will apply.
906
--
907
-- If the path, s, does not end in .edb, it will be added automatically.
908
--
909
-- A version number is stored in the database file so future
910
-- versions of the database software can recognize the format, and
911
-- possibly read it and deal with it in some way.
912
--
913
-- If the database already exists, it will not be overwritten.
914
-- db_create() will return DB_EXISTS_ALREADY.
915
--
916
-- Example 1:
917
--
918
-- if db_create("mydata", DB_LOCK_NO) != DB_OK then
919
-- puts(2, "Couldn't create the database!\n")
920
-- abort(1)
921
-- end if
922
--
923
--
924
-- See Also:
925
-- [[:db_open]], [[:db_select]]
926
9276
928
integer db
929
9306
if init_tables < 1 then
9310
init_tables = 1
932
end if
933
9346
if init_free < 0 then
9350
init_free = 0
936
end if
937
9386
if not eu:find('.', path) then
9390
path &= ".edb"
940
end if
941
942
-- see if it already exists
9436
db = open(path, "rb")
9446
if db != -1 then
945
-- don't destroy an existing db - let user delete himself
9461
close(db)
9471
return DB_EXISTS_ALREADY
948
end if
949
950
-- file must exist before "ub" can be used
9515
db = open(path, "wb")
9525
if db = -1 then
9530
return DB_OPEN_FAIL
954
end if
9555
close(db)
956
957
-- get read and write access, "ub"
9585
db = open(path, "ub")
9595
if db = -1 then
9600
return DB_OPEN_FAIL
961
end if
9625
if lock_method = DB_LOCK_SHARED then
963
-- shared lock doesn't make sense for create
9640
lock_method = DB_LOCK_NO
965
end if
9665
if lock_method = DB_LOCK_EXCLUSIVE then
9671
if not lock_file(db, LOCK_EXCLUSIVE, {}) then
9680
return DB_LOCK_FAIL
969
end if
970
end if
9715
save_keys()
9725
current_db = db
9735
current_lock = lock_method
9745
current_table_pos = -1
9755
current_table_name = ""
9765
db_names = append(db_names, path)
9775
db_lock_methods = append(db_lock_methods, lock_method)
9785
db_file_nums = append(db_file_nums, db)
979
980
-- initialize the header
9815
put1(DB_MAGIC) -- so we know what type of file it is
9825
put1(DB_MAJOR) -- major version
9835
put1(DB_MINOR) -- minor version
984
-- 3:
9855
put4(19) -- pointer to tables
986
-- 7:
9875
put4(0) -- number of free blocks
988
-- 11:
9895
put4(23 + init_tables * SIZEOF_TABLE_HEADER + 4) -- pointer to free list
990
-- 15: initial table block:
9915
put4( 8 + init_tables * SIZEOF_TABLE_HEADER) -- allocated size
992
-- 19:
9935
put4(0) -- number of tables that currently exist
994
-- 23: initial space for tables
9955
putn(repeat(0, init_tables * SIZEOF_TABLE_HEADER))
996
-- initial space for free list
9975
put4(4+init_free*8) -- allocated size
9985
putn(repeat(0, init_free * 8))
9995
return DB_OK
1000
end function
1001
1002
--**
1003
-- Open an existing Euphoria database.
1004
--
1005
-- Parameters:
1006
-- # ##path## : a sequence, the path to the file containing the database
1007
-- # ##lock_method## : an integer specifying which sort of access can
1008
-- be granted to the database. The types of lock that you can use are:
1009
-- ## ##DB_LOCK_NO## : (no lock) - The default
1010
-- ## ##DB_LOCK_SHARED## : (shared lock for read-only access)
1011
-- ## ##DB_LOCK_EXCLUSIVE## : (for read/write access).
1012
--
1013
-- Returns:
1014
-- An **integer**, status code, either ##DB_OK## if creation successful or anything else on an error.
1015
--
1016
-- The return codes are:
1017
--
1018
--
1019
-- public constant
1020
-- DB_OK = 0 -- success
1021
-- DB_OPEN_FAIL = -1 -- could not open the file
1022
-- DB_LOCK_FAIL = -3 -- could not lock the file in the
1023
-- -- manner requested
1024
--
1025
--
1026
-- Comments:
1027
-- ##DB_LOCK_SHARED## is only supported on Unix platforms. It allows you to read the database,
1028
-- but not write anything to it. If you request ##DB_LOCK_SHARED## on //WIN32// it will be
1029
-- treated as if you had asked for DB_LOCK_EXCLUSIVE.
1030
--
1031
-- If the lock fails, your program should wait a few seconds and try again.
1032
-- Another process might be currently accessing the database.
1033
--
1034
-- Example 1:
1035
--
1036
-- tries = 0
1037
-- while 1 do
1038
-- err = db_open("mydata", DB_LOCK_SHARED)
1039
-- if err = DB_OK then
1040
-- exit
1041
-- elsif err = DB_LOCK_FAIL then
1042
-- tries += 1
1043
-- if tries > 10 then
1044
-- puts(2, "too many tries, giving up\n")
1045
-- abort(1)
1046
-- else
1047
-- sleep(5)
1048
-- end if
1049
-- else
1050
-- puts(2, "Couldn't open the database!\n")
1051
-- abort(1)
1052
-- end if
1053
-- end while
1054
--
1055
--
1056
-- See Also:
1057
-- [[:db_create]], [[:db_select]]
1058
10592
1060
integer db, magic
1061
10622
if not eu:find('.', path) then
10631
path &= ".edb"
1064
end if
1065
10662
ifdef UNIX then
10672
if lock_method = DB_LOCK_NO or
1068
lock_method = DB_LOCK_EXCLUSIVE then
1069
-- get read and write access, "ub"
10702
db = open(path, "ub")
1071
else
1072
-- DB_LOCK_SHARED
10730
db = open(path, "rb")
1074
end if
1075
elsedef
1076
if lock_method = DB_LOCK_SHARED then
1077
lock_method = DB_LOCK_EXCLUSIVE
1078
end if
1079
db = open(path, "ub")
1080
end ifdef
1081
10822
if db = -1 then
10830
return DB_OPEN_FAIL
1084
end if
10852
if lock_method = DB_LOCK_EXCLUSIVE then
10861
if not lock_file(db, LOCK_EXCLUSIVE, {}) then
10870
close(db)
10880
return DB_LOCK_FAIL
1089
end if
10901
elsif lock_method = DB_LOCK_SHARED then
10910
if not lock_file(db, LOCK_SHARED, {}) then
10920
close(db)
10930
return DB_LOCK_FAIL
1094
end if
1095
end if
10962
magic = getc(db)
10972
if magic != DB_MAGIC then
10980
close(db)
10990
return DB_OPEN_FAIL
1100
end if
11012
save_keys()
11022
current_db = db
11032
current_table_pos = -1
11042
current_table_name = ""
11052
current_lock = lock_method
11062
db_names = append(db_names, path)
11072
db_lock_methods = append(db_lock_methods, lock_method)
11082
db_file_nums = append(db_file_nums, db)
11092
return DB_OK
1110
end function
1111
1112
--**
1113
-- Choose a new, already open, database to be the current database.
1114
--
1115
-- Parameters:
1116
-- # ##path## : a sequence, the path to the database to be the new current database.
1117
-- # ##lock_method## : an integer. Optional locking method.
1118
--
1119
-- Returns:
1120
-- An **integer**, ##DB_OK## on success or an error code.
1121
--
1122
-- Comments:
1123
-- * Subsequent database operations will apply to this database. path is the
1124
-- path of the database file as it was originally opened with ##db_open##()
1125
-- or ##db_create##().\\
1126
-- * When you create (db_create) or open (db_open) a database, it automatically
1127
-- becomes the current database. Use ##db_select##() when you want to switch back
1128
-- and forth between open databases, perhaps to copy records from one to the
1129
-- other. After selecting a new database, you should select a table within
1130
-- that database using ##db_select_table##().
1131
-- * If the ##lock_method## is omitted and the database has not already been opened,
1132
-- this function will fail. However, if ##lock_method## is a valid lock type for
1133
-- [[:db_open]] and the database is not open yet, this function will attempt to
1134
-- open it. It may still fail if the database cannot be opened.
1135
--
1136
-- Example 1:
1137
--
1138
-- if db_select("employees") != DB_OK then
1139
-- puts(2, "Could not select employees database\n")
1140
-- end if
1141
--
1142
--
1143
-- Example 2:
1144
--
1145
-- if db_select("customer", DB_LOCK_SHARED) != DB_OK then
1146
-- puts(2, "Could not open or select Customer database\n")
1147
-- end if
1148
--
1149
--
1150
-- See Also:
1151
-- [[:db_open]], [[:db_select]]
1152
115321
1154
integer index
1155
115621
if not eu:find('.', path) then
11570
path &= ".edb"
1158
end if
1159
116021
index = eu:find(path, db_names)
116121
if index = 0 then
11620
if lock_method = -1 then
11630
return DB_OPEN_FAIL
1164
end if
11650
index = db_open(path, lock_method)
11660
if index != DB_OK then
11670
return index
1168
end if
11690
index = eu:find(path, db_names)
1170
end if
117121
save_keys()
117221
current_db = db_file_nums[index]
117321
current_lock = db_lock_methods[index]
117421
current_table_pos = -1
117521
current_table_name = ""
117621
key_pointers = {}
117721
return DB_OK
1178
end function
1179
1180
--**
1181
-- Unlock and close the current database.
1182
--
1183
-- Comments:
1184
-- Call this procedure when you are finished with the current database. Any lock will be removed, allowing other processes to access the database file. The current database becomes undefined.
1185
11866
1187
-- close the current database
1188
integer index
1189
11906
if current_db = -1 then
11911
return
1192
end if
1193
-- unlock the database
11945
if current_lock then
11952
unlock_file(current_db, {})
1196
end if
11975
close(current_db)
1198
-- delete info for current_db
11995
index = eu:find(current_db, db_file_nums)
12005
db_names = db_names[1..index-1] & db_names[index+1..$]
12015
db_file_nums = db_file_nums[1..index-1] & db_file_nums[index+1..$]
12025
db_lock_methods = db_lock_methods[1..index-1] & db_lock_methods[index+1..$]
1203
-- delete each cache entry for this database
12045
for i = length(cache_index) to 1 by -1 do
120522
if cache_index[i][1] = current_db then
120617
cache_index = remove(cache_index, i)
120717
key_cache = remove(key_cache, i)
1208
end if
120922
end for
12105
current_db = -1
12115
key_pointers = {}
12125
end procedure
1213
121499
1215
-- find a table, given its name
1216
-- return table pointer
1217
atom tables
1218
atom nt
1219
atom t_header, name_ptr
1220
122199
safe_seek(TABLE_HEADERS)
122299
if length(vLastErrors) > 0 then return -1 end if
122399
tables = get4()
122499
void = seek(current_db, tables)
122599
nt = get4()
122699
t_header = tables+4
122799
for i = 1 to nt do
1228274
void = seek(current_db, t_header)
1229274
name_ptr = get4()
1230274
void = seek(current_db, name_ptr)
1231274
if equal_string(name) > 0 then
1232
-- found it
123373
return t_header
1234
end if
1235201
t_header += SIZEOF_TABLE_HEADER
1236201
end for
123726
return -1
1238
end function
1239
1240
--**
1241
--==== Managing tables
1242
-- Parameters:
1243
-- # ##name## : a sequence which defines the name of the new current table.
1244
--
1245
-- Description:
1246
-- On success, the table with name given by name becomes the current table.
1247
--
1248
-- Returns:
1249
-- An **integer**, either DB_OK on success or DB_OPEN_FAIL otherwise.
1250
--
1251
-- Errors:
1252
-- An error occurs if the current database is not defined.
1253
--
1254
-- Comments:
1255
-- All record-level database operations apply automatically to the current table.
1256
--
1257
-- Example 1:
1258
--
1259
-- if db_select_table("salary") != DB_OK then
1260
-- puts(2, "Couldn't find salary table!\n")
1261
-- abort(1)
1262
-- end if
1263
--
1264
--
1265
-- See Also:
1266
-- [[:db_table_list]]
1267
126867
1269
-- let table with the given name be the current table
1270
atom table, nkeys, index
1271
atom block_ptr, block_size
1272
integer blocks, k
1273
127467
if equal(current_table_name, name) then
12752
return DB_OK
1276
end if
127765
table = table_find(name)
127865
if table = -1 then
12792
return DB_OPEN_FAIL
1280
end if
1281
128263
save_keys()
1283
128463
current_table_pos = table
128563
current_table_name = name
1286
128763
k = 0
128863
if caching_option = 1 then
128960
k = eu:find({current_db, current_table_pos}, cache_index)
129060
if k != 0 then
129138
key_pointers = key_cache[k]
1292
end if
1293
end if
129463
if k = 0 then
1295
-- read in all the key pointers for the current table
129625
void = seek(current_db, table+4)
129725
nkeys = get4()
129825
blocks = get4()
129925
index = get4()
130025
key_pointers = repeat(0, nkeys)
130125
k = 1
130225
for b = 0 to blocks-1 do
130327
void = seek(current_db, index)
130427
block_size = get4()
130527
block_ptr = get4()
130627
void = seek(current_db, block_ptr)
130727
for j = 1 to block_size do
130888
key_pointers[k] = get4()
130988
k += 1
131088
end for
131127
index += 8
131227
end for
1313
end if
131463
return DB_OK
1315
end function
1316
1317
--**
1318
-- Get name of currently selected table
1319
--
1320
-- Parameters:
1321
-- # None.
1322
--
1323
-- Returns:
1324
-- A **sequence**, the name of the current table. An empty string means
1325
-- that no table is currently selected.
1326
--
1327
-- Example 1:
1328
--
1329
-- s = db_current_table()
1330
--
1331
--
1332
-- See Also:
1333
-- [[:db_select_table]], [[:db_table_list]]
1334
133510
133610
return current_table_name
1337
end function
1338
1339
--**
1340
-- Create a new table within the current database.
1341
--
1342
-- Parameters:
1343
-- # ##name## : a sequence, the name of the new table.
1344
-- # ##init_records## : The number of records to initially reserve space for.
1345
-- (Default is 50)
1346
--
1347
-- Returns:
1348
-- An **integer**, either DB_OK on success or DB_EXISTS_ALREADY on failure.
1349
--
1350
-- Errors:
1351
-- An error occurs if the current database is not defined.
1352
--
1353
-- Comments:
1354
-- * The supplied name must not exist already on the current database.
1355
-- * The table that you create will initially have 0 records. However
1356
-- it will reserve some space for a number of records, which will
1357
-- improve the initial data load for the table.
1358
-- * It becomes the current table.
1359
--
1360
-- Example 1:
1361
--
1362
-- if db_create_table("my_new_table") != DB_OK then
1363
-- puts(2, "Could not create my_new_table!\n")
1364
-- end if
1365
--
1366
--
1367
-- See Also:
1368
-- [[:db_select_table]], [[:db_table_list]]
1369
137023
1371
atom name_ptr, nt, tables, newtables, table, records_ptr
1372
atom size, newsize, index_ptr
1373
sequence remaining
1374
integer init_index
1375
137623
table = table_find(name)
137723
if table != -1 then
13781
return DB_EXISTS_ALREADY
1379
end if
1380
138122
if init_records < 1 then
13820
init_records = 1
1383
end if
138422
init_index = min({init_records, INIT_INDEX})
1385
1386
-- increment number of tables
138722
void = seek(current_db, TABLE_HEADERS)
138822
tables = get4()
138922
void = seek(current_db, tables-4)
139022
size = get4()
139122
nt = get4()+1
139222
if nt*SIZEOF_TABLE_HEADER + 8 > size then
1393
-- enlarge the block of table headers
13942
newsize = floor(size + size / 2)
13952
newtables = db_allocate(newsize)
13962
put4(nt)
1397
-- copy all table headers to the new block
13982
void = seek(current_db, tables+4)
13992
remaining = get_bytes(current_db, (nt-1)*SIZEOF_TABLE_HEADER)
14002
void = seek(current_db, newtables+4)
14012
putn(remaining)
1402
-- fill the rest
14032
putn(repeat(0, newsize - 4 - (nt-1)*SIZEOF_TABLE_HEADER))
14042
db_free(tables)
14052
void = seek(current_db, TABLE_HEADERS)
14062
put4(newtables)
14072
tables = newtables
1408
else
140920
void = seek(current_db, tables)
141020
put4(nt)
1411
end if
1412
1413
-- allocate initial space for 1st block of record pointers
141422
records_ptr = db_allocate(init_records * 4)
141522
putn(repeat(0, init_records * 4))
1416
1417
-- allocate initial space for the index
141822
index_ptr = db_allocate(init_index * 8)
141922
put4(0) -- 0 records
142022
put4(records_ptr) -- point to 1st block
142122
putn(repeat(0, (init_index-1) * 8))
1422
1423
-- store new table
142422
name_ptr = db_allocate(length(name)+1)
142522
putn(name & 0)
1426
142722
void = seek(current_db, tables+4+(nt-1)*SIZEOF_TABLE_HEADER)
142822
put4(name_ptr)
142922
put4(0) -- start with 0 records total
143022
put4(1) -- start with 1 block of records in index
143122
put4(index_ptr)
143222
if db_select_table(name) then
1433
end if
143422
return DB_OK
1435
end function
1436
1437
--**
1438
-- Delete a table in the current database.
1439
--
1440
-- Parameters:
1441
-- # ##name## : a sequence, the name of the table to delete.
1442
--
1443
-- Errors:
1444
-- An error occurs if the current database is not defined.
1445
--
1446
-- Comments:
1447
-- If there is no table with the name given by name, then nothing happens.
1448
-- On success, all records are deleted and all space used by the table
1449
-- is freed up. If the table was the current table, the current table
1450
-- becomes undefined.
1451
--
1452
-- See Also:
1453
-- [[:db_table_list]], [[:db_select_table]], [[:db_clear_table]]
1454
14554
1456
-- delete an existing table and all of its records
1457
atom table, tables, nt, nrecs, records_ptr, blocks
1458
atom p, data_ptr, index
1459
sequence remaining
1460
integer k
1461
14624
table = table_find(name)
14634
if table = -1 then
14640
return
1465
end if
1466
1467
-- free the table name
14684
void = seek(current_db, table)
14694
db_free(get4())
1470
14714
void = seek(current_db, table+4)
14724
nrecs = get4()
14734
blocks = get4()
14744
index = get4()
1475
1476
-- free all the records
14774
for b = 0 to blocks-1 do
14784
void = seek(current_db, index+b*8)
14794
nrecs = get4()
14804
records_ptr = get4()
14814
for r = 0 to nrecs-1 do
14824
void = seek(current_db, records_ptr + r*4)
14834
p = get4()
14844
void = seek(current_db, p)
14854
data_ptr = get4()
14864
db_free(data_ptr)
14874
db_free(p)
14884
end for
1489
-- free the block
14904
db_free(records_ptr)
14914
end for
1492
1493
-- free the index
14944
db_free(index)
1495
1496
-- get tables & number of tables
14974
void = seek(current_db, TABLE_HEADERS)
14984
tables = get4()
14994
void = seek(current_db, tables)
15004
nt = get4()
1501
1502
-- shift later tables up
15034
void = seek(current_db, table+SIZEOF_TABLE_HEADER)
15044
remaining = get_bytes(current_db,
1505
tables+4+nt*SIZEOF_TABLE_HEADER-
1506
(table+SIZEOF_TABLE_HEADER))
15074
void = seek(current_db, table)
15084
putn(remaining)
1509
1510
-- decrement number of tables
15114
nt -= 1
15124
void = seek(current_db, tables)
15134
put4(nt)
1514
15154
k = eu:find({current_db, current_table_pos}, cache_index)
15164
if k != 0 then
15172
cache_index = remove(cache_index, k)
15182
key_cache = remove(key_cache, k)
1519
end if
15204
if table = current_table_pos then
15211
current_table_pos = -1
15221
current_table_name = ""
15233
elsif table < current_table_pos then
15241
current_table_pos -= SIZEOF_TABLE_HEADER
15251
void = seek(current_db, current_table_pos)
15261
data_ptr = get4()
15271
void = seek(current_db, data_ptr)
15281
current_table_name = get_string()
1529
end if
15304
end procedure
1531
1532
--**
1533
-- Clears a table of all its records, in the current database.
1534
--
1535
-- Parameters:
1536
-- # ##name## : a sequence, the name of the table to clear.
1537
--
1538
-- Errors:
1539
-- An error occurs if the current database is not defined.
1540
--
1541
-- Comments:
1542
-- If there is no table with the name given by name, then nothing happens.
1543
-- On success, all records are deleted and all space used by the table
1544
-- is freed up. If this is the current table, after this operation
1545
-- it will still be the current table.
1546
--
1547
-- See Also:
1548
-- [[:db_table_list]], [[:db_select_table]], [[:db_delete_table]]
1549
15502
1551
-- delete all of records in the table
1552
atom table, nrecs, records_ptr, blocks
1553
atom p, data_ptr, index_ptr
1554
integer k
1555
integer init_index
1556
15572
table = table_find(name)
15582
if table = -1 then
15590
return
1560
end if
1561
15622
if init_records < 1 then
15630
init_records = 1
1564
end if
15652
init_index = min({init_records, INIT_INDEX})
1566
15672
void = seek(current_db, table + 4)
15682
nrecs = get4()
15692
blocks = get4()
15702
index_ptr = get4()
1571
1572
-- free all the records
15732
for b = 0 to blocks-1 do
157414
void = seek(current_db, index_ptr + b*8)
157514
nrecs = get4()
157614
records_ptr = get4()
157714
for r = 0 to nrecs-1 do
1578504
void = seek(current_db, records_ptr + r*4)
1579504
p = get4()
1580504
void = seek(current_db, p)
1581504
data_ptr = get4()
1582504
db_free(data_ptr)
1583504
db_free(p)
1584504
end for
1585
-- free the block
158614
db_free(records_ptr)
158714
end for
1588
1589
-- free the index
15902
db_free(index_ptr)
1591
1592
-- allocate initial space for 1st block of record pointers
15932
data_ptr = db_allocate(init_records * 4)
15942
putn(repeat(0, init_records * 4))
1595
1596
-- allocate initial space for the index block
15972
index_ptr = db_allocate(init_index * 8)
15982
put4(0) -- 0 records
15992
put4(data_ptr) -- point to 1st block
16002
putn(repeat(0, (init_index-1) * 8))
1601
16022
void = seek(current_db, table + 4)
16032
put4(0) -- start with 0 records total
16042
put4(1) -- start with 1 block of records in index
16052
put4(index_ptr)
1606
1607
-- Clear cache and RAM pointers
16082
k = eu:find({current_db, current_table_pos}, cache_index)
16092
if k != 0 then
16100
cache_index = remove(cache_index, k)
16110
key_cache = remove(key_cache, k)
1612
end if
16132
if table = current_table_pos then
16142
key_pointers = {}
1615
end if
1616
16172
end procedure
1618
1619
--**
1620
-- Rename a table in the current database.
1621
--
1622
-- Parameters:
1623
-- # ##name## : a sequence, the name of the table to rename
1624
-- # ##new_name## : a sequence, the new name for the table
1625
--
1626
-- Errors:
1627
-- * An error occurs if the current database is not defined.
1628
-- * If ##name## does not exist on the current database,
1629
-- or if ##new_name## does exist on the current database,
1630
-- an error will occur.
1631
--
1632
-- Comments:
1633
-- The table to be renamed can be the current table, or some other table
1634
-- in the current database.
1635
--
1636
-- See Also:
1637
-- [[:db_table_list]]
1638
16393
1640
-- rename an existing table - written by Jordah Ferguson
1641
atom table, table_ptr
1642
16433
table = table_find(name)
16443
if table = -1 then
16451
fatal(NO_TABLE, "source table doesn't exist", "db_rename_table", {name, new_name})
16461
return
1647
end if
1648
16492
if table_find(new_name) != -1 then
16501
fatal(DUP_TABLE, "target table name already exists", "db_rename_table", {name, new_name})
16511
return
1652
end if
1653
16541
void = seek(current_db, table)
16551
db_free(get4())
1656
16571
table_ptr = db_allocate(length(new_name)+1)
16581
putn(new_name & 0)
1659
16601
void = seek(current_db, table)
16611
put4(table_ptr)
16621
end procedure
1663
1664
--**
1665
-- Lists all tables on the current database.
1666
--
1667
-- Returns:
1668
-- A **sequence**, of all the table names in the current database. Each element of this
1669
-- sequence is a sequence, the name of a table.
1670
--
1671
-- Errors:
1672
-- An error occurs if the current database is undefined.
1673
--
1674
-- Example 1:
1675
--
1676
-- sequence names = db_table_list()
1677
-- for i = 1 to length(names) do
1678
-- puts(1, names[i] & '\n')
1679
-- end for
1680
--
1681
--
1682
-- See Also:
1683
-- [[:db_select_table]], [[:db_create_table]]
1684
16857
1686
sequence table_names
1687
atom tables, nt, name
1688
16897
safe_seek(TABLE_HEADERS)
16907
if length(vLastErrors) > 0 then return {} end if
16917
tables = get4()
16927
void = seek(current_db, tables)
16937
nt = get4()
16947
table_names = repeat(0, nt)
16957
for i = 0 to nt-1 do
169614
void = seek(current_db, tables + 4 + i*SIZEOF_TABLE_HEADER)
169714
name = get4()
169814
void = seek(current_db, name)
169914
table_names[i+1] = get_string()
170014
end for
17017
return table_names
1702
end function
1703
17045518
1705
-- return the value of a key,
1706
-- given a pointer to the key in the database
17075518
void = seek(current_db, ptr+4) -- skip ptr to data
17085518
return decompress(0)
1709
end function
1710
1711
--****
1712
--==== Managing Records
1713
1714
--**
1715
-- Find the record in the current table with supplied key.
1716
--
1717
-- Parameters:
1718
-- # ##key## : the identifier of the record to be looked up.
1719
-- # ##table_name## : optional name of table to find key in
1720
--
1721
-- Returns:
1722
-- An **integer**, either greater or less than zero:
1723
-- * If above zero, the record identified by ##key## was found on the
1724
-- current table, and the returned integer is its record number.
1725
-- * If less than zero, the record was not found. The returned integer
1726
-- is the opposite of what the record number would have been, had
1727
-- the record been found.
1728
-- * If equal to zero, an error occured.
1729
--
1730
-- Errors:
1731
-- If the current table is not defined, it returns 0.
1732
--
1733
-- Comments:
1734
--
1735
-- A fast binary search is used to find the key in the current table.
1736
-- The number of comparisons is proportional to the log of the number of
1737
-- records in the table. The key is unique~--a table is more like a dictionary than like a spreadsheet.
1738
--
1739
-- You can select a range of records by searching
1740
-- for the first and last key values in the range. If those key values don't
1741
-- exist, you'll at least get a negative value showing where they would be,
1742
-- if they existed. e.g. Suppose you want to know which records have keys
1743
-- greater than "GGG" and less than "MMM". If -5 is returned for key "GGG",
1744
-- it means a record with "GGG" as a key would be inserted as record number 5.
1745
-- -27 for "MMM" means a record with "MMM" as its key would be inserted as record
1746
-- number 27. This quickly tells you that all records, >= 5 and < 27 qualify.
1747
--
1748
-- Example 1:
1749
--
1750
-- rec_num = db_find_key("Millennium")
1751
-- if rec_num > 0 then
1752
-- ? db_record_key(rec_num)
1753
-- ? db_record_data(rec_num)
1754
-- else
1755
-- puts(2, "Not found, but if you insert it,\n")
1756
--
1757
-- printf(2, "it will be #%d\n", -rec_num)
1758
-- end if
1759
--
1760
--
1761
-- See Also:
1762
-- [[:db_insert]], [[:db_replace_data]], [[:db_delete_record]], [[:db_get_recid]]
1763
1764773
1765
integer lo, hi, mid, c -- works up to 1.07 billion records
1766
1767773
if not equal(table_name, current_table_name) then
17684
if db_select_table(table_name) != DB_OK then
17690
fatal(NO_TABLE, "invalid table name given", "db_find_key", {key, table_name})
17700
return 0
1771
end if
1772
end if
1773
1774773
if current_table_pos = -1 then
17750
fatal(NO_TABLE, "no table selected", "db_find_key", {key, table_name})
17760
return 0
1777
end if
1778773
lo = 1
1779773
hi = length(key_pointers)
1780773
mid = 1
1781773
c = 0
1782773
while lo <= hi do
17835412
mid = floor((lo + hi) / 2)
17845412
c = eu:compare(key, key_value(key_pointers[mid]))
17855412
if c < 0 then
1786151
hi = mid - 1
17875261
elsif c > 0 then
17885224
lo = mid + 1
1789
else
179037
return mid
1791
end if
17925375
end while
1793
-- return the position it would have, if inserted now
1794736
if c > 0 then
1795700
mid += 1
1796
end if
1797736
return -mid
1798
end function
1799
1800
--**
1801
-- Returns the unique record identifier (##recid##) value for the record.
1802
--
1803
-- Parameters:
1804
-- # ##key## : the identifier of the record to be looked up.
1805
-- # ##table_name## : optional name of table to find key in
1806
--
1807
-- Returns:
1808
-- An **atom**, either greater or equal to zero:
1809
-- * If above zero, it is a ##recid##.
1810
-- * If less than zero, the record wasn't found.
1811
-- * If equal to zero, an error occured.
1812
--
1813
-- Errors:
1814
-- If the table is not defined, an error is raised.
1815
--
1816
-- Comments:
1817
-- A **##recid##** is a number that uniquely identifies a record in the database.
1818
-- No two records in a database has the same ##recid## value. They can be used
1819
-- instead of keys to //quickly// refetch a record, as they avoid the overhead of
1820
-- looking for a matching record key. They can also be used without selecting
1821
-- a table first, as the ##recid## is unique to the database and not just a table.
1822
-- However, they only remain valid while a database is open and so long as it
1823
-- doesn't get compressed. Compressing the database will give each record a
1824
-- new ##recid## value.
1825
--
1826
-- Because it is faster to fetch a record with a ##recid## rather than with its key,
1827
-- these are used when you know you have to **refetch** a record.
1828
--
1829
-- Example 1:
1830
--
1831
-- rec_num = db_get_recid("Millennium")
1832
-- if rec_num > 0 then
1833
-- ? db_record_recid(rec_num) -- fetch key and data.
1834
-- else
1835
-- puts(2, "Not found\n")
1836
-- end if
1837
--
1838
--
1839
-- See Also:
1840
-- [[:db_insert]], [[:db_replace_data]], [[:db_delete_record]], [[:db_find_key]]
1841
18423
1843
integer lo, hi, mid, c -- works up to 1.07 billion records
1844
18453
if not equal(table_name, current_table_name) then
18460
if db_select_table(table_name) != DB_OK then
18470
fatal(NO_TABLE, "invalid table name given", "db_get_recid", {key, table_name})
18480
return 0
1849
end if
1850
end if
1851
18523
if current_table_pos = -1 then
18530
fatal(NO_TABLE, "no table selected", "db_get_recid", {key, table_name})
18540
return 0
1855
end if
18563
lo = 1
18573
hi = length(key_pointers)
18583
mid = 1
18593
c = 0
18603
while lo <= hi do
186119
mid = floor((lo + hi) / 2)
186219
c = eu:compare(key, key_value(key_pointers[mid]))
186319
if c < 0 then
18648
hi = mid - 1
186511
elsif c > 0 then
18669
lo = mid + 1
1867
else
18682
return key_pointers[mid]
1869
end if
187017
end while
18711
return -1
1872
end function
1873
1874
--**
1875
-- Insert a new record into the current table.
1876
--
1877
-- Parameters:
1878
-- # ##key## : an object, the record key, which uniquely identifies it inside the current table
1879
-- # ##data## : an object, associated to ##key##.
1880
-- # ##table_name## : optional table name to insert record into
1881
--
1882
-- Returns:
1883
-- An **integer**, either DB_OK on success or an error code on failure.
1884
--
1885
-- Comments:
1886
-- Within a table, all keys must be unique. ##db_insert##() will fail with
1887
-- ##DB_EXISTS_ALREADY## if a record already exists on current table with the same key value.
1888
--
1889
-- Both key and data can be any Euphoria data objects, atoms or sequences.
1890
--
1891
-- Example 1:
1892
--
1893
-- if db_insert("Smith", {"Peter", 100, 34.5}) != DB_OK then
1894
-- puts(2, "insert failed!\n")
1895
-- end if
1896
--
1897
--
1898
-- See Also:
1899
-- [[:db_delete_record]]
1900
1901707
1902
sequence key_string, data_string, last_part, remaining
1903
atom key_ptr, data_ptr, records_ptr, nrecs, current_block, size, new_size
1904
atom key_location, new_block, index_ptr, new_index_ptr, total_recs
1905
integer r, blocks, new_recs, n
1906
1907707
key_location = db_find_key(key, table_name) -- Let it set the current table if necessary
1908
1909707
if key_location > 0 then
1910
-- key is already in the table
19111
return DB_EXISTS_ALREADY
1912
end if
1913706
key_location = -key_location
1914
1915706
data_string = compress(data)
1916706
key_string = compress(key)
1917
1918706
data_ptr = db_allocate(length(data_string))
1919706
putn(data_string)
1920
1921706
key_ptr = db_allocate(4+length(key_string))
1922706
put4(data_ptr)
1923706
putn(key_string)
1924
1925
-- increment number of records in whole table
1926
1927706
void = seek(current_db, current_table_pos+4)
1928706
total_recs = get4()+1
1929706
blocks = get4()
1930706
void = seek(current_db, current_table_pos+4)
1931706
put4(total_recs)
1932
1933706
n = length(key_pointers)
1934706
if key_location >= floor(n/2) then
1935
-- add space at end
1936705
key_pointers = append(key_pointers, 0)
1937
-- shift up
1938705
key_pointers[key_location+1..n+1] = key_pointers[key_location..n]
1939
else
1940
-- add space at beginning
19411
key_pointers = prepend(key_pointers, 0)
1942
-- shift down
19431
key_pointers[1..key_location-1] = key_pointers[2..key_location]
1944
end if
1945706
key_pointers[key_location] = key_ptr
1946
1947706
void = seek(current_db, current_table_pos+12) -- get after put - seek is necessary
1948706
index_ptr = get4()
1949
1950706
void = seek(current_db, index_ptr)
1951706
r = 0
1952706
while TRUE do
19533786
nrecs = get4()
19543786
records_ptr = get4()
19553786
r += nrecs
19563786
if r + 1 >= key_location then
1957706
exit
1958
end if
19593080
end while
1960
1961706
current_block = where(current_db)-8
1962
1963706
key_location -= (r-nrecs)
1964
1965706
void = seek(current_db, records_ptr+4*(key_location-1))
1966706
for i = key_location to nrecs+1 do
1967714
put4(key_pointers[i+r-nrecs])
1968714
end for
1969
1970
-- increment number of records in this block
1971706
void = seek(current_db, current_block)
1972706
nrecs += 1
1973706
put4(nrecs)
1974
1975
-- check allocated size for this block
1976706
void = seek(current_db, records_ptr - 4)
1977706
size = get4() - 4
1978706
if nrecs*4 > size-4 then
1979
-- This block is now full - split it into 2 pieces.
1980
-- Magic formula: On average we'd like to have N blocks with
1981
-- N records in each block and space for 2N records,
1982
-- with N-squared total records in the table. We should also
1983
-- avoid allocating extremely small blocks, and we should
1984
-- anticipate some future growth of the database.
1985
198616
new_size = 8 * (20 + floor(sqrt(1.5 * total_recs)))
1987
198816
new_recs = floor(new_size/8)
198916
if new_recs > floor(nrecs/2) then
199016
new_recs = floor(nrecs/2)
1991
end if
1992
1993
-- copy last portion to the new block
199416
void = seek(current_db, records_ptr + (nrecs-new_recs)*4)
199516
last_part = get_bytes(current_db, new_recs*4)
199616
new_block = db_allocate(new_size)
199716
putn(last_part)
1998
-- fill the rest
199916
putn(repeat(0, new_size-length(last_part)))
2000
2001
-- change nrecs for this block in index
200216
void = seek(current_db, current_block)
200316
put4(nrecs-new_recs)
2004
2005
-- insert new block into index after current block
200616
void = seek(current_db, current_block+8)
200716
remaining = get_bytes(current_db, index_ptr+blocks*8-(current_block+8))
200816
void = seek(current_db, current_block+8)
200916
put4(new_recs)
201016
put4(new_block)
201116
putn(remaining)
201216
void = seek(current_db, current_table_pos+8)
201316
blocks += 1
201416
put4(blocks)
2015
-- enlarge index if full
201616
void = seek(current_db, index_ptr-4)
201716
size = get4() - 4
201816
if blocks*8 > size-8 then
2019
-- grow the index
20201
remaining = get_bytes(current_db, blocks*8)
20211
new_size = floor(size + size/2)
20221
new_index_ptr = db_allocate(new_size)
20231
putn(remaining)
20241
putn(repeat(0, new_size-blocks*8))
20251
db_free(index_ptr)
20261
void = seek(current_db, current_table_pos+12)
20271
put4(new_index_ptr)
2028
end if
2029
end if
2030706
return DB_OK
2031
end function
2032
2033
--**
2034
-- Delete record number key_location from the current table.
2035
--
2036
-- Parameter:
2037
-- # ##key_location## : a positive integer, designating the record to delete.
2038
-- # ##table_name## : optional table name to delete record from.
2039
--
2040
-- Errors:
2041
-- If the current table is not defined, or ##key_location## is not a valid record index, an error will occur. Valid record indexes are between 1 and the number of records in the table.
2042
--
2043
-- Example 1:
2044
--
2045
-- db_delete_record(55)
2046
--
2047
--
2048
-- See Also:
2049
-- [[:db_find_key]]
2050
205122
2052
atom key_ptr, nrecs, records_ptr, data_ptr, index_ptr, current_block
2053
integer r, blocks, n
2054
sequence remaining
2055
205622
if not equal(table_name, current_table_name) then
20573
if db_select_table(table_name) != DB_OK then
20581
fatal(NO_TABLE, "invalid table name given", "db_delete_record", {key_location, table_name})
20591
return
2060
end if
2061
end if
2062
206321
if current_table_pos = -1 then
20641
fatal(NO_TABLE, "no table selected", "db_delete_record", {key_location, table_name})
20651
return
2066
end if
206720
if key_location < 1 or key_location > length(key_pointers) then
20680
fatal(BAD_RECNO, "bad record number", "db_delete_record", {key_location, table_name})
20690
return
2070
end if
207120
key_ptr = key_pointers[key_location]
207220
safe_seek(key_ptr)
207320
if length(vLastErrors) > 0 then return end if
207420
data_ptr = get4()
207520
db_free(key_ptr)
207620
db_free(data_ptr)
2077
207820
n = length(key_pointers)
207920
if key_location >= floor(n/2) then
2080
-- shift down
208112
key_pointers[key_location..n-1] = key_pointers[key_location+1..n]
208212
key_pointers = key_pointers[1..n-1]
2083
else
2084
-- shift up
20858
key_pointers[2..key_location] = key_pointers[1..key_location-1]
20868
key_pointers = key_pointers[2..n]
2087
end if
2088
2089
-- decrement number of records in whole table
209020
void = seek(current_db, current_table_pos+4)
209120
nrecs = get4()-1
209220
blocks = get4()
209320
void = seek(current_db, current_table_pos+4)
209420
put4(nrecs)
2095
209620
void = seek(current_db, current_table_pos+12)
209720
index_ptr = get4()
2098
209920
void = seek(current_db, index_ptr)
210020
r = 0
210120
while TRUE do
210236
nrecs = get4()
210336
records_ptr = get4()
210436
r += nrecs
210536
if r >= key_location then
210620
exit
2107
end if
210816
end while
2109
211020
r -= nrecs
211120
current_block = where(current_db)-8
211220
nrecs -= 1
2113
211420
if nrecs = 0 and blocks > 1 then
2115
-- delete this block from the index (unless it's the very last block)
21160
remaining = get_bytes(current_db, index_ptr+blocks*8-(current_block+8))
21170
void = seek(current_db, current_block)
21180
putn(remaining)
21190
void = seek(current_db, current_table_pos+8)
21200
put4(blocks-1)
21210
db_free(records_ptr)
2122
else
212320
key_location -= r
2124
-- decrement the record count in the index
212520
void = seek(current_db, current_block)
212620
put4(nrecs)
2127
-- delete one record
212820
void = seek(current_db, records_ptr+4*(key_location-1))
212920
for i = key_location to nrecs do
2130235
put4(key_pointers[i+r])
2131235
end for
2132
end if
213320
end procedure
2134
2135
--**
2136
-- In the current database, replace the data portion of a record with new data.
2137
-- This can be used to quickly update records that have already been located
2138
-- by calling [[:db_get_recid]]. This operation is faster than using
2139
-- [[:db_replace_data]]
2140
--
2141
-- Parameters:
2142
-- # ##recid## : an atom, the ##recid## of the record to be updated.
2143
-- # ##data## : an object, the new value of the record.
2144
--
2145
-- Comments:
2146
-- * ##recid## must be fetched using [[:db_get_recid]] first.
2147
-- * ##data## is an Euphoria object of any kind, atom or sequence.
2148
-- * The ##recid## does not have to be from the current table.
2149
-- * This does no error checking. It assumes the database is open and valid.
2150
--
2151
-- Example 1:
2152
--
2153
-- rid = db_get_recid("Peter")
2154
-- rec = db_record_recid(rid)
2155
-- rec[2][3] *= 1.10
2156
-- db_replace_recid(rid, rec[2])
2157
--
2158
--
2159
-- See Also:
2160
-- [[:db_replace_data]], [[:db_find_key]], [[:db_get_recid]]
2161
21623
2163
atom old_size, new_size, data_ptr
2164
sequence data_string
2165
21663
void = seek(current_db, recid)
21673
data_ptr = get4()
21683
void = seek(current_db, data_ptr-4)
21693
old_size = get4()-4
21703
data_string = compress(data)
21713
new_size = length(data_string)
21723
if new_size <= old_size and
2173
new_size >= old_size - 16 then
2174
-- keep the same data block
21751
void = seek(current_db, data_ptr)
2176
else
2177
-- free the old block
21782
db_free(data_ptr)
2179
-- get a new data block
21802
data_ptr = db_allocate(new_size + 8)
21812
void = seek(current_db, recid)
21822
put4(data_ptr)
21832
void = seek(current_db, data_ptr)
2184
2185
-- if the data comes from the end of the file, we need to
2186
-- make sure it gets filled
21872
data_string &= repeat( 0, 8 )
2188
2189
end if
21903
putn(data_string)
21913
end procedure
2192
2193
--**
2194
-- In the current table, replace the data portion of a record with new data.
2195
--
2196
-- Parameters:
2197
-- # ##key_location##: an integer, the index of the record the data is to be altered.
2198
-- # ##data##: an object , the new value associated to the key of the record.
2199
-- # ##table_name##: optional table name of record to replace data in.
2200
--
2201
-- Comments:
2202
--##key_location## must be from 1 to the number of records in the
2203
-- current table.
2204
-- ##data## is an Euphoria object of any kind, atom or sequence.
2205
--
2206
-- Example 1:
2207
--
2208
-- db_replace_data(67, {"Peter", 150, 34.5})
2209
--
2210
--
2211
-- See Also:
2212
-- [[:db_find_key]]
2213
22142
22152
if not equal(table_name, current_table_name) then
22162
if db_select_table(table_name) != DB_OK then
22170
fatal(NO_TABLE, "invalid table name given", "db_replace_data", {key_location, data, table_name})
22180
return
2219
end if
2220
end if
2221
22222
if current_table_pos = -1 then
22230
fatal(NO_TABLE, "no table selected", "db_replace_data", {key_location, data, table_name})
22240
return
2225
end if
22262
if key_location < 1 or key_location > length(key_pointers) then
22270
fatal(BAD_RECNO, "bad record number", "db_replace_data", {key_location, data, table_name})
22280
return
2229
end if
22302
db_replace_recid(key_pointers[key_location], data)
22312
end procedure
2232
2233
--**
2234
-- Get the size (number of records) of the default table.
2235
--
2236
-- Parameters:
2237
-- # ##table_name## : optional table name to get the size of.
2238
--
2239
-- Returns
2240
-- An **integer**, the current number of records in the current table.
2241
-- If a value less than zero is returned, it means that an error occured.
2242
--
2243
-- Errors:
2244
-- If the current table is undefined, an error will occur.
2245
--
2246
-- Example 1:
2247
--
2248
-- -- look at all records in the current table
2249
-- for i = 1 to db_table_size() do
2250
-- if db_record_key(i) = 0 then
2251
-- puts(1, "0 key found\n")
2252
-- exit
2253
-- end if
2254
-- end for
2255
--
2256
--
2257
-- See Also:
2258
-- [[:db_replace_data]]
2259
226012
226112
if not equal(table_name, current_table_name) then
22623
if db_select_table(table_name) != DB_OK then
22630
fatal(NO_TABLE, "invalid table name given", "db_table_size", {table_name})
22640
return -1
2265
end if
2266
end if
2267
226812
if current_table_pos = -1 then
22690
fatal(NO_TABLE, "no table selected", "db_table_size", {table_name})
22700
return -1
2271
end if
227212
return length(key_pointers)
2273
end function
2274
2275
--**
2276
-- Returns the data in a record queried by position.
2277
--
2278
-- Parameters:
2279
-- # ##key_location## : the index of the record the data of which is being fetched.
2280
-- # ##table_name## : optional table name to get record data from.
2281
--
2282
-- Returns:
2283
-- An **object**, the data portion of requested record.\\
2284
-- **NOTE** This function calls ##fatal##() and returns a value of -1 if an error prevented
2285
-- the correct data being returned.
2286
--
2287
-- Comments:
2288
-- Each record in a Euphoria database consists of a key portion and a data
2289
-- portion. Each of these can be any Euphoria atom or sequence.
2290
--
2291
-- Errors:
2292
-- If the current table is not defined, or if the record index is invalid, an error will occur.
2293
--
2294
-- Example 1:
2295
--
2296
-- puts(1, "The 6th record has data value: ")
2297
-- ? db_record_data(6)
2298
--
2299
--
2300
-- See Also:
2301
-- [[:db_find_key]], [[:db_replace_data]]
2302
230392
2304
atom data_ptr
2305
object data_value
2306
230792
if not equal(table_name, current_table_name) then
23082
if db_select_table(table_name) != DB_OK then
23090
fatal(NO_TABLE, "invalid table name given", "db_record_data", {key_location, table_name})
23100
return -1
2311
end if
2312
end if
2313
231492
if current_table_pos = -1 then
23150
fatal(NO_TABLE, "no table selected", "db_record_data", {key_location, table_name})
23160
return -1
2317
end if
231892
if key_location < 1 or key_location > length(key_pointers) then
23191
fatal(BAD_RECNO, "bad record number", "db_record_data", {key_location, table_name})
23201
return -1
2321
end if
2322
232391
safe_seek(key_pointers[key_location])
232491
if length(vLastErrors) > 0 then return -1 end if
232591
data_ptr = get4()
232691
void = seek(current_db, data_ptr)
232791
data_value = decompress(0)
2328
232991
return data_value
2330
end function
2331
2332
--**
2333
-- Returns the data for the record with supplied key.
2334
--
2335
-- Parameters:
2336
-- # ##key## : the identifier of the record to be looked up.
2337
-- # ##table_name## : optional name of table to find key in
2338
--
2339
-- Returns:
2340
-- An **integer**,
2341
-- * If less than zero, the record was not found. The returned integer
2342
-- is the opposite of what the record number would have been, had
2343
-- the record been found.
2344
-- * If equal to zero, an error occured.
2345
-- A sequence, the data for the record.
2346
--
2347
-- Errors:
2348
-- If the current table is not defined, it returns 0.
2349
--
2350
-- Comments:
2351
-- Each record in a Euphoria database consists of a key portion and a data
2352
-- portion. Each of these can be any Euphoria atom or sequence. **NOTE** This
2353
-- function does not support records that data consists of a single non-sequence value.
2354
-- In those cases you will need to use [[:db_find_key]] and [[:db_record_data]].
2355
--
2356
-- Example 1:
2357
--
2358
-- printf(1, "The record['%s'] has data value:\n", {"foo"})
2359
-- ? db_fetch_record("foo")
2360
--
2361
--
2362
-- See Also:
2363
-- [[:db_find_key]], [[:db_record_data]]
2364
23650
2366
integer pos
2367
23680
pos = db_find_key(key, table_name)
23690
if pos > 0 then
23700
return db_record_data(pos, table_name)
2371
else
23720
return pos
2373
end if
2374
end function
2375
2376
--**
2377
-- Parameters:
2378
-- # ##key_location## : an integer, the index of the record the key is being requested.
2379
-- # ##table_name## : optional table name to get record key from.
2380
--
2381
-- Returns
2382
-- An **object**, the key of the record being queried by index.\\
2383
-- **NOTE** This function calls fatal() and returns a value of -1 if an error prevented
2384
-- the correct data being returned.
2385
--
2386
-- Errors:
2387
-- If the current table is not defined, or if the record index is invalid, an error will occur.
2388
--
2389
-- Comments:
2390
-- Each record in a Euphoria database consists of a key portion and a
2391
-- data portion. Each of these can be any Euphoria atom or sequence.
2392
--
2393
-- Example 1:
2394
--
2395
-- puts(1, "The 6th record has key value: ")
2396
-- ? db_record_key(6)
2397
--
2398
-- See Also:
2399
-- [[:db_record_data]]
2400
240187
240287
if not equal(table_name, current_table_name) then
24030
if db_select_table(table_name) != DB_OK then
24040
fatal(NO_TABLE, "invalid table name given", "db_record_key", {key_location, table_name})
24050
return -1
2406
end if
2407
end if
2408
240987
if current_table_pos = -1 then
24100
fatal(NO_TABLE, "no table selected", "db_record_key", {key_location, table_name})
24110
return -1
2412
end if
241387
if key_location < 1 or key_location > length(key_pointers) then
24140
fatal(BAD_RECNO, "bad record number", "db_record_key", {key_location, table_name})
24150
return -1
2416
end if
241787
return key_value(key_pointers[key_location])
2418
end function
2419
2420
--**
2421
-- Returns the key and data in a record queried by ##recid##.
2422
--
2423
-- Parameters:
2424
-- # ##recid## : the ##recid## of the required record, which has been
2425
-- previously fetched using [[:db_get_recid]].
2426
--
2427
-- Returns:
2428
-- An **sequence**, the first element is the key and the second element
2429
-- is the data portion of requested record.
2430
--
2431
-- Comments:
2432
-- * This is much faster than calling [[:db_record_key]] and [[:db_record_data]].
2433
-- * This does no error checking. It assumes the database is open and valid.
2434
-- * This function does not need the requested record to be from the current
2435
-- table. The ##recid## can refer to a record in any table.
2436
--
2437
-- Example 1:
2438
--
2439
-- rid = db_get_recid("SomeKey")
2440
-- ? db_record_recid(rid)
2441
--
2442
--
2443
-- See Also:
2444
-- [[:db_get_recid]], [[:db_replace_recid]]
2445
24463
2447
atom data_ptr
2448
object data_value
2449
object key_value
2450
24513
void = seek(current_db, recid)
24523
data_ptr = get4()
24533
key_value = decompress(0)
24543
void = seek(current_db, data_ptr)
24553
data_value = decompress(0)
2456
24573
return {key_value, data_value}
2458
end function
2459
2460
--**
2461
-- Compresses the current database.
2462
--
2463
-- Returns:
2464
-- An **integer**, either DB_OK on success or an error code on failure.
2465
--
2466
-- Comments:
2467
-- The current database is copied to a new
2468
-- file such that any blocks of unused space are eliminated. If successful,
2469
-- the return value will be set to ##DB_OK##, and the new compressed database
2470
-- file will retain the same name. The current table will be undefined. As
2471
-- a backup, the original, uncompressed file will be renamed with an extension
2472
-- of .t0 (or .t1, .t2, ..., .t99). In the highly unusual case that the
2473
-- compression is unsuccessful, the database will be left unchanged, and no
2474
-- backup will be made.
2475
--
2476
-- When you delete items from a database, you create blocks of free space within
2477
-- the database file. The system keeps track of these blocks and tries to use them
2478
-- for storing new data that you insert. db_compress() will copy the current
2479
-- database without copying these free areas. The size of the database file may
2480
-- therefore be reduced. If the backup filenames reach .t99 you will have to
2481
-- delete some of them.
2482
--
2483
-- Example 1:
2484
--
2485
-- if db_compress() != DB_OK then
2486
-- puts(2, "compress failed!\n")
2487
-- end if
2488
--
2489
24901
2491
integer index, chunk_size, nrecs, r, fn
2492
sequence new_path, old_path, table_list, record, chunk
2493
24941
if current_db = -1 then
24950
fatal(NO_DATABASE, "no current database", "db_compress", {})
24960
return -1
2497
end if
2498
24991
index = eu:find(current_db, db_file_nums)
25001
new_path = trim(db_names[index])
25011
db_close()
2502
25031
fn = -1
25041
sequence temp_path = temp_file()
25051
fn = open( temp_path, "r" )
25061
if fn != -1 then
25070
return DB_EXISTS_ALREADY -- you better delete some temp files
2508
end if
2509
25101
move_file( new_path, temp_path )
2511
2512
-- create a new database
25131
index = db_create(new_path, DB_LOCK_NO)
25141
if index != DB_OK then
25150
move_file( temp_path, new_path )
25160
return index
2517
end if
2518
25191
index = db_open(temp_path, DB_LOCK_NO)
25201
table_list = db_table_list()
2521
25221
for i = 1 to length(table_list) do
25232
index = db_select(new_path)
25242
index = db_create_table(table_list[i])
2525
25262
index = db_select(temp_path)
25272
index = db_select_table(table_list[i])
2528
25292
nrecs = db_table_size()
25302
r = 1
25312
while r <= nrecs do
25326
chunk_size = nrecs - r + 1
25336
if chunk_size > 20 then
25344
chunk_size = 20 -- copy up to 20 records at a time
2535
end if
2536
-- read a bunch of records
25376
chunk = {}
25386
for j = 1 to chunk_size do
253987
record = {db_record_key(r), db_record_data(r)}
254087
r += 1
254187
chunk = append(chunk, record)
254287
end for
2543
-- switch to new table
25446
index = db_select(new_path)
25456
index = db_select_table(table_list[i])
2546
-- insert a bunch of records
25476
for j = 1 to chunk_size do
254887
if db_insert(chunk[j][1], chunk[j][2]) != DB_OK then
25490
fatal(INSERT_FAILED, "couldn't insert into new database", "db_compress", {})
25500
return DB_FATAL_FAIL
2551
end if
255287
end for
2553
-- switch back to old table
25546
index = db_select(temp_path)
25556
index = db_select_table(table_list[i])
25566
end while
25572
end for
25581
db_close()
25591
index = db_select(new_path)
25601
return DB_OK
2561
end function
2562
2563
--**
2564
-- Get name of currently selected database.
2565
--
2566
-- Parameters:
2567
-- # None.
2568
--
2569
-- Returns:
2570
-- A **sequence**, the name of the current database. An empty string means
2571
-- that no database is currently selected.
2572
--
2573
-- Comments:
2574
-- The actual name returned is the //path// as supplied to the db_open routine.
2575
--
2576
-- Example 1:
2577
--
2578
-- s = db_current_database()
2579
--
2580
--
2581
-- See Also:
2582
-- [[:db_select]]
2583
25846
2585
integer index
2586
25876
index = find (current_db, db_file_nums)
25886
if index != 0 then
25893
return db_names [index]
2590
else
25913
return ""
2592
end if
2593
end function
2594
2595
--**
2596
-- Forces the database index cache to be cleared.
2597
--
2598
-- Parameters:
2599
-- None
2600
--
2601
-- Comments:
2602
-- * This is not normally required to the run. You might run it to set up a
2603
-- predetermined state for performance timing, or to release some memory back to the
2604
-- application.
2605
--
2606
-- Example 1:
2607
--
2608
-- db_cache_clear() -- Clear the cache.
2609
--
2610
26111
26121
cache_index = {}
26131
key_cache = {}
26141
end procedure
2615
2616
--**
2617
-- Sets the key cache behavior.\\
2618
-- Initially, the cache option is turned on. This means that when possible, the
2619
-- keys of a table are kept in RAM rather than read from disk each time
2620
-- ##db_select_table##() is called. For most databases, this will improve performance
2621
-- when you have more than one table in it.
2622
--
2623
-- Parameters:
2624
-- # ##integer## : 0 will turn of caching, 1 will turn it back on.
2625
--
2626
-- Returns:
2627
-- An **integer**, the previous setting of the option.
2628
--
2629
-- Comments:
2630
-- When caching is turned off, the current cache contents is totally cleared.
2631
--
2632
-- Example 1:
2633
--
2634
-- x = db_set_caching(0) -- Turn off key caching.
2635
--
2636
26372
2638
integer lOldVal
2639
26402
lOldVal = caching_option
26412
caching_option = (new_setting != 0)
2642
26432
if caching_option = 0 then
2644
-- Wipe existing cache data.
26451
db_cache_clear()
2646
end if
26472
return lOldVal
2648
end function