KirbyBase 2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/README +73 -0
  2. data/bin/kbserver.rb +20 -0
  3. data/changes.txt +105 -0
  4. data/examples/aaa_try_this_first/kbtest.rb +207 -0
  5. data/examples/add_column_test/add_column_test.rb +27 -0
  6. data/examples/calculated_field_test/calculated_field_test.rb +51 -0
  7. data/examples/change_column_type_test/change_column_type_test.rb +25 -0
  8. data/examples/column_required_test/column_required_test.rb +33 -0
  9. data/examples/crosstab_test/crosstab_test.rb +100 -0
  10. data/examples/csv_import_test/csv_import_test.rb +31 -0
  11. data/examples/csv_import_test/plane.csv +11 -0
  12. data/examples/default_value_test/default_value_test.rb +43 -0
  13. data/examples/drop_column_test/drop_column_test.rb +24 -0
  14. data/examples/indexes_test/add_index_test.rb +46 -0
  15. data/examples/indexes_test/drop_index_test.rb +66 -0
  16. data/examples/indexes_test/index_test.rb +71 -0
  17. data/examples/kbserver_as_win32_service/kbserver_daemon.rb +47 -0
  18. data/examples/kbserver_as_win32_service/kbserverctl.rb +75 -0
  19. data/examples/link_many_test/link_many_test.rb +70 -0
  20. data/examples/lookup_field_test/lookup_field_test.rb +55 -0
  21. data/examples/lookup_field_test/lookup_field_test_2.rb +62 -0
  22. data/examples/lookup_field_test/the_hal_fulton_feature_test.rb +69 -0
  23. data/examples/many_to_many_test/many_to_many_test.rb +65 -0
  24. data/examples/memo_test/memo_test.rb +63 -0
  25. data/examples/memo_test/memos/blank.txt +0 -0
  26. data/examples/record_class_test/record_class_test.rb +77 -0
  27. data/examples/rename_column_test/rename_column_test.rb +46 -0
  28. data/examples/rename_table_test/rename_table_test.rb +38 -0
  29. data/examples/yaml_field_test/yaml_field_test.rb +47 -0
  30. data/images/blank.png +0 -0
  31. data/images/callouts/1.png +0 -0
  32. data/images/callouts/10.png +0 -0
  33. data/images/callouts/11.png +0 -0
  34. data/images/callouts/12.png +0 -0
  35. data/images/callouts/13.png +0 -0
  36. data/images/callouts/14.png +0 -0
  37. data/images/callouts/15.png +0 -0
  38. data/images/callouts/2.png +0 -0
  39. data/images/callouts/3.png +0 -0
  40. data/images/callouts/4.png +0 -0
  41. data/images/callouts/5.png +0 -0
  42. data/images/callouts/6.png +0 -0
  43. data/images/callouts/7.png +0 -0
  44. data/images/callouts/8.png +0 -0
  45. data/images/callouts/9.png +0 -0
  46. data/images/caution.png +0 -0
  47. data/images/client_server.png +0 -0
  48. data/images/example.png +0 -0
  49. data/images/home.png +0 -0
  50. data/images/important.png +0 -0
  51. data/images/kirby1.jpg +0 -0
  52. data/images/next.png +0 -0
  53. data/images/note.png +0 -0
  54. data/images/prev.png +0 -0
  55. data/images/single_user.png +0 -0
  56. data/images/smallnew.png +0 -0
  57. data/images/tip.png +0 -0
  58. data/images/toc-blank.png +0 -0
  59. data/images/toc-minus.png +0 -0
  60. data/images/toc-plus.png +0 -0
  61. data/images/up.png +0 -0
  62. data/images/warning.png +0 -0
  63. data/kirbybaserubymanual.html +2243 -0
  64. data/lib/kirbybase.rb +3662 -0
  65. metadata +126 -0
