fireruby 0.4.1-mswin32 → 0.4.2-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/README +456 -456
- data/doc/license.txt +411 -411
- data/examples/example01.rb +65 -65
- data/lib/SQLType.rb +223 -227
- data/lib/fireruby.rb +22 -22
- data/lib/fr_lib.so +0 -0
- data/lib/mkdoc +1 -1
- data/lib/src.rb +1795 -1795
- data/test/AddRemoveUserTest.rb +56 -55
- data/test/BackupRestoreTest.rb +99 -99
- data/test/BlobTest.rb +57 -0
- data/test/CharacterSetTest.rb +63 -63
- data/test/ConnectionTest.rb +111 -111
- data/test/DDLTest.rb +54 -54
- data/test/DatabaseTest.rb +83 -83
- data/test/GeneratorTest.rb +50 -50
- data/test/KeyTest.rb +140 -140
- data/test/ResultSetTest.rb +162 -162
- data/test/RoleTest.rb +73 -0
- data/test/RowCountTest.rb +65 -65
- data/test/RowTest.rb +203 -203
- data/test/SQLTest.rb +182 -182
- data/test/SQLTypeTest.rb +101 -101
- data/test/ServiceManagerTest.rb +29 -29
- data/test/StatementTest.rb +135 -135
- data/test/TestSetup.rb +11 -11
- data/test/TransactionTest.rb +112 -112
- data/test/TypeTest.rb +92 -92
- data/test/UnitTest.rb +65 -64
- metadata +49 -110
- data/doc/CVS/Entries +0 -3
- data/doc/CVS/Entries.Log +0 -2
- data/doc/CVS/Repository +0 -1
- data/doc/CVS/Root +0 -1
- data/doc/classes/CVS/Entries +0 -1
- data/doc/classes/CVS/Entries.Log +0 -1
- data/doc/classes/CVS/Repository +0 -1
- data/doc/classes/CVS/Root +0 -1
- data/doc/classes/FireRuby/CVS/Entries +0 -1
- data/doc/classes/FireRuby/CVS/Entries.Log +0 -7
- data/doc/classes/FireRuby/CVS/Repository +0 -1
- data/doc/classes/FireRuby/CVS/Root +0 -1
- data/doc/classes/FireRuby/Connection.src/CVS/Entries +0 -1
- data/doc/classes/FireRuby/Connection.src/CVS/Repository +0 -1
- data/doc/classes/FireRuby/Connection.src/CVS/Root +0 -1
- data/doc/classes/FireRuby/Database.src/CVS/Entries +0 -1
- data/doc/classes/FireRuby/Database.src/CVS/Repository +0 -1
- data/doc/classes/FireRuby/Database.src/CVS/Root +0 -1
- data/doc/classes/FireRuby/FireRubyError.src/CVS/Entries +0 -1
- data/doc/classes/FireRuby/FireRubyError.src/CVS/Repository +0 -1
- data/doc/classes/FireRuby/FireRubyError.src/CVS/Root +0 -1
- data/doc/classes/FireRuby/Generator.src/CVS/Entries +0 -1
- data/doc/classes/FireRuby/Generator.src/CVS/Repository +0 -1
- data/doc/classes/FireRuby/Generator.src/CVS/Root +0 -1
- data/doc/classes/FireRuby/ResultSet.src/CVS/Entries +0 -1
- data/doc/classes/FireRuby/ResultSet.src/CVS/Repository +0 -1
- data/doc/classes/FireRuby/ResultSet.src/CVS/Root +0 -1
- data/doc/classes/FireRuby/Statement.src/CVS/Entries +0 -1
- data/doc/classes/FireRuby/Statement.src/CVS/Repository +0 -1
- data/doc/classes/FireRuby/Statement.src/CVS/Root +0 -1
- data/doc/classes/FireRuby/Transaction.src/CVS/Entries +0 -1
- data/doc/classes/FireRuby/Transaction.src/CVS/Repository +0 -1
- data/doc/classes/FireRuby/Transaction.src/CVS/Root +0 -1
- data/doc/files/CVS/Entries +0 -1
- data/doc/files/CVS/Repository +0 -1
- data/doc/files/CVS/Root +0 -1
- data/examples/CVS/Entries +0 -2
- data/examples/CVS/Repository +0 -1
- data/examples/CVS/Root +0 -1
- data/lib/CVS/Entries +0 -6
- data/lib/CVS/Repository +0 -1
- data/lib/CVS/Root +0 -1
- data/test/CVS/Entries +0 -20
- data/test/CVS/Repository +0 -1
- data/test/CVS/Root +0 -1
data/doc/README
CHANGED
@@ -1,456 +1,456 @@
|
|
1
|
-
= FireRuby Version 0.4.1
|
2
|
-
FireRuby is an extension for the Ruby programming language that provides access
|
3
|
-
to the Firebird open source RDBMS. The FireRuby library is release under the
|
4
|
-
Mozilla Public Licence version 1.1 and is free for commercial use.
|
5
|
-
|
6
|
-
---
|
7
|
-
|
8
|
-
== Enhancements & Alterations
|
9
|
-
|
10
|
-
This release has been brought about as a direct result of efforts to get the
|
11
|
-
library working on a 64 bit platform. This process exposed some code of
|
12
|
-
questionable quality. All of the issues raised in getting a 64 bit build have
|
13
|
-
been addressed and it's only fair that the improvements obtained be passed on
|
14
|
-
to all platforms. Functionally nothing has changed since the last release and
|
15
|
-
the new version should replace the old with no problems.
|
16
|
-
|
17
|
-
=== Bug Fixes
|
18
|
-
|
19
|
-
A number of bug fixes were implemented as part of the effort to get the library
|
20
|
-
working on a 64 bit platform. None of these had been raised as bugs against the
|
21
|
-
library so I have nothing specific to tick off.
|
22
|
-
|
23
|
-
=== Backward Compatibility
|
24
|
-
|
25
|
-
Version 0.4.0 of the library made fundamental changes to functionality that was
|
26
|
-
available in earlier versions of the library. To help accommodate this change
|
27
|
-
elements were added to support backward compatibility. The relevant details are
|
28
|
-
listed here...
|
29
|
-
|
30
|
-
- Row objects were switched from keying on column names to keying on column
|
31
|
-
aliases. To revert to the older functionality assign a value of true to the
|
32
|
-
$FireRubySettings[:ALIAS_KEYS] global setting.
|
33
|
-
|
34
|
-
- DATE columns were switched from being returned as Time objects to be returned
|
35
|
-
as Date objects. To revert to the older functionality assign a value of true
|
36
|
-
to the $FireRubySettings[:DATE_AS_DATE] global setting.
|
37
|
-
|
38
|
-
One other point to note is that, as of version 0.4.0, Enumerable is included in
|
39
|
-
the Row and ResultSet classes.
|
40
|
-
|
41
|
-
=== Issues
|
42
|
-
|
43
|
-
Nothing is perfect so this section outlines those issues that are known to
|
44
|
-
exist as of this release.
|
45
|
-
|
46
|
-
- The service manager functionality does not appear to work on the Mac OS X
|
47
|
-
platform. I don't believe that this is a problem in the FireRuby code as I
|
48
|
-
have tested the Firebird gbak utility with the -service option and it gives
|
49
|
-
the same result. If anyone knows this to be untrue or of a work around let me
|
50
|
-
know.
|
51
|
-
|
52
|
-
- The library currently does not support array columns. This may be implemented
|
53
|
-
for a later release depending on demand. No-one has asked for this so far so
|
54
|
-
I'm starting to think that people don't make much use of array columns.
|
55
|
-
|
56
|
-
- The library can be a bit touchy if you don't clean up after yourself. This
|
57
|
-
can result in a segmentation violation whenever your program stops if you've
|
58
|
-
left a ResultSet or Statement object unclosed. Check through your code to
|
59
|
-
insure that this isn't the case before contacting me about problems in this
|
60
|
-
line.
|
61
|
-
|
62
|
-
- The unit tests are currently set up on the assumption that the password for
|
63
|
-
your sysdba account is 'masterkey'. If this is not the case, or if you wish
|
64
|
-
to use an alternative user for testing, edit the TestSetup.rb file in the
|
65
|
-
unit test directory and update the entries there as appropriate. I should also
|
66
|
-
note that you may need to alter permissions on the test directory to run the
|
67
|
-
actual unit tests on Linux/Unix.
|
68
|
-
|
69
|
-
---
|
70
|
-
|
71
|
-
== Credit Where Credit Is Due
|
72
|
-
|
73
|
-
Over its lifetime the FireRuby library has benefitted from input provided by a
|
74
|
-
number of individuals. This section acknowledges these inputs...
|
75
|
-
|
76
|
-
<b>Ken Kunz</b>: Ken has been a strong supporter of the library from early on and
|
77
|
-
has contributed through feedback, testing and suggestions. For some time he
|
78
|
-
produced and tested the Linux builds of the library.
|
79
|
-
|
80
|
-
<b>David Walthour</b>: David basically executed all of the work to generate the
|
81
|
-
64 bit version of the library, along the way exposing some flaws in the code
|
82
|
-
(amazing what a bit of peer review can find!). David produced the 64 bit version
|
83
|
-
of the library gem.
|
84
|
-
|
85
|
-
<b>John Wood</b>: John currently builds and tests the Mac OS X version of the
|
86
|
-
library.
|
87
|
-
|
88
|
-
<b>Art Federov</b>: Art provided input on handling and testing character sets.
|
89
|
-
|
90
|
-
---
|
91
|
-
|
92
|
-
== Installation & Usage
|
93
|
-
|
94
|
-
The library is provided as a gem and built for use with Ruby 1.8+. Testing
|
95
|
-
against an earlier release of Ruby has not been performed. Installation requires
|
96
|
-
the Ruby Gems package to be installed. Assuming that these installation criteria
|
97
|
-
have been met the library can be installed on Windows by executing a command
|
98
|
-
such as the following...
|
99
|
-
|
100
|
-
gem install fireruby-0.4.1-mswin32.gem
|
101
|
-
|
102
|
-
On the Mac OS X platform you may require super user privilege if your Ruby is
|
103
|
-
installed to the default location (i.e. /usr/local/lib). In this case you can
|
104
|
-
use the sudo command to make the installation like this...
|
105
|
-
|
106
|
-
sudo gem install fireruby-0.4.1-powerpc-darwin.gem
|
107
|
-
|
108
|
-
Once the gem installation is complete the FireRuby functionality can be accessed
|
109
|
-
in code with the usual gem style requires...
|
110
|
-
|
111
|
-
require 'rubygems'
|
112
|
-
require 'fireruby'
|
113
|
-
|
114
|
-
=== Build Details
|
115
|
-
|
116
|
-
The FireRuby library is a Ruby extension written in C. The avoid build issues
|
117
|
-
binary versions are provided for a number of platforms, including...
|
118
|
-
|
119
|
-
- Windows: Built against a version of Ruby installed using the one-click
|
120
|
-
installer and using the freely available Microsoft development tools. This
|
121
|
-
version was compiled against version 1.5.2 of Firebird.
|
122
|
-
|
123
|
-
- Linux: Built on Ubuntu Linux (Breezy Badger) using a version of Ruby 1.8.2
|
124
|
-
installed via the Synaptic package manager. This package manager was also
|
125
|
-
used to make an installation of Firebird.
|
126
|
-
|
127
|
-
- Mac OS X: Build on version 10.4.3 of OS X against the 1.8.2 version of Ruby
|
128
|
-
that comes with the operating system. A framework installation of Firebird
|
129
|
-
version 1.5.1 was used to make the build.
|
130
|
-
|
131
|
-
Its possible to try and build the library on other platforms so I'll provide a
|
132
|
-
few details as to how to go about doing this. The first step is to download the
|
133
|
-
CVS tar ball from the Ruby Forge site and expand it into a local directory. This
|
134
|
-
will create a directory called fireruby. Change into this directory and then
|
135
|
-
into the fireruby/src subdirectory.
|
136
|
-
|
137
|
-
This directory contains a file called extconf.rb that is used to create the
|
138
|
-
make file used to build the library. The make file is created by executing this
|
139
|
-
file but before you do there are a number of parameters that you should be
|
140
|
-
aware of. The main one of these is --with-firebird-dir. This parameter is used
|
141
|
-
to indicate the whereabouts of the Firebird headers and libraries. The following
|
142
|
-
is an example of how this might be used...
|
143
|
-
|
144
|
-
ruby extconf.rb --with-firebird-dir=/usr/local/firebird
|
145
|
-
|
146
|
-
You may need to customise the path for your own Firebird installation. The path
|
147
|
-
specified should be a directory that contains subdirectories called 'lib' and
|
148
|
-
'include'. The lib subdirectory should contain the fbclient shared library and
|
149
|
-
include should contain the ibase.h header file.
|
150
|
-
|
151
|
-
A note for Windows users. The library requires the free Microsoft C++ compiler,
|
152
|
-
the Windows SDK, the .NET SDK and nmake to build. If you have all of these
|
153
|
-
and Firebird installed to default locations then you can create a make file
|
154
|
-
using the mkmf.bat batch file in the src directory.
|
155
|
-
|
156
|
-
Once you have the make file you can attempt a library build using either make
|
157
|
-
(on Unix/Linux) or nmake (on Windows). If it builds successfully you can move
|
158
|
-
on to creating a gem file for installation. To do this, change into the ../gem
|
159
|
-
directory. In this directory you can do the following (on Windows)...
|
160
|
-
|
161
|
-
make_gem
|
162
|
-
|
163
|
-
...or the following (on Unix/Linux)...
|
164
|
-
|
165
|
-
ruby make_gem.rb
|
166
|
-
|
167
|
-
This will create the gem file in the main fireruby directory. Install this and
|
168
|
-
execute the unit tests to check whether you're version is working.
|
169
|
-
|
170
|
-
=== So How Do I Use It?
|
171
|
-
|
172
|
-
This section will provide some examples of usage for the the FireRuby classes.
|
173
|
-
Throughout the code the following set of assumptions are made.
|
174
|
-
|
175
|
-
- The user name and password that will be employed to attach to the database
|
176
|
-
are 'sysdba' and 'masterkey' respectively (the Firebird defaults).
|
177
|
-
|
178
|
-
- The databases attached to will all be local (i.e. they will all reside on the
|
179
|
-
same machine) as the test code.
|
180
|
-
|
181
|
-
A database, from the Firebird perspective, is made up of one or more files. From
|
182
|
-
a FireRuby perspective a user interaction with a database starts through the
|
183
|
-
Database class. This class provides facilities that allow for creating, dropping
|
184
|
-
and connecting to database instances. For example, to obtain a connection to a
|
185
|
-
database you would use something like the following...
|
186
|
-
|
187
|
-
require 'rubygems'
|
188
|
-
require 'fireruby'
|
189
|
-
|
190
|
-
include FireRuby
|
191
|
-
|
192
|
-
db = Database.new('./test.fdb')
|
193
|
-
c = db.connect('sysdba', 'masterkey')
|
194
|
-
|
195
|
-
This example starts by requiring the necessary files and including the FireRuby
|
196
|
-
module locally - later examples will not detail these lines but they are always
|
197
|
-
required to use the FireRuby code.
|
198
|
-
|
199
|
-
The first line of code after the include creates a new database object. This
|
200
|
-
process does not actually create the database file (see the Database#create
|
201
|
-
method API documentation if that is what you want to do), it simple creates an
|
202
|
-
abstract reference to a database. In creating the Database object we had to
|
203
|
-
provide a database specification string which identifies the database we want to
|
204
|
-
access. In this case we are specifying a database in the current working
|
205
|
-
directory called 'test.fdb'. See the Firebird documentation for details on the
|
206
|
-
structure of more complex database specifications.
|
207
|
-
|
208
|
-
The last line of code in the example given above opens a connection to the
|
209
|
-
database. In doing this we had to provide two parameters, the database user
|
210
|
-
name and password. These are required to gain access to the database.
|
211
|
-
|
212
|
-
A connection represents a conduit to a database and obtaining a connection is a
|
213
|
-
prerequisite to working with the database. The FireRuby library support having
|
214
|
-
multiple connections, to one or more databases, using one or more users, active
|
215
|
-
simultaneously. FireRuby represents a database connection through objects of the
|
216
|
-
Connection class. This class provides functionality to determine the current
|
217
|
-
state a database connection (open or closed) and for closing the connection.
|
218
|
-
Connections take up resources, both locally and on the database server and
|
219
|
-
should be explicitly closed when they are no longer required.
|
220
|
-
|
221
|
-
The connection class also provides a set of conveniences methods to allow for
|
222
|
-
the execution of SQL against a database. These methods, execute_immediate and
|
223
|
-
execute, represently two slightly different approaches to executing SQL against
|
224
|
-
the database. Refer to the API documentation for more information.
|
225
|
-
|
226
|
-
An advantage of using a relational database management system like Firebird is
|
227
|
-
that it provides transactions. A transaction represents a block of work that is
|
228
|
-
either all completed successful or none of it is applied. From the perspective
|
229
|
-
of the database this means that a series of steps that make changes to the
|
230
|
-
tables in the database can be wrapped in a transaction to insure that they
|
231
|
-
either all complete or that none of the changes are applied.
|
232
|
-
|
233
|
-
The FireRuby library represents a database transaction through instances of the
|
234
|
-
Transaction class. There are two ways of obtaining a Transaction using the
|
235
|
-
library, both requiring you to have an open database connection. The first way
|
236
|
-
is to construct a new Transaction object like so...
|
237
|
-
|
238
|
-
tx = Transaction.new(connection)
|
239
|
-
|
240
|
-
The Transaction constructor takes a single parameter which must be either a
|
241
|
-
Connection object or an array of Connection objects. If you pass an array of
|
242
|
-
Connection objects to this constructor then the Transaction created will apply
|
243
|
-
across all of the databases that the connections refer to, allowing you to
|
244
|
-
have transactional control of work that must utilise more than one database. The
|
245
|
-
second way to obtain a transaction is to simply request one from a Connection
|
246
|
-
object, like so.
|
247
|
-
|
248
|
-
tx = connection.start_transaction
|
249
|
-
|
250
|
-
In this case the transaction will only ever apply to one database, the one that
|
251
|
-
the connection relates to. This method also accepts a block, taking a single
|
252
|
-
parameter. The parameter passed to the block will be the transaction created.
|
253
|
-
In this case the lifetime of the transaction is delimited by the block. If the
|
254
|
-
block completes successfully then the work of the transaction will be committed
|
255
|
-
to the database. If the block raises an exception then the transactional work
|
256
|
-
will be rolled back.
|
257
|
-
|
258
|
-
When the block of work associated with a transaction is complete the user must
|
259
|
-
instruct the system to either apply the changes implemented by the work or to
|
260
|
-
discard them. This can be done by calling the commit or rollback methods of the
|
261
|
-
Transaction class respectively. Once a transaction has been committed or rolled
|
262
|
-
back it can no longer be used and should be discarded. Note that attempts to
|
263
|
-
close a connection that has an active transaction against it will fail, so one
|
264
|
-
of the commit or rollback methods should be explictly called in code. The
|
265
|
-
block technique detailed above helps protect against the failure to do this and
|
266
|
-
is a useful technique.
|
267
|
-
|
268
|
-
The Transaction object provides a number of other informational and utility
|
269
|
-
methods. Check the API documentation for this class for more information.
|
270
|
-
|
271
|
-
So we've looked at connections and transactions, but how do we actually do
|
272
|
-
something practical with the database. Well there are a number of possible
|
273
|
-
approaches that we can take to this. Both the Connection and Transaction classes
|
274
|
-
have convenience method for the execution of SQL statements and these are useful
|
275
|
-
for quick SQL. Where you want something that you can repeatedly reuse and,
|
276
|
-
optionally, pass parameters to then you need the Statement class.
|
277
|
-
|
278
|
-
The Statement class represents a SQL statement that has been validated and
|
279
|
-
prepared for execution. Here's an example of creating a SQL statement...
|
280
|
-
|
281
|
-
s = Statement.new(cxn, tx, 'SELECT * FROM MY_TABLE', 3)
|
282
|
-
|
283
|
-
In this example we have created a Statement object that wraps a SQL select from
|
284
|
-
a table called MY_TABLE. The first parameter to the constructor is a Connection
|
285
|
-
object and the second is a Transaction, both mandatory. You may be thinking
|
286
|
-
'why do I need a transaction here, I'm not changing anything?'. This is true
|
287
|
-
(well sort of) but it's a requirement of the underlying database system. This
|
288
|
-
is also the case for the final parameter to the constructor. The value 3 is
|
289
|
-
the SQL dialect to be used with the Statement. This exists for reason arising
|
290
|
-
from the move from closed source Interbase to open source Firebird. The
|
291
|
-
parameter should be given a value of between 1 and 3. If you're not sure what
|
292
|
-
this is and you're only using Firebird it's probably safe to use a value of
|
293
|
-
3 here. Other values are for backward compatibility. Consult the Firebird and
|
294
|
-
Interbase documentation for more details.
|
295
|
-
|
296
|
-
Anyway, now that we have our Statement how do we use it? Well, the answer is
|
297
|
-
that we call once of the Statement objects execute methods. The one to be called
|
298
|
-
depends on whether the Statement requires parameters or not. What are parameters
|
299
|
-
you ask? Well, look at the following...
|
300
|
-
|
301
|
-
s = Statement.new(cxn, tx, 'SELECT * FROM MY_TABLE WHERE MYID = ?', 3)
|
302
|
-
|
303
|
-
Note that the SQL select for this Statement contains a '?'. This is a position
|
304
|
-
holder for a value that the statement expects to be provided later. A Statement
|
305
|
-
that wraps such a piece of SQL must be provided with the necessary parameters
|
306
|
-
to execute properly. Where a Statement object represents SQL that requires a
|
307
|
-
parameter then the execute_for method must be called, like this...
|
308
|
-
|
309
|
-
s.execute_for([25])
|
310
|
-
|
311
|
-
This code executes the SQL substituting the parameters from the array of data
|
312
|
-
passed to the function call. If a Statement object represents SQL that does not
|
313
|
-
require parameter values a call to the execute method will suffice, such as the
|
314
|
-
following...
|
315
|
-
|
316
|
-
s.execute
|
317
|
-
|
318
|
-
The execute methods for the Statement class, as with all of the execute methods
|
319
|
-
for the FireRuby library, have three potential return values. They will either
|
320
|
-
return an Integer, a ResultSet object or nil. A ResultSet object will only be
|
321
|
-
returned for SQL statements that constitute a query, irrespective of whether
|
322
|
-
that query returns any data. For all other SQL statements (inserts, updates and
|
323
|
-
deletes) the execute method will return a count of the number of rows affected
|
324
|
-
by the statement execution. For any other SQL statements the various execute
|
325
|
-
methods will return nil.
|
326
|
-
|
327
|
-
A ResultSet object represents a handle by which the data retrieved for a SQL
|
328
|
-
query can be accessed. While it's possible to obtain a ResultSet from one of the
|
329
|
-
execute methods on the Connection, Transaction or Statement classes it is more
|
330
|
-
efficient to create one directly. The constructor for the ResultSet class
|
331
|
-
accepts the same arguments as the constructor for the Statement class but will
|
332
|
-
throw an exception if the SQL statement specified is not a query.
|
333
|
-
|
334
|
-
Once we have obtained a ResultSet we can extract the rows of data for a query
|
335
|
-
from it. To fetch a row of data from a ResultSet object you call the fetch
|
336
|
-
method, like the following...
|
337
|
-
|
338
|
-
row = r.fetch
|
339
|
-
|
340
|
-
This fetches a single row of data for a query represented as a Row object (which
|
341
|
-
will be covered shortly). The ResultSet class also provides for iteration across
|
342
|
-
the contents of a result set by providing an each method. The block to the each
|
343
|
-
method will be passed the data for the ResultSet, a row at a time.
|
344
|
-
|
345
|
-
It should be noted that both the Statement and ResultSet objects hold resources
|
346
|
-
while they are active. They both possess close methods and these should be
|
347
|
-
explicitly called to release the associated resources. The exception to this
|
348
|
-
rule is for ResultSets. If you select all of the rows from a ResultSet then the
|
349
|
-
resources for the ResultSet are automatically released. It is still safe to call
|
350
|
-
close on such a ResultSet as this will not cause errors.
|
351
|
-
|
352
|
-
Okay, so you've gotten a row of data in the form of a Row object from your
|
353
|
-
ResultSet, how do we get the data out of it? Well, there are a number of ways
|
354
|
-
of doing this. You can treat the Row object like an array and dereference the
|
355
|
-
columns of data within the row like this...
|
356
|
-
|
357
|
-
value = row[1]
|
358
|
-
|
359
|
-
The index specified to the array dereference operator specifies the column that
|
360
|
-
you want the data for. Column indices start at 0. Alternatively you can treat
|
361
|
-
the Row object like a read only Hash object and use the column name to access
|
362
|
-
the data, like this...
|
363
|
-
|
364
|
-
value = row['MYID']
|
365
|
-
|
366
|
-
This is beneficial as it frees you from the constraint of knowing the ordering
|
367
|
-
of the columns within the row. For more information of the Row class please
|
368
|
-
consult the API documentation.
|
369
|
-
|
370
|
-
That covers the bulk of the SQL classes provided by the FireRuby library. The
|
371
|
-
two which haven't been touched upon are the Generator class and the Blob class.
|
372
|
-
|
373
|
-
The Generator class is a wrapper around the Firebird generator facility. A
|
374
|
-
generator, also known as a sequence, provides a means of creating a list of
|
375
|
-
numeric values in a way that is guaranteed to be thread and process safe. Used
|
376
|
-
properly generators can be employed to create unique sequences that make perfect
|
377
|
-
table keys. Consult the API documentation for more details on the Generator
|
378
|
-
class.
|
379
|
-
|
380
|
-
The Blob class is returned as part of the Row object data obtained from a
|
381
|
-
ResultSet. The class wraps the concept of a binary large object stored in the
|
382
|
-
database. Consult the API documentation for further information.
|
383
|
-
|
384
|
-
=== Errors
|
385
|
-
|
386
|
-
Whenever a problem occurs within a FireRuby library class then it is likely that
|
387
|
-
a FireRubyException will be thrown. The FireRubyException class is the error
|
388
|
-
class used by the FireRuby library whenever it hits trouble. The class provides
|
389
|
-
a means of finding out a little more about what exactly has gone wrong. Again,
|
390
|
-
consult the API documentation for more details.
|
391
|
-
|
392
|
-
=== Firebird Service Manager
|
393
|
-
|
394
|
-
The FireRuby library provides a set of class that provide for an interaction
|
395
|
-
with the Firebird service manager. This interaction allows for the execution of
|
396
|
-
tasks, such as the backing up of a database, on the database server. To execute
|
397
|
-
such tasks against the service manager for a Firebird instance you first need
|
398
|
-
to obtain a ServiceManager class instance. This can be done as follows...
|
399
|
-
|
400
|
-
sm = ServiceManager.new('localhost')
|
401
|
-
|
402
|
-
The constructor for the ServiceManager class takes a single parameter that is
|
403
|
-
the host name of the server running the Firebird instance. In the example above
|
404
|
-
this would be a local machine but could be any machine that can be reached over
|
405
|
-
the network (NOTE: although Firebird supports a number of underlying transport
|
406
|
-
protocols in accessing a service manager currently only TCP/IP is supported for
|
407
|
-
the FireRuby library).
|
408
|
-
|
409
|
-
The next step in executing service manager tasks involves connecting your
|
410
|
-
ServiceManager object to the service manager for a Firebird instance. To do this
|
411
|
-
you must supply a user name and password. The user name and password used must
|
412
|
-
be a user that exists on the Firebird instance. The user you connect as can
|
413
|
-
affect the access to services that you receive. For example, to connect as the
|
414
|
-
database administrator you might do the following...
|
415
|
-
|
416
|
-
sm.connect('sysdba', 'masterkey')
|
417
|
-
|
418
|
-
Assuming that this succeeds you are now ready to execute tasks through your
|
419
|
-
ServiceManager object. Within the FireRuby library individual task are broken
|
420
|
-
out into separate classes. For this release (0.4.1) there are four task classes
|
421
|
-
provided in the library - Backup, Restore, AddUser and RemoveUser. I think the
|
422
|
-
class names are relatively self explanatory but if you want more information
|
423
|
-
consult the API documentation for a class.
|
424
|
-
|
425
|
-
To use the task classes you construct a class instance, configure it as you may
|
426
|
-
need and then execute it. Here's an example of going through this procedure to
|
427
|
-
create a database backup...
|
428
|
-
|
429
|
-
b = Backup.new('c:\database\work.fdb', 'c:\temp\work.bak')
|
430
|
-
b.metadata_only = true
|
431
|
-
b.execute(sm)
|
432
|
-
|
433
|
-
The first list creates the new Backup object. The first parameter passed to this
|
434
|
-
call is the path and name of the primary file of the database to be backed up
|
435
|
-
(NOTE: All paths are relative to the database server). The second parameter is
|
436
|
-
the path and name of the database backup file to be created. The second line
|
437
|
-
sets an attribute on the class to indicate that only the metadata (i.e. it's
|
438
|
-
schema but not it's data) for the specified database should be included in the
|
439
|
-
backup. The final line begins the execution of the backup task on the database
|
440
|
-
server. This will block until completion.
|
441
|
-
|
442
|
-
Its also possible to execute a batch of tasks against a service manager. To do
|
443
|
-
this you would accumulate the tasks to be executed and then pass them all at the
|
444
|
-
same time to the ServiceManager#execute method, like so...
|
445
|
-
|
446
|
-
t = Array.new
|
447
|
-
t.push(Backup.new('c:\database\work.fdb', 'c:\temp\work.bak'))
|
448
|
-
...
|
449
|
-
# Create more tasks here and add them to the array.
|
450
|
-
|
451
|
-
sm.execute(*t)
|
452
|
-
|
453
|
-
The tasks will be executed in the order they are specified to the ServiceManager
|
454
|
-
object. For the example above this would mean in the order they were added to
|
455
|
-
the array. For more details on the ServiceManager class and the various task
|
456
|
-
classes please consult the API documentation.
|
1
|
+
= FireRuby Version 0.4.1
|
2
|
+
FireRuby is an extension for the Ruby programming language that provides access
|
3
|
+
to the Firebird open source RDBMS. The FireRuby library is release under the
|
4
|
+
Mozilla Public Licence version 1.1 and is free for commercial use.
|
5
|
+
|
6
|
+
---
|
7
|
+
|
8
|
+
== Enhancements & Alterations
|
9
|
+
|
10
|
+
This release has been brought about as a direct result of efforts to get the
|
11
|
+
library working on a 64 bit platform. This process exposed some code of
|
12
|
+
questionable quality. All of the issues raised in getting a 64 bit build have
|
13
|
+
been addressed and it's only fair that the improvements obtained be passed on
|
14
|
+
to all platforms. Functionally nothing has changed since the last release and
|
15
|
+
the new version should replace the old with no problems.
|
16
|
+
|
17
|
+
=== Bug Fixes
|
18
|
+
|
19
|
+
A number of bug fixes were implemented as part of the effort to get the library
|
20
|
+
working on a 64 bit platform. None of these had been raised as bugs against the
|
21
|
+
library so I have nothing specific to tick off.
|
22
|
+
|
23
|
+
=== Backward Compatibility
|
24
|
+
|
25
|
+
Version 0.4.0 of the library made fundamental changes to functionality that was
|
26
|
+
available in earlier versions of the library. To help accommodate this change
|
27
|
+
elements were added to support backward compatibility. The relevant details are
|
28
|
+
listed here...
|
29
|
+
|
30
|
+
- Row objects were switched from keying on column names to keying on column
|
31
|
+
aliases. To revert to the older functionality assign a value of true to the
|
32
|
+
$FireRubySettings[:ALIAS_KEYS] global setting.
|
33
|
+
|
34
|
+
- DATE columns were switched from being returned as Time objects to be returned
|
35
|
+
as Date objects. To revert to the older functionality assign a value of true
|
36
|
+
to the $FireRubySettings[:DATE_AS_DATE] global setting.
|
37
|
+
|
38
|
+
One other point to note is that, as of version 0.4.0, Enumerable is included in
|
39
|
+
the Row and ResultSet classes.
|
40
|
+
|
41
|
+
=== Issues
|
42
|
+
|
43
|
+
Nothing is perfect so this section outlines those issues that are known to
|
44
|
+
exist as of this release.
|
45
|
+
|
46
|
+
- The service manager functionality does not appear to work on the Mac OS X
|
47
|
+
platform. I don't believe that this is a problem in the FireRuby code as I
|
48
|
+
have tested the Firebird gbak utility with the -service option and it gives
|
49
|
+
the same result. If anyone knows this to be untrue or of a work around let me
|
50
|
+
know.
|
51
|
+
|
52
|
+
- The library currently does not support array columns. This may be implemented
|
53
|
+
for a later release depending on demand. No-one has asked for this so far so
|
54
|
+
I'm starting to think that people don't make much use of array columns.
|
55
|
+
|
56
|
+
- The library can be a bit touchy if you don't clean up after yourself. This
|
57
|
+
can result in a segmentation violation whenever your program stops if you've
|
58
|
+
left a ResultSet or Statement object unclosed. Check through your code to
|
59
|
+
insure that this isn't the case before contacting me about problems in this
|
60
|
+
line.
|
61
|
+
|
62
|
+
- The unit tests are currently set up on the assumption that the password for
|
63
|
+
your sysdba account is 'masterkey'. If this is not the case, or if you wish
|
64
|
+
to use an alternative user for testing, edit the TestSetup.rb file in the
|
65
|
+
unit test directory and update the entries there as appropriate. I should also
|
66
|
+
note that you may need to alter permissions on the test directory to run the
|
67
|
+
actual unit tests on Linux/Unix.
|
68
|
+
|
69
|
+
---
|
70
|
+
|
71
|
+
== Credit Where Credit Is Due
|
72
|
+
|
73
|
+
Over its lifetime the FireRuby library has benefitted from input provided by a
|
74
|
+
number of individuals. This section acknowledges these inputs...
|
75
|
+
|
76
|
+
<b>Ken Kunz</b>: Ken has been a strong supporter of the library from early on and
|
77
|
+
has contributed through feedback, testing and suggestions. For some time he
|
78
|
+
produced and tested the Linux builds of the library.
|
79
|
+
|
80
|
+
<b>David Walthour</b>: David basically executed all of the work to generate the
|
81
|
+
64 bit version of the library, along the way exposing some flaws in the code
|
82
|
+
(amazing what a bit of peer review can find!). David produced the 64 bit version
|
83
|
+
of the library gem.
|
84
|
+
|
85
|
+
<b>John Wood</b>: John currently builds and tests the Mac OS X version of the
|
86
|
+
library.
|
87
|
+
|
88
|
+
<b>Art Federov</b>: Art provided input on handling and testing character sets.
|
89
|
+
|
90
|
+
---
|
91
|
+
|
92
|
+
== Installation & Usage
|
93
|
+
|
94
|
+
The library is provided as a gem and built for use with Ruby 1.8+. Testing
|
95
|
+
against an earlier release of Ruby has not been performed. Installation requires
|
96
|
+
the Ruby Gems package to be installed. Assuming that these installation criteria
|
97
|
+
have been met the library can be installed on Windows by executing a command
|
98
|
+
such as the following...
|
99
|
+
|
100
|
+
gem install fireruby-0.4.1-mswin32.gem
|
101
|
+
|
102
|
+
On the Mac OS X platform you may require super user privilege if your Ruby is
|
103
|
+
installed to the default location (i.e. /usr/local/lib). In this case you can
|
104
|
+
use the sudo command to make the installation like this...
|
105
|
+
|
106
|
+
sudo gem install fireruby-0.4.1-powerpc-darwin.gem
|
107
|
+
|
108
|
+
Once the gem installation is complete the FireRuby functionality can be accessed
|
109
|
+
in code with the usual gem style requires...
|
110
|
+
|
111
|
+
require 'rubygems'
|
112
|
+
require 'fireruby'
|
113
|
+
|
114
|
+
=== Build Details
|
115
|
+
|
116
|
+
The FireRuby library is a Ruby extension written in C. The avoid build issues
|
117
|
+
binary versions are provided for a number of platforms, including...
|
118
|
+
|
119
|
+
- Windows: Built against a version of Ruby installed using the one-click
|
120
|
+
installer and using the freely available Microsoft development tools. This
|
121
|
+
version was compiled against version 1.5.2 of Firebird.
|
122
|
+
|
123
|
+
- Linux: Built on Ubuntu Linux (Breezy Badger) using a version of Ruby 1.8.2
|
124
|
+
installed via the Synaptic package manager. This package manager was also
|
125
|
+
used to make an installation of Firebird.
|
126
|
+
|
127
|
+
- Mac OS X: Build on version 10.4.3 of OS X against the 1.8.2 version of Ruby
|
128
|
+
that comes with the operating system. A framework installation of Firebird
|
129
|
+
version 1.5.1 was used to make the build.
|
130
|
+
|
131
|
+
Its possible to try and build the library on other platforms so I'll provide a
|
132
|
+
few details as to how to go about doing this. The first step is to download the
|
133
|
+
CVS tar ball from the Ruby Forge site and expand it into a local directory. This
|
134
|
+
will create a directory called fireruby. Change into this directory and then
|
135
|
+
into the fireruby/src subdirectory.
|
136
|
+
|
137
|
+
This directory contains a file called extconf.rb that is used to create the
|
138
|
+
make file used to build the library. The make file is created by executing this
|
139
|
+
file but before you do there are a number of parameters that you should be
|
140
|
+
aware of. The main one of these is --with-firebird-dir. This parameter is used
|
141
|
+
to indicate the whereabouts of the Firebird headers and libraries. The following
|
142
|
+
is an example of how this might be used...
|
143
|
+
|
144
|
+
ruby extconf.rb --with-firebird-dir=/usr/local/firebird
|
145
|
+
|
146
|
+
You may need to customise the path for your own Firebird installation. The path
|
147
|
+
specified should be a directory that contains subdirectories called 'lib' and
|
148
|
+
'include'. The lib subdirectory should contain the fbclient shared library and
|
149
|
+
include should contain the ibase.h header file.
|
150
|
+
|
151
|
+
A note for Windows users. The library requires the free Microsoft C++ compiler,
|
152
|
+
the Windows SDK, the .NET SDK and nmake to build. If you have all of these
|
153
|
+
and Firebird installed to default locations then you can create a make file
|
154
|
+
using the mkmf.bat batch file in the src directory.
|
155
|
+
|
156
|
+
Once you have the make file you can attempt a library build using either make
|
157
|
+
(on Unix/Linux) or nmake (on Windows). If it builds successfully you can move
|
158
|
+
on to creating a gem file for installation. To do this, change into the ../gem
|
159
|
+
directory. In this directory you can do the following (on Windows)...
|
160
|
+
|
161
|
+
make_gem
|
162
|
+
|
163
|
+
...or the following (on Unix/Linux)...
|
164
|
+
|
165
|
+
ruby make_gem.rb
|
166
|
+
|
167
|
+
This will create the gem file in the main fireruby directory. Install this and
|
168
|
+
execute the unit tests to check whether you're version is working.
|
169
|
+
|
170
|
+
=== So How Do I Use It?
|
171
|
+
|
172
|
+
This section will provide some examples of usage for the the FireRuby classes.
|
173
|
+
Throughout the code the following set of assumptions are made.
|
174
|
+
|
175
|
+
- The user name and password that will be employed to attach to the database
|
176
|
+
are 'sysdba' and 'masterkey' respectively (the Firebird defaults).
|
177
|
+
|
178
|
+
- The databases attached to will all be local (i.e. they will all reside on the
|
179
|
+
same machine) as the test code.
|
180
|
+
|
181
|
+
A database, from the Firebird perspective, is made up of one or more files. From
|
182
|
+
a FireRuby perspective a user interaction with a database starts through the
|
183
|
+
Database class. This class provides facilities that allow for creating, dropping
|
184
|
+
and connecting to database instances. For example, to obtain a connection to a
|
185
|
+
database you would use something like the following...
|
186
|
+
|
187
|
+
require 'rubygems'
|
188
|
+
require 'fireruby'
|
189
|
+
|
190
|
+
include FireRuby
|
191
|
+
|
192
|
+
db = Database.new('./test.fdb')
|
193
|
+
c = db.connect('sysdba', 'masterkey')
|
194
|
+
|
195
|
+
This example starts by requiring the necessary files and including the FireRuby
|
196
|
+
module locally - later examples will not detail these lines but they are always
|
197
|
+
required to use the FireRuby code.
|
198
|
+
|
199
|
+
The first line of code after the include creates a new database object. This
|
200
|
+
process does not actually create the database file (see the Database#create
|
201
|
+
method API documentation if that is what you want to do), it simple creates an
|
202
|
+
abstract reference to a database. In creating the Database object we had to
|
203
|
+
provide a database specification string which identifies the database we want to
|
204
|
+
access. In this case we are specifying a database in the current working
|
205
|
+
directory called 'test.fdb'. See the Firebird documentation for details on the
|
206
|
+
structure of more complex database specifications.
|
207
|
+
|
208
|
+
The last line of code in the example given above opens a connection to the
|
209
|
+
database. In doing this we had to provide two parameters, the database user
|
210
|
+
name and password. These are required to gain access to the database.
|
211
|
+
|
212
|
+
A connection represents a conduit to a database and obtaining a connection is a
|
213
|
+
prerequisite to working with the database. The FireRuby library support having
|
214
|
+
multiple connections, to one or more databases, using one or more users, active
|
215
|
+
simultaneously. FireRuby represents a database connection through objects of the
|
216
|
+
Connection class. This class provides functionality to determine the current
|
217
|
+
state a database connection (open or closed) and for closing the connection.
|
218
|
+
Connections take up resources, both locally and on the database server and
|
219
|
+
should be explicitly closed when they are no longer required.
|
220
|
+
|
221
|
+
The connection class also provides a set of conveniences methods to allow for
|
222
|
+
the execution of SQL against a database. These methods, execute_immediate and
|
223
|
+
execute, represently two slightly different approaches to executing SQL against
|
224
|
+
the database. Refer to the API documentation for more information.
|
225
|
+
|
226
|
+
An advantage of using a relational database management system like Firebird is
|
227
|
+
that it provides transactions. A transaction represents a block of work that is
|
228
|
+
either all completed successful or none of it is applied. From the perspective
|
229
|
+
of the database this means that a series of steps that make changes to the
|
230
|
+
tables in the database can be wrapped in a transaction to insure that they
|
231
|
+
either all complete or that none of the changes are applied.
|
232
|
+
|
233
|
+
The FireRuby library represents a database transaction through instances of the
|
234
|
+
Transaction class. There are two ways of obtaining a Transaction using the
|
235
|
+
library, both requiring you to have an open database connection. The first way
|
236
|
+
is to construct a new Transaction object like so...
|
237
|
+
|
238
|
+
tx = Transaction.new(connection)
|
239
|
+
|
240
|
+
The Transaction constructor takes a single parameter which must be either a
|
241
|
+
Connection object or an array of Connection objects. If you pass an array of
|
242
|
+
Connection objects to this constructor then the Transaction created will apply
|
243
|
+
across all of the databases that the connections refer to, allowing you to
|
244
|
+
have transactional control of work that must utilise more than one database. The
|
245
|
+
second way to obtain a transaction is to simply request one from a Connection
|
246
|
+
object, like so.
|
247
|
+
|
248
|
+
tx = connection.start_transaction
|
249
|
+
|
250
|
+
In this case the transaction will only ever apply to one database, the one that
|
251
|
+
the connection relates to. This method also accepts a block, taking a single
|
252
|
+
parameter. The parameter passed to the block will be the transaction created.
|
253
|
+
In this case the lifetime of the transaction is delimited by the block. If the
|
254
|
+
block completes successfully then the work of the transaction will be committed
|
255
|
+
to the database. If the block raises an exception then the transactional work
|
256
|
+
will be rolled back.
|
257
|
+
|
258
|
+
When the block of work associated with a transaction is complete the user must
|
259
|
+
instruct the system to either apply the changes implemented by the work or to
|
260
|
+
discard them. This can be done by calling the commit or rollback methods of the
|
261
|
+
Transaction class respectively. Once a transaction has been committed or rolled
|
262
|
+
back it can no longer be used and should be discarded. Note that attempts to
|
263
|
+
close a connection that has an active transaction against it will fail, so one
|
264
|
+
of the commit or rollback methods should be explictly called in code. The
|
265
|
+
block technique detailed above helps protect against the failure to do this and
|
266
|
+
is a useful technique.
|
267
|
+
|
268
|
+
The Transaction object provides a number of other informational and utility
|
269
|
+
methods. Check the API documentation for this class for more information.
|
270
|
+
|
271
|
+
So we've looked at connections and transactions, but how do we actually do
|
272
|
+
something practical with the database. Well there are a number of possible
|
273
|
+
approaches that we can take to this. Both the Connection and Transaction classes
|
274
|
+
have convenience method for the execution of SQL statements and these are useful
|
275
|
+
for quick SQL. Where you want something that you can repeatedly reuse and,
|
276
|
+
optionally, pass parameters to then you need the Statement class.
|
277
|
+
|
278
|
+
The Statement class represents a SQL statement that has been validated and
|
279
|
+
prepared for execution. Here's an example of creating a SQL statement...
|
280
|
+
|
281
|
+
s = Statement.new(cxn, tx, 'SELECT * FROM MY_TABLE', 3)
|
282
|
+
|
283
|
+
In this example we have created a Statement object that wraps a SQL select from
|
284
|
+
a table called MY_TABLE. The first parameter to the constructor is a Connection
|
285
|
+
object and the second is a Transaction, both mandatory. You may be thinking
|
286
|
+
'why do I need a transaction here, I'm not changing anything?'. This is true
|
287
|
+
(well sort of) but it's a requirement of the underlying database system. This
|
288
|
+
is also the case for the final parameter to the constructor. The value 3 is
|
289
|
+
the SQL dialect to be used with the Statement. This exists for reason arising
|
290
|
+
from the move from closed source Interbase to open source Firebird. The
|
291
|
+
parameter should be given a value of between 1 and 3. If you're not sure what
|
292
|
+
this is and you're only using Firebird it's probably safe to use a value of
|
293
|
+
3 here. Other values are for backward compatibility. Consult the Firebird and
|
294
|
+
Interbase documentation for more details.
|
295
|
+
|
296
|
+
Anyway, now that we have our Statement how do we use it? Well, the answer is
|
297
|
+
that we call once of the Statement objects execute methods. The one to be called
|
298
|
+
depends on whether the Statement requires parameters or not. What are parameters
|
299
|
+
you ask? Well, look at the following...
|
300
|
+
|
301
|
+
s = Statement.new(cxn, tx, 'SELECT * FROM MY_TABLE WHERE MYID = ?', 3)
|
302
|
+
|
303
|
+
Note that the SQL select for this Statement contains a '?'. This is a position
|
304
|
+
holder for a value that the statement expects to be provided later. A Statement
|
305
|
+
that wraps such a piece of SQL must be provided with the necessary parameters
|
306
|
+
to execute properly. Where a Statement object represents SQL that requires a
|
307
|
+
parameter then the execute_for method must be called, like this...
|
308
|
+
|
309
|
+
s.execute_for([25])
|
310
|
+
|
311
|
+
This code executes the SQL substituting the parameters from the array of data
|
312
|
+
passed to the function call. If a Statement object represents SQL that does not
|
313
|
+
require parameter values a call to the execute method will suffice, such as the
|
314
|
+
following...
|
315
|
+
|
316
|
+
s.execute
|
317
|
+
|
318
|
+
The execute methods for the Statement class, as with all of the execute methods
|
319
|
+
for the FireRuby library, have three potential return values. They will either
|
320
|
+
return an Integer, a ResultSet object or nil. A ResultSet object will only be
|
321
|
+
returned for SQL statements that constitute a query, irrespective of whether
|
322
|
+
that query returns any data. For all other SQL statements (inserts, updates and
|
323
|
+
deletes) the execute method will return a count of the number of rows affected
|
324
|
+
by the statement execution. For any other SQL statements the various execute
|
325
|
+
methods will return nil.
|
326
|
+
|
327
|
+
A ResultSet object represents a handle by which the data retrieved for a SQL
|
328
|
+
query can be accessed. While it's possible to obtain a ResultSet from one of the
|
329
|
+
execute methods on the Connection, Transaction or Statement classes it is more
|
330
|
+
efficient to create one directly. The constructor for the ResultSet class
|
331
|
+
accepts the same arguments as the constructor for the Statement class but will
|
332
|
+
throw an exception if the SQL statement specified is not a query.
|
333
|
+
|
334
|
+
Once we have obtained a ResultSet we can extract the rows of data for a query
|
335
|
+
from it. To fetch a row of data from a ResultSet object you call the fetch
|
336
|
+
method, like the following...
|
337
|
+
|
338
|
+
row = r.fetch
|
339
|
+
|
340
|
+
This fetches a single row of data for a query represented as a Row object (which
|
341
|
+
will be covered shortly). The ResultSet class also provides for iteration across
|
342
|
+
the contents of a result set by providing an each method. The block to the each
|
343
|
+
method will be passed the data for the ResultSet, a row at a time.
|
344
|
+
|
345
|
+
It should be noted that both the Statement and ResultSet objects hold resources
|
346
|
+
while they are active. They both possess close methods and these should be
|
347
|
+
explicitly called to release the associated resources. The exception to this
|
348
|
+
rule is for ResultSets. If you select all of the rows from a ResultSet then the
|
349
|
+
resources for the ResultSet are automatically released. It is still safe to call
|
350
|
+
close on such a ResultSet as this will not cause errors.
|
351
|
+
|
352
|
+
Okay, so you've gotten a row of data in the form of a Row object from your
|
353
|
+
ResultSet, how do we get the data out of it? Well, there are a number of ways
|
354
|
+
of doing this. You can treat the Row object like an array and dereference the
|
355
|
+
columns of data within the row like this...
|
356
|
+
|
357
|
+
value = row[1]
|
358
|
+
|
359
|
+
The index specified to the array dereference operator specifies the column that
|
360
|
+
you want the data for. Column indices start at 0. Alternatively you can treat
|
361
|
+
the Row object like a read only Hash object and use the column name to access
|
362
|
+
the data, like this...
|
363
|
+
|
364
|
+
value = row['MYID']
|
365
|
+
|
366
|
+
This is beneficial as it frees you from the constraint of knowing the ordering
|
367
|
+
of the columns within the row. For more information of the Row class please
|
368
|
+
consult the API documentation.
|
369
|
+
|
370
|
+
That covers the bulk of the SQL classes provided by the FireRuby library. The
|
371
|
+
two which haven't been touched upon are the Generator class and the Blob class.
|
372
|
+
|
373
|
+
The Generator class is a wrapper around the Firebird generator facility. A
|
374
|
+
generator, also known as a sequence, provides a means of creating a list of
|
375
|
+
numeric values in a way that is guaranteed to be thread and process safe. Used
|
376
|
+
properly generators can be employed to create unique sequences that make perfect
|
377
|
+
table keys. Consult the API documentation for more details on the Generator
|
378
|
+
class.
|
379
|
+
|
380
|
+
The Blob class is returned as part of the Row object data obtained from a
|
381
|
+
ResultSet. The class wraps the concept of a binary large object stored in the
|
382
|
+
database. Consult the API documentation for further information.
|
383
|
+
|
384
|
+
=== Errors
|
385
|
+
|
386
|
+
Whenever a problem occurs within a FireRuby library class then it is likely that
|
387
|
+
a FireRubyException will be thrown. The FireRubyException class is the error
|
388
|
+
class used by the FireRuby library whenever it hits trouble. The class provides
|
389
|
+
a means of finding out a little more about what exactly has gone wrong. Again,
|
390
|
+
consult the API documentation for more details.
|
391
|
+
|
392
|
+
=== Firebird Service Manager
|
393
|
+
|
394
|
+
The FireRuby library provides a set of class that provide for an interaction
|
395
|
+
with the Firebird service manager. This interaction allows for the execution of
|
396
|
+
tasks, such as the backing up of a database, on the database server. To execute
|
397
|
+
such tasks against the service manager for a Firebird instance you first need
|
398
|
+
to obtain a ServiceManager class instance. This can be done as follows...
|
399
|
+
|
400
|
+
sm = ServiceManager.new('localhost')
|
401
|
+
|
402
|
+
The constructor for the ServiceManager class takes a single parameter that is
|
403
|
+
the host name of the server running the Firebird instance. In the example above
|
404
|
+
this would be a local machine but could be any machine that can be reached over
|
405
|
+
the network (NOTE: although Firebird supports a number of underlying transport
|
406
|
+
protocols in accessing a service manager currently only TCP/IP is supported for
|
407
|
+
the FireRuby library).
|
408
|
+
|
409
|
+
The next step in executing service manager tasks involves connecting your
|
410
|
+
ServiceManager object to the service manager for a Firebird instance. To do this
|
411
|
+
you must supply a user name and password. The user name and password used must
|
412
|
+
be a user that exists on the Firebird instance. The user you connect as can
|
413
|
+
affect the access to services that you receive. For example, to connect as the
|
414
|
+
database administrator you might do the following...
|
415
|
+
|
416
|
+
sm.connect('sysdba', 'masterkey')
|
417
|
+
|
418
|
+
Assuming that this succeeds you are now ready to execute tasks through your
|
419
|
+
ServiceManager object. Within the FireRuby library individual task are broken
|
420
|
+
out into separate classes. For this release (0.4.1) there are four task classes
|
421
|
+
provided in the library - Backup, Restore, AddUser and RemoveUser. I think the
|
422
|
+
class names are relatively self explanatory but if you want more information
|
423
|
+
consult the API documentation for a class.
|
424
|
+
|
425
|
+
To use the task classes you construct a class instance, configure it as you may
|
426
|
+
need and then execute it. Here's an example of going through this procedure to
|
427
|
+
create a database backup...
|
428
|
+
|
429
|
+
b = Backup.new('c:\database\work.fdb', 'c:\temp\work.bak')
|
430
|
+
b.metadata_only = true
|
431
|
+
b.execute(sm)
|
432
|
+
|
433
|
+
The first list creates the new Backup object. The first parameter passed to this
|
434
|
+
call is the path and name of the primary file of the database to be backed up
|
435
|
+
(NOTE: All paths are relative to the database server). The second parameter is
|
436
|
+
the path and name of the database backup file to be created. The second line
|
437
|
+
sets an attribute on the class to indicate that only the metadata (i.e. it's
|
438
|
+
schema but not it's data) for the specified database should be included in the
|
439
|
+
backup. The final line begins the execution of the backup task on the database
|
440
|
+
server. This will block until completion.
|
441
|
+
|
442
|
+
Its also possible to execute a batch of tasks against a service manager. To do
|
443
|
+
this you would accumulate the tasks to be executed and then pass them all at the
|
444
|
+
same time to the ServiceManager#execute method, like so...
|
445
|
+
|
446
|
+
t = Array.new
|
447
|
+
t.push(Backup.new('c:\database\work.fdb', 'c:\temp\work.bak'))
|
448
|
+
...
|
449
|
+
# Create more tasks here and add them to the array.
|
450
|
+
|
451
|
+
sm.execute(*t)
|
452
|
+
|
453
|
+
The tasks will be executed in the order they are specified to the ServiceManager
|
454
|
+
object. For the example above this would mean in the order they were added to
|
455
|
+
the array. For more details on the ServiceManager class and the various task
|
456
|
+
classes please consult the API documentation.
|