@@ -0,0 +1,63 @@
1
+ # This script is an example of how you can use KirbyBase's new Memo field
2
+ # type.
3
+
4
+ require 'kirbybase'
5
+
6
+ db = KirbyBase.new { |d| d.memo_blob_path = './memos' }
7
+
8
+ #db = KirbyBase.new(:client, 'localhost', 44444)
9
+
10
+
11
+ # If table exists, delete it.
12
+ db.drop_table(:plane) if db.table_exists?(:plane)
13
+
14
+ # Create a table.
15
+ plane_tbl = db.create_table(:plane, :name, :String, :country, :String,
16
+ :speed, :Integer, :range, :Integer, :descr, :Memo)
17
+
18
+ # Create a long string field with embedded newlines for the memo contents.
19
+ memo_string = <<END_OF_STRING
20
+ The P-51 Mustang was the premier Allied fighter aircraft of World War II.
21
+ It's performance and long range allowed it to escort Allied strategic
22
+ bombers on raids deep inside Germany.
23
+ END_OF_STRING
24
+
25
+ # Create an instance of KBMemo for the memo field.
26
+ memo = KBMemo.new(db, 'P-51.txt', memo_string)
27
+
28
+ # Insert the new record, including the memo field.
29
+ plane_tbl.insert('P-51', 'USA', 403, 1201, memo)
30
+
31
+ # Insert another record.
32
+ memo_string = <<END_OF_STRING
33
+ The FW-190 was a World War II German fighter. It was used primarily as an
34
+ interceptor against Allied strategic bombers.
35
+ END_OF_STRING
36
+
37
+ memo = KBMemo.new(db, 'FW-190.txt', memo_string)
38
+ plane_tbl.insert('FW-190', 'Germany', 399, 499, memo)
39
+
40
+ # Select all records, print name, country, speed and range on first line.
41
+ # Then, print contents of memo field below.
42
+ plane_tbl.select.each { |r|
43
+ puts "Name: %s Country: %s Speed: %d Range: %d\n\n" % [r.name,
44
+ r.country, r.speed, r.range]
45
+ puts r.descr.contents
46
+ puts "\n" + "-" * 75 + "\n\n"
47
+ }
48
+
49
+
50
+ puts "\n\nNow we will change the memo for the P-51:\n\n"
51
+
52
+ # Grab the P-51's record.
53
+ rec = plane_tbl.select { |r| r.name == 'P-51' }.first
54
+
55
+ # Grab the contents of the memo field and add a line to it.
56
+ memo = rec.descr
57
+ memo.contents += "This last line should show up if the memo was changed."
58
+
59
+ # Now, update the record with the changed contents of the memo field.
60
+ plane_tbl.update {|r| r.name == 'P-51'}.set(:descr => memo)
61
+
62
+ # Do another select to show that the memo field indeed changed.
63
+ puts plane_tbl.select { |r| r.name == 'P-51' }.first.descr.contents
File without changes
@@ -0,0 +1,77 @@
1
+ #Test of returning result set composed of instances of user class.
2
+
3
+ require 'kirbybase'
4
+
5
+ class Foobar
6
+ attr_accessor(:recno, :name, :country, :role, :speed, :range,
7
+ :began_service, :still_flying, :alpha, :beta)
8
+
9
+ def Foobar.kb_create(recno, name, country, role, speed, range,
10
+ began_service, still_flying)
11
+ name ||= 'No Name!'
12
+ speed ||= 0
13
+ began_service ||= Date.today
14
+ Foobar.new do |x|
15
+ x.recno = recno
16
+ x.name = name
17
+ x.country = country
18
+ x.role = role
19
+ x.speed = speed
20
+ x.range = range
21
+ x.began_service = began_service
22
+ x.still_flying = still_flying
23
+ end
24
+ end
25
+
26
+ def initialize(&block)
27
+ instance_eval(&block)
28
+ end
29
+ end
30
+
31
+ # To run local, single-user, uncomment next line.
32
+ db = KirbyBase.new
33
+
34
+ # If table exists, delete it.
35
+ db.drop_table(:plane) if db.table_exists?(:plane)
36
+
37
+ # Create a table. Notice how you set record_class equal to your class.
38
+ plane_tbl = db.create_table do |t|
39
+ t.name = :plane
40
+ t.field_defs = [:name, :String, :country, :String, :role, :String,
41
+ :speed, :Integer, :range, :Integer, :began_service, :Date,
42
+ :still_flying, :Boolean]
43
+ t.encrypt = false
44
+ t.record_class = Foobar
45
+ end
46
+
47
+ plane_tbl = db.get_table(:plane)
48
+
49
+ # Insert a record using an instance of Foobar.
50
+ foo = Foobar.new do |x|
51
+ x.name = 'Spitfire'
52
+ x.country = 'Great Britain'
53
+ x.role = 'Fighter'
54
+ x.speed = 333
55
+ x.range = 454
56
+ x.began_service = Date.new(1936, 1, 1)
57
+ x.still_flying = true
58
+ x.alpha = "This variable won't be stored in KirbyBase."
59
+ x.beta = 'Neither will this one.'
60
+ end
61
+ plane_tbl.insert(foo)
62
+
63
+ # Notice how select returns instances of Foobar, since it was defined as the
64
+ # record class.
65
+ recs = plane_tbl.select
66
+ puts "Example using #kb_create"
67
+ puts recs[0].class
68
+
69
+ # Now we are going to change a couple of fields of the Spitfire's Foobar
70
+ # object and update the Spitfire record in the Plane table with the updated
71
+ # Foobar object.
72
+ recs[0].speed = 344
73
+ recs[0].range = 555
74
+ plane_tbl.update(recs[0]) {|r| r.name == 'Spitfire'}
75
+
76
+ # Here's proof that the table was updated.
77
+ p plane_tbl.select {|r| r.name == 'Spitfire'}
@@ -0,0 +1,46 @@
1
+ # This script is an example of how to rename a column.
2
+ #
3
+ require 'kirbybase'
4
+
5
+ db = KirbyBase.new
6
+
7
+ # If table exists, delete it.
8
+ db.drop_table(:address_book) if db.table_exists?(:address_book)
9
+
10
+ address_book_tbl = db.create_table(:address_book,
11
+ :firstname, :String, :lastname, :String, :street_address, :String,
12
+ :city, :String, :phone, :String, :category, :String
13
+ )
14
+
15
+ # Insert some contact info records.
16
+ address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
17
+ '111-111-1111', 'Super Hero')
18
+ address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
19
+ '222-222-2222', 'Cartoon Character')
20
+ address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
21
+ 'Washington', '333-333-3333', 'President')
22
+ address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
23
+ 'Any City', '444-444-4444', 'Super Hero')
24
+
25
+ address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
26
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
27
+ }
28
+ puts;puts
29
+
30
+ address_book_tbl.rename_column(:phone, :phone_no)
31
+
32
+ begin
33
+ address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
34
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
35
+ }
36
+ rescue StandardError => e
37
+ puts e
38
+ puts;puts
39
+ end
40
+
41
+ address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
42
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone_no]
43
+ }
44
+ puts;puts
45
+
46
+ p address_book_tbl.field_names
@@ -0,0 +1,38 @@
1
+ # This script is an example of how to rename a table.
2
+ #
3
+ require 'kirbybase'
4
+
5
+ db = KirbyBase.new
6
+
7
+ # If tables exist, delete them.
8
+ db.drop_table(:address_book) if db.table_exists?(:address_book)
9
+ db.drop_table(:contact_list) if db.table_exists?(:contact_list)
10
+
11
+ address_book_tbl = db.create_table(:address_book,
12
+ :firstname, :String, :lastname, :String, :street_address, :String,
13
+ :city, :String, :phone, :String, :category, :String
14
+ )
15
+
16
+ # Insert some contact info records.
17
+ address_book_tbl.insert('Bruce', 'Wayne', '1234 Bat Cave', 'Gotham City',
18
+ '111-111-1111', 'Super Hero')
19
+ address_book_tbl.insert('Bugs', 'Bunny', '1234 Rabbit Hole', 'The Forest',
20
+ '222-222-2222', 'Cartoon Character')
21
+ address_book_tbl.insert('George', 'Bush', '1600 Pennsylvania Ave',
22
+ 'Washington', '333-333-3333', 'President')
23
+ address_book_tbl.insert('Silver', 'Surfer', '1234 Galaxy Way',
24
+ 'Any City', '444-444-4444', 'Super Hero')
25
+
26
+ address_book_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
27
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
28
+ }
29
+ puts;puts
30
+
31
+ contact_list_tbl = db.rename_table(:address_book, :contact_list)
32
+
33
+ contact_list_tbl.select { |r| r.category == 'Super Hero' }.each { |r|
34
+ puts '%s %s %s' % [r.firstname, r.lastname, r.phone]
35
+ }
36
+ puts;puts
37
+
38
+ p db.tables
@@ -0,0 +1,47 @@
1
+ #Test of YAML field type.
2
+
3
+ require 'kirbybase'
4
+
5
+ # To run local, single-user, uncomment next line.
6
+ db = KirbyBase.new
7
+
8
+ # To run as a client in a multi-user environment, uncomment next line.
9
+ # Also, make sure kbserver.rb is running.
10
+ #db = KirbyBase.new do |d|
11
+ # d.connect_type = :client
12
+ # d.host = 'localhost'
13
+ # d.port = 44444
14
+ #end
15
+
16
+ # If table exists, delete it.
17
+ db.drop_table(:pet) if db.table_exists?(:pet)
18
+
19
+ # Create a table.
20
+ pet_tbl = db.create_table(:pet, :name, :String, :pet_type, :String,
21
+ :born, :Date, :characteristics, :YAML)
22
+
23
+ pet_tbl.insert('Kirby', 'dog', Date.new(2002, 06, 01),
24
+ ['cute', 'stinky', 4, 55.6])
25
+ pet_tbl.insert('Mojo', 'cat', Date.new(2000, 04, 01),
26
+ ['cute', 'soft', '6', 12.25])
27
+ pet_tbl.insert('Goldy', 'fish', Date.new(2004, 10, 10),
28
+ nil)
29
+
30
+ pet_tbl.select.each { |r|
31
+ puts '%s %s' % [r.name, r.characteristics[1]]
32
+ }
33
+
34
+ puts
35
+
36
+ pet_tbl.select { |r| r.characteristics.include?('stinky') }.each { |r|
37
+ puts '%s smells like a dog!' % r.name
38
+ }
39
+
40
+ pet_tbl.update { |r| r.name == 'Goldy' }.set(
41
+ :characteristics => ['small', 'slimy', 2, 0.02])
42
+
43
+ puts
44
+ pet_tbl.select.each { |r|
45
+ puts '%s %s' % [r.name, r.characteristics.join(' ')]
46
+ }
47
+
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,2243 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <meta name="generator" content="AsciiDoc 7.0.2" />
7
+ <style type="text/css">
8
+ /* Debug borders */
9
+ p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
10
+ /*
11
+ border: 1px solid red;
12
+ */
13
+ }
14
+
15
+ body {
16
+ margin: 1em 5% 1em 5%;
17
+ }
18
+
19
+ a { color: blue; }
20
+ a:visited { color: fuchsia; }
21
+
22
+ em {
23
+ font-style: italic;
24
+ }
25
+
26
+ strong {
27
+ font-weight: bold;
28
+ }
29
+
30
+ tt {
31
+ color: navy;
32
+ }
33
+
34
+ h1, h2, h3, h4, h5, h6 {
35
+ color: #527bbd;
36
+ font-family: sans-serif;
37
+ margin-top: 1.2em;
38
+ margin-bottom: 0.5em;
39
+ line-height: 1.3;
40
+ }
41
+
42
+ h1 {
43
+ border-bottom: 2px solid silver;
44
+ }
45
+ h2 {
46
+ border-bottom: 2px solid silver;
47
+ padding-top: 0.5em;
48
+ }
49
+
50
+ div.sectionbody {
51
+ font-family: serif;
52
+ margin-left: 0;
53
+ }
54
+
55
+ hr {
56
+ border: 1px solid silver;
57
+ }
58
+
59
+ p {
60
+ margin-top: 0.5em;
61
+ margin-bottom: 0.5em;
62
+ }
63
+
64
+ pre {
65
+ padding: 0;
66
+ margin: 0;
67
+ }
68
+
69
+ span#author {
70
+ color: #527bbd;
71
+ font-family: sans-serif;
72
+ font-weight: bold;
73
+ font-size: 1.2em;
74
+ }
75
+ span#email {
76
+ }
77
+ span#revision {
78
+ font-family: sans-serif;
79
+ }
80
+
81
+ div#footer {
82
+ font-family: sans-serif;
83
+ font-size: small;
84
+ border-top: 2px solid silver;
85
+ padding-top: 0.5em;
86
+ margin-top: 4.0em;
87
+ }
88
+ div#footer-text {
89
+ float: left;
90
+ padding-bottom: 0.5em;
91
+ }
92
+ div#footer-badges {
93
+ float: right;
94
+ padding-bottom: 0.5em;
95
+ }
96
+
97
+ div#preamble,
98
+ div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
99
+ div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
100
+ div.admonitionblock {
101
+ margin-right: 10%;
102
+ margin-top: 1.5em;
103
+ margin-bottom: 1.5em;
104
+ }
105
+ div.admonitionblock {
106
+ margin-top: 2.5em;
107
+ margin-bottom: 2.5em;
108
+ }
109
+
110
+ div.content { /* Block element content. */
111
+ padding: 0;
112
+ }
113
+
114
+ /* Block element titles. */
115
+ div.title, caption.title {
116
+ font-family: sans-serif;
117
+ font-weight: bold;
118
+ text-align: left;
119
+ margin-top: 1.0em;
120
+ margin-bottom: 0.5em;
121
+ }
122
+ div.title + * {
123
+ margin-top: 0;
124
+ }
125
+
126
+ td div.title:first-child {
127
+ margin-top: 0.0em;
128
+ }
129
+ div.content div.title:first-child {
130
+ margin-top: 0.0em;
131
+ }
132
+ div.content + div.title {
133
+ margin-top: 0.0em;
134
+ }
135
+
136
+ div.sidebarblock > div.content {
137
+ background: #ffffee;
138
+ border: 1px solid silver;
139
+ padding: 0.5em;
140
+ }
141
+
142
+ div.listingblock > div.content {
143
+ border: 1px solid silver;
144
+ background: #f4f4f4;
145
+ padding: 0.5em;
146
+ }
147
+
148
+ div.quoteblock > div.content {
149
+ padding-left: 2.0em;
150
+ }
151
+ div.quoteblock .attribution {
152
+ text-align: right;
153
+ }
154
+
155
+ div.admonitionblock .icon {
156
+ vertical-align: top;
157
+ font-size: 1.1em;
158
+ font-weight: bold;
159
+ text-decoration: underline;
160
+ color: #527bbd;
161
+ padding-right: 0.5em;
162
+ }
163
+ div.admonitionblock td.content {
164
+ padding-left: 0.5em;
165
+ border-left: 2px solid silver;
166
+ }
167
+
168
+ div.exampleblock > div.content {
169
+ border-left: 2px solid silver;
170
+ padding: 0.5em;
171
+ }
172
+
173
+ div.verseblock div.content {
174
+ white-space: pre;
175
+ }
176
+
177
+ div.imageblock div.content { padding-left: 0; }
178
+ div.imageblock img { border: 1px solid silver; }
179
+ span.image img { border-style: none; }
180
+
181
+ dl {
182
+ margin-top: 0.8em;
183
+ margin-bottom: 0.8em;
184
+ }
185
+ dt {
186
+ margin-top: 0.5em;
187
+ margin-bottom: 0;
188
+ font-style: italic;
189
+ }
190
+ dd > *:first-child {
191
+ margin-top: 0;
192
+ }
193
+
194
+ ul, ol {
195
+ list-style-position: outside;
196
+ }
197
+ ol.olist2 {
198
+ list-style-type: lower-alpha;
199
+ }
200
+
201
+ div.tableblock > table {
202
+ border-color: #527bbd;
203
+ border-width: 3px;
204
+ }
205
+ thead {
206
+ font-family: sans-serif;
207
+ font-weight: bold;
208
+ }
209
+ tfoot {
210
+ font-weight: bold;
211
+ }
212
+
213
+ div.hlist {
214
+ margin-top: 0.8em;
215
+ margin-bottom: 0.8em;
216
+ }
217
+ td.hlist1 {
218
+ vertical-align: top;
219
+ font-style: italic;
220
+ padding-right: 0.8em;
221
+ }
222
+ td.hlist2 {
223
+ vertical-align: top;
224
+ }
225
+
226
+ @media print {
227
+ div#footer-badges { display: none; }
228
+ }
229
+ /* Workarounds for IE6's broken and incomplete CSS2. */
230
+
231
+ div.sidebar-content {
232
+ background: #ffffee;
233
+ border: 1px solid silver;
234
+ padding: 0.5em;
235
+ }
236
+ div.sidebar-title, div.image-title {
237
+ font-family: sans-serif;
238
+ font-weight: bold;
239
+ margin-top: 0.0em;
240
+ margin-bottom: 0.5em;
241
+ }
242
+
243
+ div.listingblock div.content {
244
+ border: 1px solid silver;
245
+ background: #f4f4f4;
246
+ padding: 0.5em;
247
+ }
248
+
249
+ div.quoteblock-content {
250
+ padding-left: 2.0em;
251
+ }
252
+
253
+ div.exampleblock-content {
254
+ border-left: 2px solid silver;
255
+ padding-left: 0.5em;
256
+ }
257
+ </style>
258
+ <title>KirbyBase Manual (Ruby Version)</title>
259
+ </head>
260
+ <body>
261
+ <div id="header">
262
+ <h1>KirbyBase Manual (Ruby Version)</h1>
263
+ <span id="author">Jamey Cribbs</span><br />
264
+ <span id="email"><tt>&lt;<a href="mailto:jcribbs@twmi.rr.com">jcribbs@twmi.rr.com</a>&gt;</tt></span><br />
265
+ <span id="revision">version 2.5,</span>
266
+ 1 December 2005
267
+ </div>
268
+ <div id="preamble">
269
+ <div class="sectionbody">
270
+ <div class="imageblock">
271
+ <div class="content">
272
+ <img src="images/kirby1.jpg" alt="images/kirby1.jpg"/>
273
+ </div>
274
+ <div class="image-title">Figure: Kirby pictured here in attack mode.</div>
275
+ </div>
276
+ </div>
277
+ </div>
278
+ <h2>Table of Contents</h2>
279
+ <div class="sectionbody">
280
+ <div class="sidebarblock">
281
+ <div class="sidebar-content">
282
+ <ol>
283
+ <li>
284
+ <p>
285
+ <a href="#introduction">Introduction</a>
286
+ </p>
287
+ </li>
288
+ <li>
289
+ <p>
290
+ <a href="#connecting-to-a-database">Connecting to a database</a>
291
+ </p>
292
+ </li>
293
+ <li>
294
+ <p>
295
+ <a href="#creating-a-new-table">Creating a new table</a>
296
+ </p>
297
+ <ol class="olist2">
298
+ <li>
299
+ <p>
300
+ <a href="#field-types">Database field types</a>
301
+ </p>
302
+ </li>
303
+ <li>
304
+ <p>
305
+ <a href="#recno">The recno field</a>
306
+ </p>
307
+ </li>
308
+ <li>
309
+ <p>
310
+ <a href="#defaults">Specifying default values</a>
311
+ </p>
312
+ </li>
313
+ <li>
314
+ <p>
315
+ <a href="#requireds">Specifying required fields</a>
316
+ </p>
317
+ </li>
318
+ <li>
319
+ <p>
320
+ <a href="#creating-indexes">Indexes</a>
321
+ </p>
322
+ </li>
323
+ <li>
324
+ <p>
325
+ <a href="#a-note-about-indexes">A note about indexes</a>
326
+ </p>
327
+ </li>
328
+ <li>
329
+ <p>
330
+ <a href="#creating-lookup-fields">Lookup Fields</a>
331
+ </p>
332
+ </li>
333
+ <li>
334
+ <p>
335
+ <a href="#creating-link-many-fields">Link_many Fields</a>
336
+ </p>
337
+ </li>
338
+ <li>
339
+ <p>
340
+ <a href="#creating-calculated-fields">Calculated Fields</a>
341
+ </p>
342
+ </li>
343
+ </ol>
344
+ </li>
345
+ <li>
346
+ <p>
347
+ <a href="#obtaining-a-reference-to-an-existing-table">Obtaining a reference to an existing table</a>
348
+ </p>
349
+ </li>
350
+ <li>
351
+ <p>
352
+ <a href="#insert-method">The insert method</a>
353
+ </p>
354
+ </li>
355
+ <li>
356
+ <p>
357
+ <a href="#how-to-select-records">How to select records</a>
358
+ </p>
359
+ <ol class="olist2">
360
+ <li>
361
+ <p>
362
+ <a href="#select-method">The select method</a>
363
+ </p>
364
+ </li>
365
+ <li>
366
+ <p>
367
+ <a href="#selecting-by-index">Selecting by index</a>
368
+ </p>
369
+ </li>
370
+ <li>
371
+ <p>
372
+ <a href="#selecting-by-recno-index">Selecting by :recno index</a>
373
+ </p>
374
+ </li>
375
+ <li>
376
+ <p>
377
+ <a href="#selects-involving-lookups-or-link-manys">Selects involving Lookups or Link_manys</a>
378
+ </p>
379
+ </li>
380
+ </ol>
381
+ </li>
382
+ <li>
383
+ <p>
384
+ <a href="#kbresultset">KBResultSet</a>
385
+ </p>
386
+ <ol class="olist2">
387
+ <li>
388
+ <p>
389
+ <a href="#sorting-a-result-set">Sorting a result set</a>
390
+ </p>
391
+ </li>
392
+ <li>
393
+ <p>
394
+ <a href="#to-report">Producing a report from a result set</a>
395
+ </p>
396
+ </li>
397
+ <li>
398
+ <p>
399
+ <a href="#crosstabs">CrossTabs or Pivot Tables or Column Arrays (i.e. I don't know what to call them!)</a>
400
+ </p>
401
+ </li>
402
+ </ol>
403
+ </li>
404
+ <li>
405
+ <p>
406
+ <a href="#how-to-update-records">How to update records</a>
407
+ </p>
408
+ <ol class="olist2">
409
+ <li>
410
+ <p>
411
+ <a href="#update-method">The update method</a>
412
+ </p>
413
+ </li>
414
+ <li>
415
+ <p>
416
+ <a href="#set-method">The set method</a>
417
+ </p>
418
+ </li>
419
+ <li>
420
+ <p>
421
+ <a href="#update-all-method">The update_all method</a>
422
+ </p>
423
+ </li>
424
+ </ol>
425
+ </li>
426
+ <li>
427
+ <p>
428
+ <a href="#how-to-delete-records">How to delete records</a>
429
+ </p>
430
+ <ol class="olist2">
431
+ <li>
432
+ <p>
433
+ <a href="#delete-method">The delete method</a>
434
+ </p>
435
+ </li>
436
+ <li>
437
+ <p>
438
+ <a href="#clear-method">The clear method</a>
439
+ </p>
440
+ </li>
441
+ </ol>
442
+ </li>
443
+ <li>
444
+ <p>
445
+ <a href="#pack-method">The pack method</a>
446
+ </p>
447
+ </li>
448
+ <li>
449
+ <p>
450
+ <a href="#memo-and-blob-fields">Memo and Blob Fields</a>
451
+ </p>
452
+ </li>
453
+ <li>
454
+ <p>
455
+ <a href="#misc-kirbybase-methods">Miscellaneous KirbyBase methods</a>
456
+ </p>
457
+ <ol class="olist2">
458
+ <li>
459
+ <p>
460
+ <a href="#drop-table">KirbyBase#drop_table</a>
461
+ </p>
462
+ </li>
463
+ <li>
464
+ <p>
465
+ <a href="#tables">KirbyBase#tables</a>
466
+ </p>
467
+ </li>
468
+ <li>
469
+ <p>
470
+ <a href="#table-exists">KirbyBase#table_exists?</a>
471
+ </p>
472
+ </li>
473
+ <li>
474
+ <p>
475
+ <a href="#rename-table">KirbyBase#rename_table</a>
476
+ </p>
477
+ </li>
478
+ </ol>
479
+ </li>
480
+ <li>
481
+ <p>
482
+ <a href="#misc-kbtable-methods">Miscellaneous KBTable methods</a>
483
+ </p>
484
+ <ol class="olist2">
485
+ <li>
486
+ <p>
487
+ <a href="#update-by-recno">KBTable#[]=</a>
488
+ </p>
489
+ </li>
490
+ <li>
491
+ <p>
492
+ <a href="#get-by-recno">KBTable#[]</a>
493
+ </p>
494
+ </li>
495
+ <li>
496
+ <p>
497
+ <a href="#field-names">KBTable#field_names</a>
498
+ </p>
499
+ </li>
500
+ <li>
501
+ <p>
502
+ <a href="#field-types">KBTable#field_types</a>
503
+ </p>
504
+ </li>
505
+ <li>
506
+ <p>
507
+ <a href="#total-recs">KBTable#total_recs</a>
508
+ </p>
509
+ </li>
510
+ <li>
511
+ <p>
512
+ <a href="#import-csv">KBTable#import_csv</a>
513
+ </p>
514
+ </li>
515
+ <li>
516
+ <p>
517
+ <a href="#add-column">KBTable#add_column</a>
518
+ </p>
519
+ </li>
520
+ <li>
521
+ <p>
522
+ <a href="#drop-column">KBTable#drop_column</a>
523
+ </p>
524
+ </li>
525
+ <li>
526
+ <p>
527
+ <a href="#rename-column">KBTable#rename_column</a>
528
+ </p>
529
+ </li>
530
+ <li>
531
+ <p>
532
+ <a href="#change-column-type">KBTable#change_column_type</a>
533
+ </p>
534
+ </li>
535
+ <li>
536
+ <p>
537
+ <a href="#change-column-default-value">KBTable#change_column_defaul_value</a>
538
+ </p>
539
+ </li>
540
+ <li>
541
+ <p>
542
+ <a href="#change-column-required">KBTable#change_column_required</a>
543
+ </p>
544
+ </li>
545
+ <li>
546
+ <p>
547
+ <a href="#add-index">KBTable#add_index</a>
548
+ </p>
549
+ </li>
550
+ <li>
551
+ <p>
552
+ <a href="#drop-index">KBTable#drop_index</a>
553
+ </p>
554
+ </li>
555
+ </ol>
556
+ </li>
557
+ <li>
558
+ <p>
559
+ <a href="#special-characters-in-data">Special characters in data</a>
560
+ </p>
561
+ </li>
562
+ <li>
563
+ <p>
564
+ <a href="#table-structure">Table Structure</a>
565
+ </p>
566
+ </li>
567
+ <li>
568
+ <p>
569
+ <a href="#server-notes">Server Notes</a>
570
+ </p>
571
+ </li>
572
+ <li>
573
+ <p>
574
+ <a href="#tips-on-improving-performance">Tips on improving performance</a>
575
+ </p>
576
+ </li>
577
+ <li>
578
+ <p>
579
+ <a href="#client-server-diagram">Client/Server memory space diagram</a>
580
+ </p>
581
+ </li>
582
+ <li>
583
+ <p>
584
+ <a href="#single-user-diagram">Single-user memory space diagram</a>
585
+ </p>
586
+ </li>
587
+ <li>
588
+ <p>
589
+ <a href="#license">License</a>
590
+ </p>
591
+ </li>
592
+ <li>
593
+ <p>
594
+ <a href="#credits">Credits</a>
595
+ </p>
596
+ </li>
597
+ </ol>
598
+ </div></div>
599
+ </div>
600
+ <h2><a id="introduction"></a>Introduction</h2>
601
+ <div class="sectionbody">
602
+ <p>KirbyBase is a simple, pure-Ruby, flat-file database management system.
603
+ Some of its features include:</p>
604
+ <ul>
605
+ <li>
606
+ <p>
607
+ Since KirbyBase is written in Ruby, it runs anywhere that Ruby runs. It
608
+ is easy to distribute, since the entire dbms is in one (approx. 100k) code
609
+ file.
610
+ </p>
611
+ </li>
612
+ <li>
613
+ <p>
614
+ All data is kept in plain-text, delimited files that can be edited by
615
+ hand. This gives you the ability to make changes by just opening the file
616
+ up in a text editor, or you can use another programming language to read the
617
+ file in and do things with it.
618
+ </p>
619
+ </li>
620
+ <li>
621
+ <p>
622
+ It can be used as an embedded database or in a client/server, multi-user
623
+ mode. To switch from one mode to the other, you only have to change one
624
+ line in your program. Included in the distribution is a sample database
625
+ server script using DRb.
626
+ </p>
627
+ </li>
628
+ <li>
629
+ <p>
630
+ Tables are kept on disk during use and accessed from disk when selecting,
631
+ updating, inserting, and deleting records. Changes to a table are written
632
+ immediately to disk. KirbyBase is not an "in-memory" database. Once you
633
+ update the database in your program, you can be assured that the change has
634
+ been saved to disk. The chance of lost data due to power interruptions, or
635
+ disk crashes is much reduced. Also, since the entire database does not have
636
+ to reside in memory at once, KirbyBase should run adequately on a
637
+ memory-constrained system.
638
+ </p>
639
+ </li>
640
+ <li>
641
+ <p>
642
+ You can specify the type of data that each field will hold. The available
643
+ data types are: String, Integer, Float, Boolean, Time, Date, DateTime, Memo,
644
+ Blob, and YAML.
645
+ </p>
646
+ </li>
647
+ <li>
648
+ <p>
649
+ The query syntax is very "rubyish". Instead of having to use another
650
+ language like SQL, you can express your query using Ruby code blocks.
651
+ </p>
652
+ </li>
653
+ <li>
654
+ <p>
655
+ All inserted records have an auto-incrementing primary key that is
656
+ guaranteed to uniquely identify the record throughout it's lifetime.
657
+ </p>
658
+ </li>
659
+ <li>
660
+ <p>
661
+ You can specify that the result set be sorted on multiple fields, each
662
+ one either ascending or descending.
663
+ </p>
664
+ </li>
665
+ <li>
666
+ <p>
667
+ You can specify that certain fields be indexed. Using an index in a select
668
+ query can greatly improve performance on large tables (I've seen 10x speed
669
+ improvements). Index maintenance is completely handled by KirbyBase.
670
+ </p>
671
+ </li>
672
+ <li>
673
+ <p>
674
+ You can specify that a field has a "lookup table". Whenever that field is
675
+ accessed, the corresponding record from the lookup table is automatically
676
+ available.
677
+ </p>
678
+ </li>
679
+ <li>
680
+ <p>
681
+ You can specify one-to-many links between tables, somewhat analogous to a
682
+ "join" in SQL.
683
+ </p>
684
+ </li>
685
+ <li>
686
+ <p>
687
+ You can create calculated fields that are computed at runtime.
688
+ </p>
689
+ </li>
690
+ <li>
691
+ <p>
692
+ It is fairly fast, comparing favorably to SQLite.
693
+ </p>
694
+ </li>
695
+ </ul>
696
+ <p>In meeting your DBMS needs, KirbyBase fits in somewhere between plain
697
+ text files and small SQL database management systems like SQLite and
698
+ MySQL.</p>
699
+ <div class="sidebarblock">
700
+ <div class="sidebar-content">
701
+ <div class="sidebar-title">Drop me a line!</div>
702
+ <p>If you find a use for KirbyBase, please send an email
703
+ telling me how you use it. I find that hearing how people have
704
+ put KirbyBase to use is one of the biggest rewards I get for working on it.</p>
705
+ </div></div>
706
+ </div>
707
+ <h2><a id="connecting-to-a-database"></a>Connecting to a database</h2>
708
+ <div class="sectionbody">
709
+ <p>To use Kirbybase, you first need to require the module:</p>
710
+ <div class="listingblock">
711
+ <div class="content">
712
+ <pre><tt>require 'kirbybase'</tt></pre>
713
+ </div></div>
714
+ <p>Then create an instance:</p>
715
+ <div class="listingblock">
716
+ <div class="content">
717
+ <pre><tt>db = KirbyBase.new</tt></pre>
718
+ </div></div>
719
+ <p>By default, the instance is a local connection using the same memory space
720
+ as your application. To specify a client/server connection, it would look
721
+ like this:</p>
722
+ <div class="listingblock">
723
+ <div class="content">
724
+ <pre><tt>db = KirbyBase.new(:client, 'localhost', 44444)</tt></pre>
725
+ </div></div>
726
+ <p>Of course, you would substitute your server's ip address and port number.</p>
727
+ <p>To specify a different location other than the current directory for the
728
+ database files, you need to pass the location as an argument, like so:</p>
729
+ <div class="listingblock">
730
+ <div class="content">
731
+ <pre><tt>db = KirbyBase.new(:local, nil, nil, './data')</tt></pre>
732
+ </div></div>
733
+ <p>KirbyBase treats every file in the specified directory that has the proper
734
+ extension as a database table. The default extension is ".tbl". To specify
735
+ a different extension, pass this as an argument, like so:</p>
736
+ <div class="listingblock">
737
+ <div class="content">
738
+ <pre><tt>db = KirbyBase.new(:local, nil, nil, './', '.dat')</tt></pre>
739
+ </div></div>
740
+ <p>You can also specify the arguments via a code block. So, if you don't want
741
+ to have to specify a bunch of arguments just to get to the one you want,
742
+ put it in a code block attached to the method call. You could re-code the
743
+ previous example like so:</p>
744
+ <div class="listingblock">
745
+ <div class="content">
746
+ <pre><tt>db = KirbyBase.new { |d| d.ext = '.dat' }</tt></pre>
747
+ </div></div>
748
+ </div>
749
+ <h2><a id="creating-a-new-table"></a>Creating a new table</h2>
750
+ <div class="sectionbody">
751
+ <p>To create a new table, you specify the table name, and a name and type for
752
+ each column. For example, to create a table containing information on World
753
+ War II planes:</p>
754
+ <div class="listingblock">
755
+ <div class="content">
756
+ <pre><tt>plane_tbl = db.create_table(:plane, :name, :String, :country, :String,
757
+ :role, :String, :speed, :Integer, :range, :Integer, :began_service, :Date,
758
+ :still_flying, :Boolean)</tt></pre>
759
+ </div></div>
760
+ <div class="sidebarblock">
761
+ <a id="field-types"></a>
762
+ <div class="sidebar-content">
763
+ <div class="sidebar-title">KirbyBase Field Types</div>
764
+ <div class="admonitionblock">
765
+ <table><tr>
766
+ <td class="icon">
767
+ <img src="./images/tip.png" alt="Tip" />
768
+ </td>
769
+ <td class="content">:String, :Integer, :Float, :Boolean(true/false), :Time, :Date,
770
+ :DateTime, :Memo, :Blob, and :YAML.</td>
771
+ </tr></table>
772
+ </div>
773
+ </div></div>
774
+ <div class="sidebarblock">
775
+ <a id="recno"></a>
776
+ <div class="sidebar-content">
777
+ <div class="sidebar-title">The recno field</div>
778
+ <div class="admonitionblock">
779
+ <table><tr>
780
+ <td class="icon">
781
+ <img src="./images/important.png" alt="Important" />
782
+ </td>
783
+ <td class="content">KirbyBase will automatically create a primary key field, called
784
+ recno, with a type of :Integer, for each table. This field will be
785
+ auto-incremented each time a record is inserted. You can use this field in
786
+ select, update, and delete queries, but you can't modify this field.</td>
787
+ </tr></table>
788
+ </div>
789
+ </div></div>
790
+ <p>You can also specify whether the table should be encrypted. This will save
791
+ the table to disk encrypted (more like obfuscated) using a Vignere Cipher.
792
+ This is similar to rot13, but it uses a key to determine character
793
+ substitution. Still, this encryption will only stymie the most casual
794
+ of hackers. Do not rely on it to keep sensitive data safe! You specify
795
+ encryption by using a code block attached to #create_table:</p>
796
+ <div class="listingblock">
797
+ <div class="content">
798
+ <pre><tt>plane_tbl = db.create_table(:plane, :name, :String...) do |t|
799
+ t.encrypt = true
800
+ end</tt></pre>
801
+ </div></div>
802
+ <p>You can also specify that you want records of the table to be returned to
803
+ you as instances of a class. To do this, simply define a class before you
804
+ call #create_table. This class needs to have an accessor for each fieldname
805
+ in the table. Also, this class needs to have a class method, called
806
+ #kb_create, that returns a new class instance. Here is an example class:</p>
807
+ <div class="listingblock">
808
+ <div class="content">
809
+ <pre><tt>class Foobar
810
+ attr_accessor(:recno, :name, :country, :role, :speed, :range,
811
+ :began_service, :still_flying, :alpha, :beta)
812
+
813
+ def Foobar.kb_create(recno, name, country, role, speed, range,
814
+ began_service, still_flying)
815
+ name ||= 'No Name!'
816
+ speed ||= 0
817
+ began_service ||= Date.today
818
+
819
+ Foobar.new do |x|
820
+ x.recno = recno
821
+ x.name = name
822
+ x.country = country
823
+ x.role = role
824
+ x.speed = speed
825
+ x.range = range
826
+ x.began_service = began_service
827
+ x.still_flying = still_flying
828
+ end
829
+ end
830
+
831
+ def initialize(&amp;block)
832
+ instance_eval(&amp;block)
833
+ end
834
+ end</tt></pre>
835
+ </div></div>
836
+ <p>Pass this class to #create_table in an attached code block, like so:</p>
837
+ <div class="listingblock">
838
+ <div class="content">
839
+ <pre><tt>plane_tbl = db.create_table(:plane, :name, :String...) do |t|
840
+ t.record_class = Foobar
841
+ end</tt></pre>
842
+ </div></div>
843
+ <p>Now, when you call #select, the result set will be made up of instances of
844
+ Foobar, instead of the default, which is instances of Struct. This also
845
+ works the other way. You can now specify instances of Foobar as input to
846
+ the #insert, #update and #set methods. More on those methods below.</p>
847
+ <div class="sidebarblock">
848
+ <div class="sidebar-content">
849
+ <div class="admonitionblock">
850
+ <table><tr>
851
+ <td class="icon">
852
+ <img src="./images/important.png" alt="Important" />
853
+ </td>
854
+ <td class="content">The #create_table method will return a reference to a KBTable
855
+ instance. This is the only way, besides calling KirbyBase#get_table, that
856
+ you can obtain a handle to a KBTable instance. You can not call KBTable#new
857
+ directly.</td>
858
+ </tr></table>
859
+ </div>
860
+ </div></div>
861
+ <h3>Specifying Advanced Field Type Information</h3>
862
+ <p>There are four types of advanced field type information that you can
863
+ specify:
864
+ Defaults, Requireds, Indexes and Extras (i.e. Lookup, Link_many,
865
+ Calculated).</p>
866
+ <h4><a id="defaults"></a>Default Field Values</h4>
867
+ <p>Normally, when you insert a record, if you don't specify a value for a field
868
+ or specify nil as the value, KirbyBase stores this as an empty string
869
+ (i.e. "") in the table's physical file, and returns it as a nil value when
870
+ you do a #select.</p>
871
+ <p>However, you can tell KirbyBase that you want a column to have a default
872
+ value. This will be applied whenever either no value or a nil value is
873
+ specified for the field when <strong>inserting</strong> a record only. When updating an
874
+ existing record, defaults will not be applied.</p>
875
+ <p>For example, to specify that the category column has a default value, you
876
+ would code:</p>
877
+ <div class="listingblock">
878
+ <div class="content">
879
+ <pre><tt>db.create_table(:addressbook, :firstname, :String,
880
+ :lastname, :String, :phone_no, :String,
881
+ :category, {:DataType=&gt;:String, :Default=&gt;'Business'})</tt></pre>
882
+ </div></div>
883
+ <p>Notice that, since we are specifying advanced field type information, we
884
+ cannot just simply say :String for the second half of the field definition.
885
+ Instead, we have to pass a hash, with a :DataType item set to :String.
886
+ Next, because we are specifying a default value, we have to include a hash
887
+ item called :Default with it's value set to whatever we want the default to
888
+ be. The default value must be of a type that is valid for the column.</p>
889
+ <h4><a id="requireds"></a>Required Fields</h4>
890
+ <p>Normally, when you insert or update a record, if you don't specify a value
891
+ for a field or specify nil as the value, KirbyBase stores this as an empty
892
+ string (i.e. "") in the table's physical file, and returns it as a nil
893
+ value when you do a #select.</p>
894
+ <p>However, you can tell KirbyBase that you want a column to be required
895
+ (i.e. you must supply a value and it can't be nil). When a record is
896
+ inserted or updated, an exception will be raised for any required field
897
+ that has not been given a value or been given a nil value.</p>
898
+ <p>For example, to specify that the category column is required, you would
899
+ code:</p>
900
+ <div class="listingblock">
901
+ <div class="content">
902
+ <pre><tt>db.create_table(:addressbook, :firstname, :String,
903
+ :lastname, :String, :phone_no, :String,
904
+ :category, {:DataType=&gt;:String, :Required=&gt;true})</tt></pre>
905
+ </div></div>
906
+ <p>Notice that, since we are specifying advanced field type information, we
907
+ cannot just simply say :String for the second half of the field definition.
908
+ Instead, we have to pass a hash, with a :DataType item set to :String.
909
+ Next, because we are specifying that a column is required, we have to
910
+ include a hash item called :Required with it's value set to true.</p>
911
+ <h4><a id="creating-indexes"></a>Indexes</h4>
912
+ <p>Indexes are in-memory arrays that have an entry that corresponds to each
913
+ table record, but just holds the field values specified when the index was
914
+ created, plus the :recno of the actual table record. Because index arrays
915
+ are smaller than the actual table and because they are in-memory instead of
916
+ on-disk, using an index in a select query is usually much faster than
917
+ selecting against the table itself, especially when the table is quite
918
+ large.</p>
919
+ <p>To specify that an index is to be created, you need to tell KirbyBase which
920
+ fields are to be included in a particular index. You can have up to 5
921
+ indexes per table. Indexes can either contain single or multiple fields.
922
+ For example, to create an index on firstname and lastname for a table called
923
+ :addressbook, you would code:</p>
924
+ <div class="listingblock">
925
+ <div class="content">
926
+ <pre><tt>db.create_table(:addressbook, :firstname, {:DataType=&gt;:String, :Index=&gt;1},
927
+ :lastname, {:DataType=&gt;:String, :Index=&gt;1},
928
+ :phone_no, :String)</tt></pre>
929
+ </div></div>
930
+ <p>Notice that, since we are specifying advanced field type information, we
931
+ cannot just simply say :String for the second half of the field definition.
932
+ Instead, we have to pass a hash, with a :DataType item set to :String.
933
+ Next, because we are creating an index, we have to include a hash item
934
+ called :Index with it's value set from 1 to 5. For compound indexes, like
935
+ the one in the above example, we need to make sure that all fields in the
936
+ index have the same number. To have another index for a table, just make
937
+ sure you increment the index number. So, for example, if we wanted to have
938
+ another index for the :addressbook table on the field phone number, we would
939
+ code:</p>
940
+ <div class="listingblock">
941
+ <div class="content">
942
+ <pre><tt>db.create_table(:addressbook, :firstname, {:DataType=&gt;:String, :Index=&gt;1},
943
+ :lastname, {:DataType=&gt;:String, :Index=&gt;1},
944
+ :phone_no, {:DataType=&gt;:String, :Index=&gt;2})</tt></pre>
945
+ </div></div>
946
+ <p>Notice how we just increment the index number to 2 for the :phone_no index.
947
+ Since there are no other fields with the same index number, this will create
948
+ an index with just the :phone_no field in it. You will see how to use
949
+ indexes in your select queries later.</p>
950
+ <div class="sidebarblock">
951
+ <a id="a-note-about-indexes"></a>
952
+ <div class="sidebar-content">
953
+ <div class="sidebar-title">A note about indexes</div>
954
+ <p>When KirbyBase initializes, it creates an instance for each table in
955
+ the database. It also creates each index array for each indexed field in
956
+ each table. So, if there are several large tables that have indexed fields,
957
+ this database initialization process could take several seconds. I decided
958
+ to have it operate this way, because I thought that it made more sense to
959
+ have a user application wait once upon initialization, rather than have it
960
+ wait the first time a table is referenced. A user is more used to waiting
961
+ for an application to properly initialize, so this initial delay, I thought,
962
+ would feel more natural to the user, rather than a wait time in the middle
963
+ of the application.</p>
964
+ <p>Please let me know if this poses a problem for any of your applications. I
965
+ have some ideas that I could implement that would allow the developer to
966
+ specify when indexes are created.</p>
967
+ <p>This is also an excellent reason to use the client/server capabilities of
968
+ KirbyBase. In client/server mode, the database initialization processing is
969
+ all done on the server, so, once this is done, any users starting their
970
+ client application and connecting to the server will experience no delay due
971
+ to index array creation.</p>
972
+ </div></div>
973
+ <h4><a id="creating-lookup-fields"></a>Lookup Fields</h4>
974
+ <p>Lookup fields are fields that hold a reference to a record in another table.
975
+ For example, say you have a table called :department that has fields called
976
+ :dept_id, :dept_name, and :manager. Now, let's say that you don't want the
977
+ :manager field to just hold the manager's name; you want it to point to the
978
+ manager's record in the :employee table, which has fields like
979
+ :employee_id, :firstname, :lastname, :ss_no, etc. What you want to do is
980
+ to tell KirbyBase that the :dept.manager field should actually point to the
981
+ manager's record in the :employee table (the "lookup" table). Here's how
982
+ you would do that:</p>
983
+ <div class="listingblock">
984
+ <div class="content">
985
+ <pre><tt>db.create_table(:department, :dept_id, :String, :dept_name, :String,
986
+ :manager, {:DataType=&gt;:String, :Lookup=&gt;[:employee, :employee_id]})</tt></pre>
987
+ </div></div>
988
+ <p>Ok, what we have done here is to tell KirbyBase a little bit "extra" about
989
+ the :manager field. We are specifying that whenever we ask for the value of
990
+ :manager, we want KirbyBase to do a #select against the :employee table that
991
+ compares the value of the :department.manager field to the value of the
992
+ :employee.employee_id field. If an index is available for the
993
+ :employee.employee_id field, KirbyBase will automatically use it.</p>
994
+ <p>There is a shortcut to specifying a lookup field. If the :employee_id field
995
+ has been designated a "key" field for the :employee table, we can even
996
+ shorten our code and KirbyBase will figure it all out. For example, if the
997
+ :employee table was created with this code:</p>
998
+ <div class="listingblock">
999
+ <div class="content">
1000
+ <pre><tt>db.create_table(:employee, :employee_id, {:DataType=&gt;:String, :Key=&gt;true},
1001
+ :firstname, :String, :lastname, :String)</tt></pre>
1002
+ </div></div>
1003
+ <p>Then the field definition for :manager could be re-written as:</p>
1004
+ <div class="listingblock">
1005
+ <div class="content">
1006
+ <pre><tt>db.create_table(:department, :dept_id, :String, :dept_name, :String,
1007
+ :manager, :employee)</tt></pre>
1008
+ </div></div>
1009
+ <p>KirbyBase will figure out that you want to compare :department.manager to
1010
+ :employee.employee_id.</p>
1011
+ <div class="sidebarblock">
1012
+ <div class="sidebar-content">
1013
+ <div class="admonitionblock">
1014
+ <table><tr>
1015
+ <td class="icon">
1016
+ <img src="./images/important.png" alt="Important" />
1017
+ </td>
1018
+ <td class="content">In order to use the shortcut when specifying a lookup field, the
1019
+ lookup table it is pointing to <strong>must</strong> already exist. This is so that
1020
+ KirbyBase can do the defaulting magic.</td>
1021
+ </tr></table>
1022
+ </div>
1023
+ </div></div>
1024
+ <h4><a id="creating-link-many-fields"></a>Link_many Fields</h4>
1025
+ <p>When you specify that a field has a Link_many, you are telling KirbyBase
1026
+ that you want to create a one-to-many link between this field and a subset
1027
+ of records from another table.</p>
1028
+ <p>For example, say you are creating an order entry system for your business.
1029
+ You have a master table called :orders that holds one record for each
1030
+ customer order that is placed. It has fields like: :order_id, :cust_id,
1031
+ :order_date, etc.</p>
1032
+ <p>Now, you also need a table that is going to have a record for each detail
1033
+ item type ordered. Let's call it :order_items and some of it's fields would
1034
+ be: :item_no, :qty, :order_id.</p>
1035
+ <p>Notice that the detail table has a field called :order_id. This will hold
1036
+ the order_id linking it back to the :orders.order_id table. If a customer
1037
+ order's only one type of item, then there will only be one record in the
1038
+ :order_items table that has that order_id. But, if the customer places an
1039
+ order for many different types of items, there will be many records in the
1040
+ :order_items table that have the same order_id. That's why we say that
1041
+ there is a "one to many" link between the master (or parent) table, :orders,
1042
+ and the detail (or child) table, :order_items.</p>
1043
+ <p>When we select an :order record, we want the ability to also select all the
1044
+ detail records from the :order_items table that belong to that order. We do
1045
+ this by telling KirbyBase about the one-to-many link between the two
1046
+ tables. Here's how:</p>
1047
+ <div class="listingblock">
1048
+ <div class="content">
1049
+ <pre><tt>db.create_table(:orders, :order_id, :Integer, :cust_id, :Integer,
1050
+ :order_date, :Date, :items, {:DataType=&gt;:ResultSet, :Link_many=&gt;[:order_id,
1051
+ :order_items, :order_id]})
1052
+
1053
+ db.create_table(:order_items, :item_no, :Integer, :qty, :Integer,
1054
+ :order_id, :Integer)</tt></pre>
1055
+ </div></div>
1056
+ <p>Now, look at the :Link_many item in the field type definition hash in the
1057
+ above example. We are specifying that a field, called :items, be created
1058
+ with a field type of :ResultSet. We tell KirbyBase that, when we ask for
1059
+ the value of :items, it should do a #select on :order_items and return a
1060
+ KBResultSet that contains :order_items whose :order_id field (the last item
1061
+ in the array above), equals the value of the :orders.order_id field (the
1062
+ first item of the array above).</p>
1063
+ <p>If you opened up the :orders table file in a text editor, you would notice
1064
+ that, for each record, the :items field is blank. No data is ever stored in
1065
+ this field, since it's value is always computed at runtime.</p>
1066
+ <h4><a id="creating-calculated-fields"></a>Calculated Fields</h4>
1067
+ <p>When you specify that a field is a Calculated field, you are telling
1068
+ KirbyBase to compute the value of the field at runtime, based on the code
1069
+ string that you pass it at table creation time.</p>
1070
+ <p>For example. let's say you have a table that is going to track your
1071
+ purchases. It will have fields like :purchase_date, :description, :qty, and
1072
+ :price.</p>
1073
+ <p>Let's say that you want to have a "virtual" field, called :total_cost, that
1074
+ is the result of quantity multiplied by price. You want this field
1075
+ calculated at runtime, so that if you change a record's quantity or price,
1076
+ the :total_cost field will automatically reflect the changes.
1077
+ Here's how you would define this table:</p>
1078
+ <div class="listingblock">
1079
+ <div class="content">
1080
+ <pre><tt>db.create_table(:purchases, :purchase_date, :Date, :description, :String,
1081
+ :qty, :Integer, :price, :Float, :total_cost, {:DataType=&gt;:Float,
1082
+ :Calculated=&gt;'qty*price'})</tt></pre>
1083
+ </div></div>
1084
+ <p>See how we tell KirbyBase how to calculate the field? By multiplying the
1085
+ :qty field by the :price field.</p>
1086
+ <p>If you opened up the :purchases file in a text editor, you would notice
1087
+ that, for each record, the :total_cost field is blank. No data is ever
1088
+ stored in this field, since it's value is always computed at runtime.</p>
1089
+ </div>
1090
+ <h2><a id="obtaining-a-reference-to-an-existing-table"></a>Obtaining a reference to an existing table</h2>
1091
+ <div class="sectionbody">
1092
+ <p>If a table already exists and you need to get a reference to it so that you
1093
+ can insert, select, etc., you would call the #get_table method from your
1094
+ KirbyBase instance. This is how to obtain a handle to an existing table.
1095
+ You cannot call KBTable#new directly.</p>
1096
+ <div class="listingblock">
1097
+ <div class="content">
1098
+ <pre><tt>plane_tbl_another_reference = db.get_table(:plane)</tt></pre>
1099
+ </div></div>
1100
+ <p>Then, you can use it just like you would use a reference you got when
1101
+ you created a new table.</p>
1102
+ </div>
1103
+ <h2><a id="insert-method"></a>The insert method</h2>
1104
+ <div class="sectionbody">
1105
+ <p>To insert records into a table, you use the insert method. You can use an
1106
+ array, a hash, a struct, a code block, or an instance of the table's custom
1107
+ record class to specify the insert values.</p>
1108
+ <h3>Insert a record using an array for the input values:</h3>
1109
+ <div class="listingblock">
1110
+ <div class="content">
1111
+ <pre><tt>plane_tbl.insert('FW-190', 'Germany', 'Fighter', 399, 499,
1112
+ Date.new(1942,12,1), false)</tt></pre>
1113
+ </div></div>
1114
+ <p>The length of the data array must equal the number of columns in the table,
1115
+ <strong>not</strong> including the :recno column. Also, the data types must match. In the
1116
+ above example, specifying "399", instead of 399, would have resulted in an
1117
+ error.</p>
1118
+ <h3>Insert a record using a hash for the input values:</h3>
1119
+ <div class="listingblock">
1120
+ <div class="content">
1121
+ <pre><tt>plane_tbl.insert(:name='P-51', :country='USA', :role='Fighter', :speed=403,
1122
+ :range=1201, :began_service=Date.new(1943,6,24), :still_flying=true)</tt></pre>
1123
+ </div></div>
1124
+ <h3>Insert a record using a Struct for the input values:</h3>
1125
+ <div class="listingblock">
1126
+ <div class="content">
1127
+ <pre><tt>InputRec = Struct.new(:name, :country, :role, :speed, :range,
1128
+ :began_service, :still_flying)
1129
+ rec = InputRec.new('P-47', 'USA', 'Fighter', 365, 888, Date.new(1943,3,12),
1130
+ false)
1131
+
1132
+ plane_tbl.insert(rec)</tt></pre>
1133
+ </div></div>
1134
+ <h3>Insert a record using a code block for the input values:</h3>
1135
+ <div class="listingblock">
1136
+ <div class="content">
1137
+ <pre><tt>plane_tbl.insert do |r|
1138
+ r.name = 'B-17'
1139
+ r.country = 'USA'
1140
+ r.role = 'Bomber'
1141
+ r.speed = 315
1142
+ r.range = 1400
1143
+ r.began_service = Date.new(1937, 5, 1)
1144
+ r.still_flying = true</tt></pre>
1145
+ </div></div>
1146
+ <h3>Insert a record using an instance of the table's custom record class:</h3>
1147
+ <div class="listingblock">
1148
+ <div class="content">
1149
+ <pre><tt>foo = Foobar.new do |x|
1150
+ x.name = 'Spitfire'
1151
+ x.country = 'Great Britain'
1152
+ x.role = 'Fighter'
1153
+ x.speed = 333
1154
+ x.range = 454
1155
+ x.began_service = Date.new(1936, 1, 1)
1156
+ x.still_flying = true
1157
+ x.alpha = "This variable won't be stored in KirbyBase."
1158
+ x.beta = 'Neither will this one.'
1159
+ end
1160
+
1161
+ plane_tbl.insert(foo)</tt></pre>
1162
+ </div></div>
1163
+ <div class="sidebarblock">
1164
+ <div class="sidebar-content">
1165
+ <div class="admonitionblock">
1166
+ <table><tr>
1167
+ <td class="icon">
1168
+ <img src="./images/note.png" alt="Note" />
1169
+ </td>
1170
+ <td class="content">The #insert method will return the record number of the newly created
1171
+ record. This is an auto-incremented integer generated by KirbyBase. This
1172
+ number will <strong>never</strong> change for the record and can be used as a unique
1173
+ identifier for the record.</td>
1174
+ </tr></table>
1175
+ </div>
1176
+ </div></div>
1177
+ </div>
1178
+ <h2><a id="how-to-select-records"></a>How to select records</h2>
1179
+ <div class="sectionbody">
1180
+ <p>The syntax you use to select records to perform operations on is the same
1181
+ for a select, update, or delete statement, so I wanted to cover, in
1182
+ general, how to create a query expression first, before getting to the
1183
+ specifics of select, update, and delete.</p>
1184
+ <p>In KirbyBase, query conditions are specified simply by using Ruby code
1185
+ blocks. Therefore, any code block that can be converted into a Proc object
1186
+ is valid. This allows for great flexibility, as you will see in the many
1187
+ examples below.</p>
1188
+ <div class="sidebarblock">
1189
+ <div class="sidebar-content">
1190
+ <div class="admonitionblock">
1191
+ <table><tr>
1192
+ <td class="icon">
1193
+ <img src="./images/tip.png" alt="Tip" />
1194
+ </td>
1195
+ <td class="content">You can find many examples of how to specify queries in the "examples"
1196
+ directory of the KirbyBase distribution.</td>
1197
+ </tr></table>
1198
+ </div>
1199
+ </div></div>
1200
+ <p>Now that we have a general understanding of how to select records to operate
1201
+ on, lets get more specific by looking at the select, update, and delete
1202
+ methods.</p>
1203
+ <h3><a id="select-method"></a>The select method</h3>
1204
+ <p>The select method allows you to ask for all records in a table that match
1205
+ certain selection criteria. Additionally, you can also specify which fields
1206
+ you want included in the result set. The select method returns an instance
1207
+ of KBResultSet, which is an array of records that satisfied the select
1208
+ criteria. KBResultSet is covered in more detail later in the manual.</p>
1209
+ <p>Here is the simplest example of a select statement:</p>
1210
+ <div class="listingblock">
1211
+ <div class="content">
1212
+ <pre><tt>result_set = plane_tbl.select</tt></pre>
1213
+ </div></div>
1214
+ <p>Since, no code block was specified, KirbyBase will include all records in
1215
+ the result set. Additionally, because a list of fields to include in the
1216
+ result set was not specified, KirbyBase will include all fields for each
1217
+ record in the result set.</p>
1218
+ <p>To specify that you only want a subset of fields in the result set, you list
1219
+ their field names as arguments to the select method. For example:</p>
1220
+ <div class="listingblock">
1221
+ <div class="content">
1222
+ <pre><tt>result_set = plane_tbl.select(:name, :speed)</tt></pre>
1223
+ </div></div>
1224
+ <p>To specify selection criteria, attach a code block to the select method
1225
+ call. For example, if you only wanted to select Japanese planes:</p>
1226
+ <div class="listingblock">
1227
+ <div class="content">
1228
+ <pre><tt>result_set = plane_tbl.select(:name, :speed) { |r| r.country == 'Japan' }</tt></pre>
1229
+ </div></div>
1230
+ <p>You can combine multiple expressions in the code block. For example, to
1231
+ select only US planes that have a speed greater than 350mph:</p>
1232
+ <div class="listingblock">
1233
+ <div class="content">
1234
+ <pre><tt>result_set = plane_tbl.select { |r| r.country == 'USA' and r.speed &gt; 350 }</tt></pre>
1235
+ </div></div>
1236
+ <p>You can use regular expressions in the code block. Let's select all Axis
1237
+ fighters:</p>
1238
+ <div class="listingblock">
1239
+ <div class="content">
1240
+ <pre><tt>result_set = plane_tbl.select do |r|
1241
+ r.country =~ /Germany|Japan/ and r.role == 'Fighter'
1242
+ end</tt></pre>
1243
+ </div></div>
1244
+ <h3><a id="selecting-by-index"></a>Selecting by index</h3>
1245
+ <p>Performing a select query using an index is almost identical to performing a
1246
+ regular select query. You just have to specify the particular select
1247
+ method, based on the index you wish to use.</p>
1248
+ <p>For example, say you have created an index on the :speed field of the
1249
+ :plane table. You want to search for all planes with a speed greater than
1250
+ 400 mph. Ruby automatically creates select methods for each one of the
1251
+ indexes of a table. So, you would code your select query like this:</p>
1252
+ <div class="listingblock">
1253
+ <div class="content">
1254
+ <pre><tt>plane_tbl.select_by_speed_index { |r| r.speed &gt; 400 }</tt></pre>
1255
+ </div></div>
1256
+ <p>Notice that you simply insert the name of the field as part of the method
1257
+ name. It's as simple as that.</p>
1258
+ <p>For compound indexes, you just need to specify the
1259
+ indexed field names in the select method in the same order as they are in
1260
+ the table. So, let's say you have indexed the :plane table on :country and
1261
+ :role, in one index. To select on this compound index, you would code:</p>
1262
+ <div class="listingblock">
1263
+ <div class="content">
1264
+ <pre><tt>plane_tbl.select_by_country_role_index do |r|
1265
+ r.country == 'Germany' and r.role == 'Fighter' }
1266
+ end</tt></pre>
1267
+ </div></div>
1268
+ <p>Notice how you just list both fields as part of the name of the select
1269
+ method, separated by underscores.</p>
1270
+ <div class="sidebarblock">
1271
+ <div class="sidebar-content">
1272
+ <div class="admonitionblock">
1273
+ <table><tr>
1274
+ <td class="icon">
1275
+ <img src="./images/warning.png" alt="Warning" />
1276
+ </td>
1277
+ <td class="content">If you specify a select method that does not exist, you will get an
1278
+ error. Likewise, if you specify a query by an index, yet include a field
1279
+ name in the query that is not part of the index, you will get an error.</td>
1280
+ </tr></table>
1281
+ </div>
1282
+ </div></div>
1283
+ <h3><a id="selecting-by-recno-index"></a>Selecting by :recno index</h3>
1284
+ <p>For each table, a :recno index is automatically created, whether or not
1285
+ other indexes are explicitly created by you. You can alway use this index
1286
+ to select records based solely on :recno. For example:</p>
1287
+ <div class="listingblock">
1288
+ <div class="content">
1289
+ <pre><tt>plane_tbl.select_by_recno_index { |r| [3, 45, 152].include?(r.recno) }</tt></pre>
1290
+ </div></div>
1291
+ <h3><a id="selects-involving-lookups-or-link-manys"></a>Selects Involving Lookups or Link_manys</h3>
1292
+ <p>Selects that involve Lookup fields or Link_many fields have a special case
1293
+ because both field types return complex objects rather than simple data
1294
+ types. For example, consider the lookup field example that I described
1295
+ earlier. For reference, here are the two table defintions again:</p>
1296
+ <div class="listingblock">
1297
+ <div class="content">
1298
+ <pre><tt>department_tbl = db.create_table(:department, :dept_id, :String,
1299
+ :dept_name, :String, :manager, {:DataType=&gt;:String, :Lookup=&gt;[:employee,
1300
+ :employee_id]})
1301
+
1302
+ employee_tbl = db.create_table(:employee, :employee_id, {:DataType=&gt;:String,
1303
+ :Key=&gt;true}, :firstname, :String, :lastname, :String)</tt></pre>
1304
+ </div></div>
1305
+ <p>To find the department managed by John Doe, the select query would look like
1306
+ this:</p>
1307
+ <div class="listingblock">
1308
+ <div class="content">
1309
+ <pre><tt>department_tbl.select do |r|
1310
+ r.manager.firstname == 'John' and r.manager.lastname == 'Doe'
1311
+ end</tt></pre>
1312
+ </div></div>
1313
+ <p>To print out all departments including the manager's full name:</p>
1314
+ <div class="listingblock">
1315
+ <div class="content">
1316
+ <pre><tt>department_tbl.select.each do |r|
1317
+ puts 'Department: %s Manager: %s %s' % [r.dept_name,
1318
+ r.manager.firstname, r.manager.lastname]
1319
+ end</tt></pre>
1320
+ </div></div>
1321
+ <p>Selects involving Link_many fields are slightly different because they
1322
+ involve ResultSets instead of just single objects. Here's the table
1323
+ definitions from the earlier Link_many discussion:</p>
1324
+ <div class="listingblock">
1325
+ <div class="content">
1326
+ <pre><tt>orders_tbl = db.create_table(:orders, :order_id, :Integer,
1327
+ :cust_id, :Integer, :order_date, :Date, :items, {:DataType=&gt;:ResultSet,
1328
+ :Link_many=&gt;[:order_id, :order_items, :order_id]})
1329
+
1330
+ order_items_tbl = db.create_table(:order_items, :item_no, :Integer,
1331
+ :qty, :Integer, :order_id, :Integer)</tt></pre>
1332
+ </div></div>
1333
+ <p>To print an order and all of it's associated detail items:</p>
1334
+ <div class="listingblock">
1335
+ <div class="content">
1336
+ <pre><tt>result = order_tbl.select { |r| r.order_id == 501 }.first
1337
+ puts '%d %d %s' % [result.order_id, result.cust_id, result.order_date]
1338
+
1339
+ result.items.each { |item| puts '%d %d' % [item.item_no, item.qty] }</tt></pre>
1340
+ </div></div>
1341
+ <p>Notice how the items attribute in the ResultSet is itself a ResultSet
1342
+ containing all of the :order_items records that belong to the selected
1343
+ order.</p>
1344
+ </div>
1345
+ <h2><a id="kbresultset"></a>KBResultSet</h2>
1346
+ <div class="sectionbody">
1347
+ <p>As stated above, the select method returns an instance of KBResultSet, which
1348
+ is an array of Struct objects (or instances of the class specified in
1349
+ record_class), each one representing a record that satisfied the selection
1350
+ criteria.</p>
1351
+ <p>Since each item in KBResultSet is a Struct object, you can easily reference
1352
+ it's members using field names. So, to print the name and speed of each
1353
+ German plane in the table you would code:</p>
1354
+ <div class="listingblock">
1355
+ <div class="content">
1356
+ <pre><tt>plane_tbl.select(:name, :speed) { |r| r.country == 'German' }.each do |r|
1357
+ puts '%s %s' % [r.name, r.speed]
1358
+ end</tt></pre>
1359
+ </div></div>
1360
+ <h3><a id="sorting-a-result-set"></a>Sorting a result set</h3>
1361
+ <p>You can specify sort criteria by calling KBResultSet#sort. You must supply
1362
+ the sort method with a list of field names that you want to sort by. For
1363
+ example, to select all planes, include just name, country, and speed in the
1364
+ result set, and sort the result set by country (ascending) then name
1365
+ (ascending), you would code:</p>
1366
+ <div class="listingblock">
1367
+ <div class="content">
1368
+ <pre><tt>result = plane_tbl.select(:name, :country, :speed).sort(:country, :name)</tt></pre>
1369
+ </div></div>
1370
+ <p>To indicate that you want a particular field sorted in descending order
1371
+ rather than ascending order, you need to put a minus sign in front of it.
1372
+ For example, to select all planes, include just name, country, and speed in
1373
+ the result set, and sort the result set by country (ascending) then speed
1374
+ (descending), you would code:</p>
1375
+ <div class="listingblock">
1376
+ <div class="content">
1377
+ <pre><tt>result_set = plane_tbl.select(:name, :country, :speed).sort(:country,
1378
+ -:speed)</tt></pre>
1379
+ </div></div>
1380
+ <p>You can also explicitly specify that a field be sorted in ascending order by
1381
+ putting a plus sign in front of it. This is not necessary, since ascending
1382
+ is the default, but it's there if you prefer to use it.</p>
1383
+ <h3><a id="to-report"></a>Producing a report from a result set</h3>
1384
+ <p>Additionally, you can also transform the KBResultSet into a nicely formatted
1385
+ report, suitable for printing, by calling KBResultSet#to_report. To print
1386
+ a formatted report of all plane names, countries, and speeds, sorted by
1387
+ name, you would code the following:</p>
1388
+ <div class="listingblock">
1389
+ <div class="content">
1390
+ <pre><tt>puts plane_tbl.select(:name, :country, :speed).sort(:name).to_report</tt></pre>
1391
+ </div></div>
1392
+ <h3><a id="crosstabs"></a>CrossTabs or Pivot Tables or Column Arrays (i.e. I don't know what to call them!)</h3>
1393
+ <p>Every KBResultSet has an additional feature that can prove quite useful.
1394
+ When a result set is created, KirbyBase creates an array for each column
1395
+ name that has all of the values of that column in it. Perhaps an example
1396
+ would make this more clear. Let's say you have a table that looks like
1397
+ this:</p>
1398
+ <div class="tableblock">
1399
+ <table rules="all"
1400
+ frame="border"
1401
+ cellspacing="0" cellpadding="4">
1402
+ <col width="102" />
1403
+ <col width="114" />
1404
+ <col width="137" />
1405
+ <thead>
1406
+ <tr>
1407
+ <th align="left">
1408
+ name
1409
+ </th>
1410
+ <th align="left">
1411
+ speed
1412
+ </th>
1413
+ <th align="left">
1414
+ range
1415
+ </th>
1416
+ </tr>
1417
+ </thead>
1418
+ <tbody valign="top">
1419
+ <tr>
1420
+ <td align="left">
1421
+ P-51
1422
+ </td>
1423
+ <td align="left">
1424
+ 402
1425
+ </td>
1426
+ <td align="left">
1427
+ 1201
1428
+ </td>
1429
+ </tr>
1430
+ <tr>
1431
+ <td align="left">
1432
+ ME-109
1433
+ </td>
1434
+ <td align="left">
1435
+ 354
1436
+ </td>
1437
+ <td align="left">
1438
+ 544
1439
+ </td>
1440
+ </tr>
1441
+ <tr>
1442
+ <td align="left">
1443
+ Spitfire
1444
+ </td>
1445
+ <td align="left">
1446
+ 343
1447
+ </td>
1448
+ <td align="left">
1449
+ 501
1450
+ </td>
1451
+ </tr>
1452
+ </tbody>
1453
+ </table>
1454
+ </div>
1455
+ <p>If you do a select on the table, not only will the result set contain a
1456
+ row for each record that satisfied the select condition, but it will also
1457
+ contain an array for each column, which will hold all the column values.
1458
+ Here's an example, using the above mentioned table:</p>
1459
+ <div class="listingblock">
1460
+ <div class="content">
1461
+ <pre><tt>result = plane_tbl.select
1462
+
1463
+ puts result[0].name =&gt; P-51
1464
+ puts result[0].speed =&gt; 402
1465
+
1466
+ p result.speed =&gt; [402,354,343]</tt></pre>
1467
+ </div></div>
1468
+ <p>Notice how you can reference this "column array" by calling the column name
1469
+ as a method. KirbyBase returns an array that holds all the values, in this
1470
+ case, of the speed column. This can be very useful in some cases. For a
1471
+ good example of this, look in the examples\crosstab_test directory of the
1472
+ distribution.</p>
1473
+ </div>
1474
+ <h2><a id="how-to-update-records"></a>How to update records</h2>
1475
+ <div class="sectionbody">
1476
+ <p>You can update the data in a table either by using the KBTable#update method
1477
+ by itself, or using it in conjunction with the KBResultSet#set method.
1478
+ Both methods produce the same result. The main difference is that, while
1479
+ using the #update method by itself, you can use a Hash, Array, or Struct as
1480
+ your update criteria, using the #set method in conjunction with the #update
1481
+ method adds the ability to use a code block as your update criteria. You
1482
+ will see specific examples of this in "The update method" description below.</p>
1483
+ <h3><a id="update-method"></a>The update method</h3>
1484
+ <p>To update a table, you use the update method. You <strong>must</strong> specify a code
1485
+ block that indicates which records are to be updated. Additionally, you must
1486
+ specify the fields to be updated and the new values for those fields.</p>
1487
+ <p>You can update records using a Hash, Struct, an Array, or an instance of a
1488
+ class you defined. For example, to change the P-51's speed to 405mph and
1489
+ it's range to 1210 miles, you could code:</p>
1490
+ <div class="listingblock">
1491
+ <div class="content">
1492
+ <pre><tt>plane_tbl.update(:speed=&gt;405, :range=&gt;1210) { |r| r.name == 'P-51' }</tt></pre>
1493
+ </div></div>
1494
+ <p>or:</p>
1495
+ <div class="listingblock">
1496
+ <div class="content">
1497
+ <pre><tt>UpdateRec = Struct.new(:name, :country, :role, :speed, :range,
1498
+ :began_service, :still_flying)
1499
+
1500
+ rec = UpdateRec.new
1501
+ rec.speed = 405
1502
+ rec.range = 1210
1503
+ plane_tbl.update(rec) { |r| r.name == 'P-51' }</tt></pre>
1504
+ </div></div>
1505
+ <h3><a id="set-method"></a>The set method</h3>
1506
+ <p>You can also update records using a code block, via KBResultSet#set:</p>
1507
+ <div class="listingblock">
1508
+ <div class="content">
1509
+ <pre><tt>plane_tbl.update {|r| r.name == 'P-51'}.set do |r|
1510
+ r.speed = 405
1511
+ r.range = 1210
1512
+ end</tt></pre>
1513
+ </div></div>
1514
+ <p>You can also update records using a Hash, Struct, or an Array, via
1515
+ KBResultSet#set:</p>
1516
+ <div class="listingblock">
1517
+ <div class="content">
1518
+ <pre><tt>plane_tbl.update {|r| r.name == 'P-51'}.set(:speed=&gt;405, :range=&gt;1210)</tt></pre>
1519
+ </div></div>
1520
+ <div class="sidebarblock">
1521
+ <div class="sidebar-content">
1522
+ <div class="admonitionblock">
1523
+ <table><tr>
1524
+ <td class="icon">
1525
+ <img src="./images/important.png" alt="Important" />
1526
+ </td>
1527
+ <td class="content">When you don't supply a code block to the #select method,
1528
+ KirbyBase automatically selects all of the records in the table. I felt
1529
+ that having the #update method work the same way was too dangerous. It
1530
+ would be too easy for someone to accidentally update all of the records in
1531
+ a table if they forgot to supply a code block to #update. That is why the
1532
+ #update method <strong>requires</strong> a code block. To update all of the records in a
1533
+ table, use the #update_all method.</td>
1534
+ </tr></table>
1535
+ </div>
1536
+ </div></div>
1537
+ <div class="sidebarblock">
1538
+ <div class="sidebar-content">
1539
+ <div class="admonitionblock">
1540
+ <table><tr>
1541
+ <td class="icon">
1542
+ <img src="./images/note.png" alt="Note" />
1543
+ </td>
1544
+ <td class="content">The #update method will return an Integer specifying the number of
1545
+ records that were updated.</td>
1546
+ </tr></table>
1547
+ </div>
1548
+ </div></div>
1549
+ <h3><a id="update-all-method"></a>The update_all method</h3>
1550
+ <p>To update all records in a table, you can use KBTable#update_all. This
1551
+ works just like the update method, except that you don't specify a code
1552
+ block containing selection criteria.</p>
1553
+ <p>For example, to add 50 mph to every record's speed field, you would code:</p>
1554
+ <div class="listingblock">
1555
+ <div class="content">
1556
+ <pre><tt>plane_tbl.update_all { |r| r.speed = r.speed + 50 }</tt></pre>
1557
+ </div></div>
1558
+ <div class="sidebarblock">
1559
+ <div class="sidebar-content">
1560
+ <div class="admonitionblock">
1561
+ <table><tr>
1562
+ <td class="icon">
1563
+ <img src="./images/note.png" alt="Note" />
1564
+ </td>
1565
+ <td class="content">The #update_all method will return an Integer specifying the number
1566
+ of records that were updated.</td>
1567
+ </tr></table>
1568
+ </div>
1569
+ </div></div>
1570
+ </div>
1571
+ <h2><a id="how-to-delete-records"></a>How to delete records</h2>
1572
+ <div class="sectionbody">
1573
+ <p>Deleting records from a table is similar to performing a #select or an
1574
+ #update.</p>
1575
+ <h3><a id="delete-method"></a>The delete method</h3>
1576
+ <p>To use the #delete method, you <strong>must</strong> supply a code block that identifies
1577
+ which records should be deleted.</p>
1578
+ <p>For example, to delete the FW-190's record from the table:</p>
1579
+ <div class="listingblock">
1580
+ <div class="content">
1581
+ <pre><tt>plane_tbl.delete { |r| r.name == 'FW-190' }</tt></pre>
1582
+ </div></div>
1583
+ <div class="sidebarblock">
1584
+ <div class="sidebar-content">
1585
+ <div class="admonitionblock">
1586
+ <table><tr>
1587
+ <td class="icon">
1588
+ <img src="./images/important.png" alt="Important" />
1589
+ </td>
1590
+ <td class="content">When you don't supply a code block to the #select method,
1591
+ KirbyBase automatically selects all of the records in the table. I felt
1592
+ that having the #delete method work the same way was too dangerous. It
1593
+ would be too easy for someone to accidentally delete all of the records in
1594
+ a table if they forgot to supply a code block to #delete. That is why the
1595
+ #delete method <strong>requires</strong> a code block. To delete all of the records in a
1596
+ table, use the #clear method.</td>
1597
+ </tr></table>
1598
+ </div>
1599
+ </div></div>
1600
+ <div class="sidebarblock">
1601
+ <div class="sidebar-content">
1602
+ <div class="admonitionblock">
1603
+ <table><tr>
1604
+ <td class="icon">
1605
+ <img src="./images/note.png" alt="Note" />
1606
+ </td>
1607
+ <td class="content">The #delete method will return an Integer specifying the total number
1608
+ of records that were deleted.</td>
1609
+ </tr></table>
1610
+ </div>
1611
+ </div></div>
1612
+ <h3><a id="clear-method"></a>The clear (alias delete_all) method</h3>
1613
+ <p>To completely empty a table, use the clear method. For example:</p>
1614
+ <div class="listingblock">
1615
+ <div class="content">
1616
+ <pre><tt>plane_tbl.clear</tt></pre>
1617
+ </div></div>
1618
+ <div class="sidebarblock">
1619
+ <div class="sidebar-content">
1620
+ <div class="admonitionblock">
1621
+ <table><tr>
1622
+ <td class="icon">
1623
+ <img src="./images/important.png" alt="Important" />
1624
+ </td>
1625
+ <td class="content">By default, KirbyBase will reset the recno counter to 0. So, any
1626
+ new records inserted after a #clear will be given a :recno starting with 1.
1627
+ To prevent #clear from resetting the recno counter, pass false to #clear.</td>
1628
+ </tr></table>
1629
+ </div>
1630
+ </div></div>
1631
+ </div>
1632
+ <h2><a id="pack-method"></a>The pack method</h2>
1633
+ <div class="sectionbody">
1634
+ <p>When KirbyBase deletes a record, it really just fills the entire line in the
1635
+ file with spaces. Deleting the entire line and moving each subsequent line
1636
+ up one would take too much time. Also, when a record is updated, if the size
1637
+ of the updated record is greater than the size of the old record, KirbyBase
1638
+ spaces out that entire line in the file, and rewrites the updated record at
1639
+ the end of the file. Again, this is done so that the entire file doesn't
1640
+ have to be re-written just because one record got updated.</p>
1641
+ <p>However, this means that after a lot of deletes and updates, a table can
1642
+ have lots of blank lines in it. This slows down searches and makes the file
1643
+ bigger than it has to be. You can use the pack method to remove these blank
1644
+ lines:</p>
1645
+ <div class="listingblock">
1646
+ <div class="content">
1647
+ <pre><tt>result = plane_tbl.pack</tt></pre>
1648
+ </div></div>
1649
+ <div class="sidebarblock">
1650
+ <div class="sidebar-content">
1651
+ <div class="admonitionblock">
1652
+ <table><tr>
1653
+ <td class="icon">
1654
+ <img src="./images/note.png" alt="Note" />
1655
+ </td>
1656
+ <td class="content">The #pack method will return an Integer specifiying the number of
1657
+ blank lines that were removed from the table.</td>
1658
+ </tr></table>
1659
+ </div>
1660
+ </div></div>
1661
+ </div>
1662
+ <h2><a id="memo-and-blob-fields"></a>Memo and Blob Fields</h2>
1663
+ <div class="sectionbody">
1664
+ <p>Memo and Blob fields operate a little differently from standard field types.
1665
+ You specify their creation just like regular field types. Notice how you
1666
+ can specify a base path for where memo/blob files will be stored.</p>
1667
+ <div class="listingblock">
1668
+ <div class="content">
1669
+ <pre><tt>db.create_table(:plane, :name, :String, :speed, :Integer, :descr,
1670
+ :Memo) do |d|
1671
+ d.memo_blob_path = './memos'
1672
+ end</tt></pre>
1673
+ </div></div>
1674
+ <p>However, what you actually store in the Memo field upon an #insert is an
1675
+ instance of KBMemo. KBMemo has two attributes: :filepath and :contents.
1676
+ The first holds the path (including filename) to the text file that will
1677
+ hold the contents of the memo. This path will be relative to whatever
1678
+ path was specified as the memo_blob_path upon database initialization. Here
1679
+ is an example of how to do this:</p>
1680
+ <div class="listingblock">
1681
+ <div class="content">
1682
+ <pre><tt>memo_string = &lt;&lt;END_OF_STRING
1683
+ The FW-190 was a World War II German fighter. It was used primarily as an
1684
+ interceptor against Allied strategic bombers.
1685
+ END_OF_STRING
1686
+
1687
+ memo = KBMemo.new(db, 'FW-190.txt', memo_string)
1688
+ plane_tbl.insert('FW-190', 'Germany', 399, 499, memo)</tt></pre>
1689
+ </div></div>
1690
+ <p>Updates work similarly in that you would need to supply a KBMemo instance
1691
+ to the #update method for the :Memo field.</p>
1692
+ <p>Other than this difference, you can use a memo field just like a regular
1693
+ field. When you do a #select, KirbyBase goes out to the file that holds the
1694
+ memo data, reads in all the lines, and returns a KBMemo instance. Here is
1695
+ an example of how you can even query against a memo field:</p>
1696
+ <div class="listingblock">
1697
+ <div class="content">
1698
+ <pre><tt>plane_tbl.select { |r| r.descr.contents =~ /built in Detroit, Michigan/ }</tt></pre>
1699
+ </div></div>
1700
+ <p>And KirbyBase would select all records whose memo field contained the phrase
1701
+ "built in Detroit, Michigan".</p>
1702
+ <p>Blob fields work similarly, except that instead of doing a #readlines,
1703
+ KirbyBase opens the file in binary mode and reads in the whole file at once.</p>
1704
+ </div>
1705
+ <h2><a id="misc-kirbybase-methods"></a>Miscellaneous KirbyBase methods</h2>
1706
+ <div class="sectionbody">
1707
+ <div class="sidebarblock">
1708
+ <a id="drop-table"></a>
1709
+ <div class="sidebar-content">
1710
+ <div class="sidebar-title">KirbyBase#drop_table</div>
1711
+ <div class="listingblock">
1712
+ <div class="content">
1713
+ <pre><tt>db.drop_table(:plane)</tt></pre>
1714
+ </div></div>
1715
+ <p>Will delete a table from the database.</p>
1716
+ <p>Returns true if table was dropped.</p>
1717
+ </div></div>
1718
+ <div class="sidebarblock">
1719
+ <a id="tables"></a>
1720
+ <div class="sidebar-content">
1721
+ <div class="sidebar-title">KirbyBase#tables</div>
1722
+ <div class="listingblock">
1723
+ <div class="content">
1724
+ <pre><tt>db.tables</tt></pre>
1725
+ </div></div>
1726
+ <p>Returns an array of all table names in the database.</p>
1727
+ </div></div>
1728
+ <div class="sidebarblock">
1729
+ <a id="table-exists"></a>
1730
+ <div class="sidebar-content">
1731
+ <div class="sidebar-title">KirbyBase#table_exists?</div>
1732
+ <div class="listingblock">
1733
+ <div class="content">
1734
+ <pre><tt>db.table_exists?(:plane)</tt></pre>
1735
+ </div></div>
1736
+ <p>Returns true if table exists, false otherwise.</p>
1737
+ </div></div>
1738
+ <div class="sidebarblock">
1739
+ <a id="rename-table"></a>
1740
+ <div class="sidebar-content">
1741
+ <div class="sidebar-title">KirbyBase#rename_table</div>
1742
+ <div class="listingblock">
1743
+ <div class="content">
1744
+ <pre><tt>db.rename_table(:plane, :warplanes)</tt></pre>
1745
+ </div></div>
1746
+ <p>Rename table to new name.</p>
1747
+ <p>Returns a handle to the newly-renamed table.</p>
1748
+ </div></div>
1749
+ </div>
1750
+ <h2><a id="misc-kbtable-methods"></a>Miscellaneous KBTable methods</h2>
1751
+ <div class="sectionbody">
1752
+ <div class="sidebarblock">
1753
+ <a id="update-by-recno"></a>
1754
+ <div class="sidebar-content">
1755
+ <div class="sidebar-title">KBTable#[]=</div>
1756
+ <div class="listingblock">
1757
+ <div class="content">
1758
+ <pre><tt>plane_tbl[5] = {:country = 'Tasmania'}</tt></pre>
1759
+ </div></div>
1760
+ <p>You can quickly update an individual record by treating the table as a Hash
1761
+ and the keys as recno's. You can update it using a Hash, Array, or Struct.</p>
1762
+ <p>Returns Integer specifying number of records updated (should always be 1).</p>
1763
+ </div></div>
1764
+ <div class="sidebarblock">
1765
+ <a id="get-by-recno"></a>
1766
+ <div class="sidebar-content">
1767
+ <div class="sidebar-title">KBTable#[]</div>
1768
+ <div class="listingblock">
1769
+ <div class="content">
1770
+ <pre><tt>plane_tbl[5]</tt></pre>
1771
+ </div></div>
1772
+ <p>You can quickly select an individual record, by passing it's recno to a
1773
+ table as if it were a hash.</p>
1774
+ <p>Returns a single record either in the form of a Struct or an instance of
1775
+ the table's custom record class, if specified.</p>
1776
+ <div class="listingblock">
1777
+ <div class="content">
1778
+ <pre><tt>plane_tbl[5, 14, 33]</tt></pre>
1779
+ </div></div>
1780
+ <p>You can also use the [] method to get a group of records by passing it more
1781
+ than one recno.</p>
1782
+ <p>Returns a KBResultSet with the records having the recno's you passed in.</p>
1783
+ </div></div>
1784
+ <div class="sidebarblock">
1785
+ <a id="field-names"></a>
1786
+ <div class="sidebar-content">
1787
+ <div class="sidebar-title">KBTable#field_names</div>
1788
+ <div class="listingblock">
1789
+ <div class="content">
1790
+ <pre><tt>plane_tbl.field_names</tt></pre>
1791
+ </div></div>
1792
+ <p>Returns an array of the table's field names.</p>
1793
+ </div></div>
1794
+ <div class="sidebarblock">
1795
+ <a id="field-types"></a>
1796
+ <div class="sidebar-content">
1797
+ <div class="sidebar-title">KBTable#field_types</div>
1798
+ <div class="listingblock">
1799
+ <div class="content">
1800
+ <pre><tt>plane_tbl.field_types</tt></pre>
1801
+ </div></div>
1802
+ <p>Returns an array of the table's field types (i.e. :String, :Integer, :Float)</p>
1803
+ </div></div>
1804
+ <div class="sidebarblock">
1805
+ <a id="total-recs"></a>
1806
+ <div class="sidebar-content">
1807
+ <div class="sidebar-title">KBTable#total_recs</div>
1808
+ <div class="listingblock">
1809
+ <div class="content">
1810
+ <pre><tt>plane_tbl.total_recs</tt></pre>
1811
+ </div></div>
1812
+ <p>Returns an Integer specifying the total number of records in the table.</p>
1813
+ </div></div>
1814
+ <div class="sidebarblock">
1815
+ <a id="import-csv"></a>
1816
+ <div class="sidebar-content">
1817
+ <div class="sidebar-title">KBTable#import_csv</div>
1818
+ <div class="listingblock">
1819
+ <div class="content">
1820
+ <pre><tt>plane_tbl.import_csv(csv_filename)</tt></pre>
1821
+ </div></div>
1822
+ <p>This method allows you to import a csv file into the current table.
1823
+ KirbyBase will attempt to convert the values in the csv file into their
1824
+ corresponding KirbyBase field types, based upon the field types you
1825
+ designated when you created the table.</p>
1826
+ <p>Returns an Integer specifying the total number of records imported.</p>
1827
+ </div></div>
1828
+ <div class="sidebarblock">
1829
+ <a id="add-column"></a>
1830
+ <div class="sidebar-content">
1831
+ <div class="sidebar-title">KBTable#add_column</div>
1832
+ <div class="listingblock">
1833
+ <div class="content">
1834
+ <pre><tt>plane_tbl.add_column(:weight, :Integer, :range)</tt></pre>
1835
+ </div></div>
1836
+ <p>This method allows you to add a column to an existing table. You must
1837
+ specify a column name, and a column type. You can optionally specify a
1838
+ column that you want the new column added after. If this is not specified,
1839
+ KirbyBase will add the column to the end of the table.</p>
1840
+ <div class="admonitionblock">
1841
+ <table><tr>
1842
+ <td class="icon">
1843
+ <img src="./images/important.png" alt="Important" />
1844
+ </td>
1845
+ <td class="content">Because #add_column changes the structure of a table, you can
1846
+ only call this method when connect_type==:local.</td>
1847
+ </tr></table>
1848
+ </div>
1849
+ </div></div>
1850
+ <div class="sidebarblock">
1851
+ <a id="drop-column"></a>
1852
+ <div class="sidebar-content">
1853
+ <div class="sidebar-title">KBTable#drop_column</div>
1854
+ <div class="listingblock">
1855
+ <div class="content">
1856
+ <pre><tt>plane_tbl.drop_column(:speed)</tt></pre>
1857
+ </div></div>
1858
+ <p>This method allows you to remove a column from an existing table. You must
1859
+ specify the column name to be removed.</p>
1860
+ <div class="admonitionblock">
1861
+ <table><tr>
1862
+ <td class="icon">
1863
+ <img src="./images/important.png" alt="Important" />
1864
+ </td>
1865
+ <td class="content">You cannot drop the :recno column.</td>
1866
+ </tr></table>
1867
+ </div>
1868
+ <div class="admonitionblock">
1869
+ <table><tr>
1870
+ <td class="icon">
1871
+ <img src="./images/important.png" alt="Important" />
1872
+ </td>
1873
+ <td class="content">Because #drop_column changes the structure of a table, you can
1874
+ only call this method when connect_type==:local.</td>
1875
+ </tr></table>
1876
+ </div>
1877
+ </div></div>
1878
+ <div class="sidebarblock">
1879
+ <a id="rename-column"></a>
1880
+ <div class="sidebar-content">
1881
+ <div class="sidebar-title">KBTable#rename_column</div>
1882
+ <div class="listingblock">
1883
+ <div class="content">
1884
+ <pre><tt>plane_tbl.rename_column(:speed, :maximum_speed)</tt></pre>
1885
+ </div></div>
1886
+ <p>This method allows you to rename a column in an existing table. You must
1887
+ specify the column to be renamed and a new column name.</p>
1888
+ <div class="admonitionblock">
1889
+ <table><tr>
1890
+ <td class="icon">
1891
+ <img src="./images/important.png" alt="Important" />
1892
+ </td>
1893
+ <td class="content">You cannot rename the :recno column.</td>
1894
+ </tr></table>
1895
+ </div>
1896
+ <div class="admonitionblock">
1897
+ <table><tr>
1898
+ <td class="icon">
1899
+ <img src="./images/important.png" alt="Important" />
1900
+ </td>
1901
+ <td class="content">Because #rename_column changes the structure of a table, you can
1902
+ only call this method when connect_type==:local.</td>
1903
+ </tr></table>
1904
+ </div>
1905
+ </div></div>
1906
+ <div class="sidebarblock">
1907
+ <a id="change-column-type"></a>
1908
+ <div class="sidebar-content">
1909
+ <div class="sidebar-title">KBTable#change_column_type</div>
1910
+ <div class="listingblock">
1911
+ <div class="content">
1912
+ <pre><tt>plane_tbl.change_column_type(:weight, :Float)</tt></pre>
1913
+ </div></div>
1914
+ <p>This method allows you to change a column's type in an existing table. You
1915
+ must specify the column name and a new column type.</p>
1916
+ <div class="admonitionblock">
1917
+ <table><tr>
1918
+ <td class="icon">
1919
+ <img src="./images/important.png" alt="Important" />
1920
+ </td>
1921
+ <td class="content">You cannot change the type of the :recno column.</td>
1922
+ </tr></table>
1923
+ </div>
1924
+ <div class="admonitionblock">
1925
+ <table><tr>
1926
+ <td class="icon">
1927
+ <img src="./images/important.png" alt="Important" />
1928
+ </td>
1929
+ <td class="content">Because #change_column_type changes the structure of a table, you
1930
+ can only call this method when connect_type==:local.</td>
1931
+ </tr></table>
1932
+ </div>
1933
+ </div></div>
1934
+ <div class="sidebarblock">
1935
+ <a id="change-column-default-value"></a>
1936
+ <div class="sidebar-content">
1937
+ <div class="sidebar-title">KBTable#change_column_default_value</div>
1938
+ <div class="listingblock">
1939
+ <div class="content">
1940
+ <pre><tt>plane_tbl.change_column_default_value(:country, 'United States')</tt></pre>
1941
+ </div></div>
1942
+ <p>This method allows you to change a column's default value in an existing
1943
+ table. You must specify the column name and a default value. If the
1944
+ default value is equal to nil, this, in effect will make the column not have
1945
+ a default value any more.</p>
1946
+ <div class="admonitionblock">
1947
+ <table><tr>
1948
+ <td class="icon">
1949
+ <img src="./images/important.png" alt="Important" />
1950
+ </td>
1951
+ <td class="content">Since the :recno column cannot have a default value, you cannot
1952
+ change the default value of the :recno column.</td>
1953
+ </tr></table>
1954
+ </div>
1955
+ <div class="admonitionblock">
1956
+ <table><tr>
1957
+ <td class="icon">
1958
+ <img src="./images/important.png" alt="Important" />
1959
+ </td>
1960
+ <td class="content">Because #change_column_default_value changes the structure of a
1961
+ table, you can only call this method when connect_type==:local.</td>
1962
+ </tr></table>
1963
+ </div>
1964
+ </div></div>
1965
+ <div class="sidebarblock">
1966
+ <a id="change-column-required"></a>
1967
+ <div class="sidebar-content">
1968
+ <div class="sidebar-title">KBTable#change_column_required</div>
1969
+ <div class="listingblock">
1970
+ <div class="content">
1971
+ <pre><tt>plane_tbl.change_column_required(:country, true)</tt></pre>
1972
+ </div></div>
1973
+ <p>This method allows you to change whether a value for a column is required or
1974
+ not. You must specify the column name and either true or false for the
1975
+ required argument.</p>
1976
+ <div class="admonitionblock">
1977
+ <table><tr>
1978
+ <td class="icon">
1979
+ <img src="./images/important.png" alt="Important" />
1980
+ </td>
1981
+ <td class="content">You cannot specify whether the :recno column is required or not.</td>
1982
+ </tr></table>
1983
+ </div>
1984
+ <div class="admonitionblock">
1985
+ <table><tr>
1986
+ <td class="icon">
1987
+ <img src="./images/important.png" alt="Important" />
1988
+ </td>
1989
+ <td class="content">Because #change_column_required changes the structure of a table,
1990
+ you can only call this method when connect_type==:local.</td>
1991
+ </tr></table>
1992
+ </div>
1993
+ </div></div>
1994
+ <div class="sidebarblock">
1995
+ <a id="add-index"></a>
1996
+ <div class="sidebar-content">
1997
+ <div class="sidebar-title">KBTable#add_index</div>
1998
+ <div class="listingblock">
1999
+ <div class="content">
2000
+ <pre><tt>plane_tbl.add_index(:name, :country)</tt></pre>
2001
+ </div></div>
2002
+ <p>This method allows you to add an index to an existing table. This index can
2003
+ consist of one or more columns. You must specify one or more column names
2004
+ that you want to make up the index.</p>
2005
+ <div class="admonitionblock">
2006
+ <table><tr>
2007
+ <td class="icon">
2008
+ <img src="./images/important.png" alt="Important" />
2009
+ </td>
2010
+ <td class="content">Because #add_index changes the structure of a table, you can
2011
+ only call this method when connect_type==:local.</td>
2012
+ </tr></table>
2013
+ </div>
2014
+ </div></div>
2015
+ <div class="sidebarblock">
2016
+ <a id="drop-index"></a>
2017
+ <div class="sidebar-content">
2018
+ <div class="sidebar-title">KBTable#drop_index</div>
2019
+ <div class="listingblock">
2020
+ <div class="content">
2021
+ <pre><tt>plane_tbl.drop_index(:name, :country)</tt></pre>
2022
+ </div></div>
2023
+ <p>This method allows you to drop an index from an existing table. You must
2024
+ specify one or more column names that make up the index that you want to
2025
+ drop.</p>
2026
+ <div class="admonitionblock">
2027
+ <table><tr>
2028
+ <td class="icon">
2029
+ <img src="./images/important.png" alt="Important" />
2030
+ </td>
2031
+ <td class="content">Because #drop_index changes the structure of a table, you can
2032
+ only call this method when connect_type==:local.</td>
2033
+ </tr></table>
2034
+ </div>
2035
+ </div></div>
2036
+ </div>
2037
+ <h2><a id="special-characters-in-data"></a>Special characters in data</h2>
2038
+ <div class="sectionbody">
2039
+ <p>Since KirbyBase tables are just plain-text, newline-delimited files with
2040
+ each field delimited by a <em>|</em>, certain ASCII characters could cause problems
2041
+ when used as input. For example, entering a newline character (\n on Unix,
2042
+ \r\n on Windows) as part of a record's data would cause problems later when
2043
+ KirbyBase attempted to read this record. Likewise, using the <em>|</em> character
2044
+ in your data would also cause problems as KirbyBase uses this character as a
2045
+ field delimiter. Finally, it turns out that Python has problems handling
2046
+ octal code \032 under Windows (possibly because it equates to Ctrl-Z), so
2047
+ to keep compatibility between the Ruby and Python versions of KirbyBase,
2048
+ this issue needs to be handled.</p>
2049
+ <p>To handle the above special characters as data input, KirbyBase checks all
2050
+ :String and :YAML input data and replaces the special characters with
2051
+ encodings that are safe. The following table shows how replacements are
2052
+ done:</p>
2053
+ <div class="tableblock">
2054
+ <table rules="all"
2055
+ frame="border"
2056
+ cellspacing="0" cellpadding="4">
2057
+ <col width="182" />
2058
+ <col width="240" />
2059
+ <thead>
2060
+ <tr>
2061
+ <th align="left">
2062
+ Input Character
2063
+ </th>
2064
+ <th align="left">
2065
+ KirbyBase Replacement
2066
+ </th>
2067
+ </tr>
2068
+ </thead>
2069
+ <tbody valign="top">
2070
+ <tr>
2071
+ <td align="left">
2072
+ \n
2073
+ </td>
2074
+ <td align="left">
2075
+ &amp;amp;linefeed;
2076
+ </td>
2077
+ </tr>
2078
+ <tr>
2079
+ <td align="left">
2080
+ \r
2081
+ </td>
2082
+ <td align="left">
2083
+ &amp;amp;carriage_return;
2084
+ </td>
2085
+ </tr>
2086
+ <tr>
2087
+ <td align="left">
2088
+ \032
2089
+ </td>
2090
+ <td align="left">
2091
+ &amp;amp;substitute;
2092
+ </td>
2093
+ </tr>
2094
+ <tr>
2095
+ <td align="left">
2096
+ |
2097
+ </td>
2098
+ <td align="left">
2099
+ &amp;amp;pipe;
2100
+ </td>
2101
+ </tr>
2102
+ <tr>
2103
+ <td align="left">
2104
+ &amp;
2105
+ </td>
2106
+ <td align="left">
2107
+ &amp;amp;
2108
+ </td>
2109
+ </tr>
2110
+ </tbody>
2111
+ </table>
2112
+ </div>
2113
+ <p>KirbyBase will translate to and from the special characters as data is
2114
+ written to and read from a table. It should all be transparent to the user.
2115
+ The only time you would encounter the replacement words is if you were to
2116
+ open up the physical table file in a text editor or read it in as input
2117
+ outside of KirbyBase.</p>
2118
+ </div>
2119
+ <h2><a id="table-structure"></a>Table Structure</h2>
2120
+ <div class="sectionbody">
2121
+ <p>Every table in KirbyBase is represented by a physical, newline-delimited
2122
+ text-file. Here is an example:</p>
2123
+ <div class="listingblock">
2124
+ <div class="content">
2125
+ <pre><tt>000006|000000|Struct|recno:Integer|name:String|country:String|speed:Integer
2126
+ 1|P-51|USA|403
2127
+ 2|P-51|USA|365
2128
+ 3|Sptitfire|England|345
2129
+ 4|Oscar|Japan|361
2130
+ 5|ME-109|Germany|366
2131
+ 6|Zero|Japan|377</tt></pre>
2132
+ </div></div>
2133
+ <p>The first line is the header rec. Each field is delimited by a "|". The
2134
+ first field in the header is the record counter. It is incremented by
2135
+ KirbyBase to create new record numbers when records are inserted.</p>
2136
+ <p>The second field in the header is the deleted-records counter. Every time a
2137
+ line in the file is blanked-out (see "The pack method"), this number is
2138
+ incremented. You can use this field in a maintenance script so that the
2139
+ table is packed whenever the deleted-records counter reaches, say, 5,000
2140
+ records.</p>
2141
+ <p>The third field in the header is the record_class field. If you specified a
2142
+ class when you created the table, it's name will show up here and records
2143
+ returned from a #select will be instances of this class. The default is
2144
+ "Struct".</p>
2145
+ <p>The fourth field in the header is the :recno field. This field is
2146
+ automatically added to the table when it is created. The field name and
2147
+ field type are separated by a ":".</p>
2148
+ <p>The rest of the fields are whatever you specified when you created the
2149
+ table.</p>
2150
+ <p>If there is a Z in the first position of the header rec and the rest of the
2151
+ file is a bunch of random characters, this means that the table is
2152
+ encrypted.</p>
2153
+ <p>Each record after the header record is simply a line of text. Newline
2154
+ characters delimit records.</p>
2155
+ </div>
2156
+ <h2><a id="server-notes"></a>Server Notes</h2>
2157
+ <div class="sectionbody">
2158
+ <p>There is a server script included in the distribution called kbserver.rb.
2159
+ This script uses DRb to turn KirbyBase into a client/server, multi-user
2160
+ dbms. This dbms server handles table locking for you so you don't have to
2161
+ worry about it.</p>
2162
+ </div>
2163
+ <h2><a id="tips-on-improving-performance"></a>Tips on improving performance</h2>
2164
+ <div class="sectionbody">
2165
+ <h3>Beware of Date/DateTime</h3>
2166
+ <p>Converting a String (the format in which data is stored in a KirbyBase
2167
+ table) to a Date/DateTime is slow. If you have a large table with a
2168
+ Date/DateTime field, this can result in long query times.</p>
2169
+ <p>To get around this, you can specify the field type as a :String, instead of
2170
+ a :Date/:DateTime. Queries will still work correctly, because Date/DateTime
2171
+ fields that are in String format sort the same way they would if they were
2172
+ in native format. Here's an example. The following two expressions will
2173
+ result in the same result set being returned:</p>
2174
+ <div class="listingblock">
2175
+ <div class="content">
2176
+ <pre><tt>date_field &lt;= Date.new(2005, 05, 11)</tt></pre>
2177
+ </div></div>
2178
+ <p>and</p>
2179
+ <div class="listingblock">
2180
+ <div class="content">
2181
+ <pre><tt>date_field_stored_as_string_field &lt;= "2005-05-11"</tt></pre>
2182
+ </div></div>
2183
+ <h3>Create indexes on large tables</h3>
2184
+ <p>The larger a table becomes, the more sense it makes to create an index on
2185
+ one or more of it's fields. Even though you take a hit when KirbyBase first
2186
+ initializes because it has to create the index arrays, you make up for it
2187
+ after that in greatly improved query speeds. I have noticed speed-ups of
2188
+ as much as 10x on large tables.</p>
2189
+ <h3>Create indexes on foreign keys</h3>
2190
+ <p>If you have a Link_many on a table field, you might want to think about
2191
+ creating an index on the field in the child table that is being linked to.
2192
+ When performing a one-to-many link, KirbyBase will automatically take
2193
+ advantage of an index on the link field in the child table.</p>
2194
+ <p>By the way, the same holds true for Lookups.</p>
2195
+ <h3>When possible, always search by :recno</h3>
2196
+ <p>This might be a no-brainer, but, if you have the chance to select by
2197
+ :recno, use the built-in #select_by_recno_index method (or the #[] method).
2198
+ This is even faster than selecting on a regularly indexed field, because the
2199
+ :recno index that KirbyBase creates for each table is actually a Hash, not
2200
+ an Array like all of the regular indexes. So selects are even faster.</p>
2201
+ </div>
2202
+ <h2><a id="client-server-diagram"></a>Client/Server memory space diagram</h2>
2203
+ <div class="sectionbody">
2204
+ <div class="imageblock">
2205
+ <div class="content">
2206
+ <img src="images/client_server.png" alt="images/client_server.png"/>
2207
+ </div>
2208
+ <div class="image-title">Figure: Client/Server (separate memory spaces) mode.</div>
2209
+ </div>
2210
+ </div>
2211
+ <h2><a id="single-user-diagram"></a>Single-user memory space diagram</h2>
2212
+ <div class="sectionbody">
2213
+ <div class="imageblock">
2214
+ <div class="content">
2215
+ <img src="images/single_user.png" alt="images/single_user.png"/>
2216
+ </div>
2217
+ <div class="image-title">Figure: Single-user (embedded) mode.</div>
2218
+ </div>
2219
+ </div>
2220
+ <h2><a id="license"></a>License</h2>
2221
+ <div class="sectionbody">
2222
+ <p>KirbyBase is distributed under the same license terms as Ruby.</p>
2223
+ </div>
2224
+ <h2><a id="credits"></a>Credits</h2>
2225
+ <div class="sectionbody">
2226
+ <div class="admonitionblock">
2227
+ <table><tr>
2228
+ <td class="icon">
2229
+ <img src="./images/note.png" alt="Note" />
2230
+ </td>
2231
+ <td class="content">This manual was produced using the awesome text document formatter,
2232
+ <a href="http://www.methods.co.nz/asciidoc/">AsciiDoc</a>.</td>
2233
+ </tr></table>
2234
+ </div>
2235
+ </div>
2236
+ <div id="footer">
2237
+ <div id="footer-text">
2238
+ Version 2.5<br />
2239
+ Last updated 01-Dec-2005 13:28:12 Eastern Daylight Time
2240
+ </div>
2241
+ </div>
2242
+ </body>
2243
+ </html>