fireruby 0.2.2-i586-linux
Sign up to get free protection for your applications and to get access to all the features.
- data/doc/README +289 -0
- data/doc/license.txt +411 -0
- data/examples/example01.rb +60 -0
- data/lib/fireruby.bundle +0 -0
- data/lib/fireruby.so +0 -0
- data/lib/mkdoc +1 -0
- data/lib/src.rb +879 -0
- data/test/ConnectionTest.rb +92 -0
- data/test/DDLTest.rb +50 -0
- data/test/DatabaseTest.rb +81 -0
- data/test/GeneratorTest.rb +48 -0
- data/test/ResultSetTest.rb +97 -0
- data/test/RowTest.rb +49 -0
- data/test/SQLTest.rb +171 -0
- data/test/StatementTest.rb +124 -0
- data/test/TestSetup.rb +10 -0
- data/test/TransactionTest.rb +108 -0
- data/test/UnitTest.rb +11 -0
- metadata +58 -0
data/doc/README
ADDED
@@ -0,0 +1,289 @@
|
|
1
|
+
== FireRuby Version 0.2.1
|
2
|
+
This is a bug fix release for version 0.2.0 of the FireRuby library. FireRuby is
|
3
|
+
an extension to the Ruby language that provides access to the functionality of
|
4
|
+
the Firebird relational database management system.
|
5
|
+
|
6
|
+
== Enhancements & Alterations
|
7
|
+
|
8
|
+
No new functionality added for this release.
|
9
|
+
|
10
|
+
== Bug Fixes
|
11
|
+
|
12
|
+
- Fixed an intermittent bug that was causing an access violation when the Ruby
|
13
|
+
interpreter attempted to clean up at exited. The access violation was
|
14
|
+
occurring in a Firebird function call so I'm not exactly sure why it was
|
15
|
+
happening. The code has been restructured to bypass the issue.
|
16
|
+
|
17
|
+
- Fixed a bug in the code for the Generator object that was leaving an active
|
18
|
+
transaction lying around whenever an exception occurred in a call to fetch a
|
19
|
+
value from the Generator.
|
20
|
+
|
21
|
+
- Fixed a buffer overrun bug were the size of an input string was being used
|
22
|
+
to determine values written rather than the size of an output field.
|
23
|
+
|
24
|
+
== Issues
|
25
|
+
|
26
|
+
Nothing is perfect so this section outlines those issues that are known to
|
27
|
+
exist as of this release.
|
28
|
+
|
29
|
+
- The library currently does not support array columns. This may be implemented
|
30
|
+
for a later release depending on demand.
|
31
|
+
|
32
|
+
- There is an issue with the use of anonymous transactions inside of a block
|
33
|
+
for the Database#connect method. An attempt is made to close the connection
|
34
|
+
when the block exits. If, within the block, there is a call to the
|
35
|
+
Connection#execute_immediate method that generates a result set and,
|
36
|
+
subsequently, an exception is raised the anonymous transaction used in the
|
37
|
+
execute_immediate will be unavailable for closure. This will, in turn,
|
38
|
+
make it impossible to close the connection, resulting in an exception. As
|
39
|
+
a work around, don't use anonymous transactions for queries.
|
40
|
+
|
41
|
+
== Installation & Usage
|
42
|
+
|
43
|
+
The library is provided as a gem and built for use with Ruby 1.8+. Testing
|
44
|
+
against an earlier release of Ruby has not been performed. Installation requires
|
45
|
+
the Ruby Gems package to be installed. Assuming that these installation criteria
|
46
|
+
have been met the library can be installed on Windows by executing a command
|
47
|
+
such as the following...
|
48
|
+
|
49
|
+
gem install fireruby-0.2.0-mswin32.gem
|
50
|
+
|
51
|
+
On the Mac OS X platform you may require super user privilege if your Ruby is
|
52
|
+
installed to the default location (i.e. /usr/local/lib). In this case you can
|
53
|
+
use the sudo command to make the installation like this...
|
54
|
+
|
55
|
+
sudo gem install fireruby-0.2.0-powerpc-darwin.gem
|
56
|
+
|
57
|
+
Once the gem installation is complete the FireRuby functionality can be accessed
|
58
|
+
in code with the usual gem style requires...
|
59
|
+
|
60
|
+
require 'rubygems'
|
61
|
+
require_gem 'fireruby'
|
62
|
+
|
63
|
+
== Build Details
|
64
|
+
|
65
|
+
The FireRuby library is an extension of the Ruby language written in C. For Mac
|
66
|
+
OS X the library was built against Firebird installed as a framework, version
|
67
|
+
1.5.1, and with Ruby version 1.8.2. For the Windows platform the library was
|
68
|
+
built against a Ruby installation created using the one-click installer, version
|
69
|
+
1.8.2. The Windows build was created using the freely available Microsoft
|
70
|
+
compilers and SDKs and built against a standard installation of Firebird,
|
71
|
+
version 1.5.2.
|
72
|
+
|
73
|
+
== So How Do I Use It?
|
74
|
+
|
75
|
+
This section will provide some examples of usage for the the FireRuby classes.
|
76
|
+
Throughout the code the following set of assumptions are made.
|
77
|
+
|
78
|
+
- The user name and password that will be employed to attach to the database
|
79
|
+
are 'sysdba' and 'masterkey' respectively (the Firebird defaults).
|
80
|
+
|
81
|
+
- The databases attached to will all be local (i.e. they will all reside on the
|
82
|
+
same machine) as the test code.
|
83
|
+
|
84
|
+
A database, from the Firebird perspective, is made up of one or more files. From
|
85
|
+
a FireRuby perspective a user interaction with a database starts through the
|
86
|
+
Database class. This class provides facilities that allow for creating, dropping
|
87
|
+
and connecting to database instances. For example, to obtain a connection to a
|
88
|
+
database you would use something like the following...
|
89
|
+
|
90
|
+
require 'rubygems'
|
91
|
+
require_gem 'fireruby'
|
92
|
+
|
93
|
+
include FireRuby
|
94
|
+
|
95
|
+
db = Database.new('./test.fdb')
|
96
|
+
c = db.connect('sysdba', 'masterkey')
|
97
|
+
|
98
|
+
This example starts by requiring the necessary files and including the FireRuby
|
99
|
+
module locally - later examples will not detail these lines but they are always
|
100
|
+
required to use the FireRuby code.
|
101
|
+
|
102
|
+
The first line of code after the include creates a new database object. This
|
103
|
+
process does not actually create the database file (see the Database#create
|
104
|
+
method API documentation if that is what you want to do), it simple creates an
|
105
|
+
abstract reference to a database. In creating the Database object we had to
|
106
|
+
provide a database specification string which identifies the database we want to
|
107
|
+
access. In this case we are specifying a database in the current working
|
108
|
+
directory called 'test.fdb'. See the Firebird documentation for details on the
|
109
|
+
structure of more complex database specifications.
|
110
|
+
|
111
|
+
The last line of code in the example given above opens a connection to the
|
112
|
+
database. In doing this we had to provide two parameters, the database user
|
113
|
+
name and password. These are required to gain access to the database.
|
114
|
+
|
115
|
+
A connection represents a conduit to a database and obtaining a connection is a
|
116
|
+
prerequisite to working with the database. The FireRuby library support having
|
117
|
+
multiple connections, to one or more databases, using one or more users, active
|
118
|
+
simultaneously. FireRuby represents a database connection through objects of the
|
119
|
+
Connection class. This class provides functionality to determine the current
|
120
|
+
state a database connection (open or closed) and for closing the connection.
|
121
|
+
Connections take up resources, both locally and on the database server and
|
122
|
+
should be explicitly closed when they are no longer required.
|
123
|
+
|
124
|
+
The connection class also provides a set of conveniences methods to allow for
|
125
|
+
the execution of SQL against a database. These methods, execute_immediate and
|
126
|
+
execute, represently two slightly different approaches to executing SQL against
|
127
|
+
the database. Refer to the API documentation for more information.
|
128
|
+
|
129
|
+
An advantage of using a relational database management system like Firebird is
|
130
|
+
that it provides transactions. A transaction represents a block of work that is
|
131
|
+
either all completed successful or none of it is applied. From the perspective
|
132
|
+
of the database this means that a series of steps that make changes to the
|
133
|
+
tables in the database can be wrapped in a transaction to insure that they
|
134
|
+
either all complete or that none of the changes are applied.
|
135
|
+
|
136
|
+
The FireRuby library represents a database transaction through instances of the
|
137
|
+
Transaction class. There are two ways of obtaining a Transaction using the
|
138
|
+
library, both requiring you to have an open database connection. The first way
|
139
|
+
is to construct a new Transaction object like so...
|
140
|
+
|
141
|
+
tx = Transaction.new(connection)
|
142
|
+
|
143
|
+
The Transaction constructor takes a single parameter which must be either a
|
144
|
+
Connection object or an array of Connection objects. If you pass an array of
|
145
|
+
Connection objects to this constructor then the Transaction created will apply
|
146
|
+
across all of the databases that the connections refer to, allowing you to
|
147
|
+
have transactional control of work that must utilise more than one database. The
|
148
|
+
second way to obtain a transaction is to simply request one from a Connection
|
149
|
+
object, like so.
|
150
|
+
|
151
|
+
tx = connection.start_transaction
|
152
|
+
|
153
|
+
In this case the transaction will only ever apply to one database, the one that
|
154
|
+
the connection relates to. This method also accepts a block, taking a single
|
155
|
+
parameter. The parameter passed to the block will be the transaction created.
|
156
|
+
In this case the lifetime of the transaction is delimited by the block. If the
|
157
|
+
block completes successfully then the work of the transaction will be committed
|
158
|
+
to the database. If the block raises an exception then the transactional work
|
159
|
+
will be rolled back.
|
160
|
+
|
161
|
+
When the block of work associated with a transaction is complete the user must
|
162
|
+
instruct the system to either apply the changes implemented by the work or to
|
163
|
+
discard them. This can be done by calling the commit or rollback methods of the
|
164
|
+
Transaction class respectively. Once a transaction has been committed or rolled
|
165
|
+
back it can no longer be used and should be discarded. Note that attempts to
|
166
|
+
close a connection that has an active transaction against it will fail, so one
|
167
|
+
of the commit or rollback methods should be explictly called in code. The
|
168
|
+
block technique detailed above helps protect against the failure to do this and
|
169
|
+
is a useful technique.
|
170
|
+
|
171
|
+
The Transaction object provides a number of other informational and utility
|
172
|
+
methods. Check the API documentation for this class for more information.
|
173
|
+
|
174
|
+
So we've looked at connections and transactions, but how do we actually do
|
175
|
+
something practical with the database. Well there are a number of possible
|
176
|
+
approaches that we can take to this. Both the Connection and Transaction classes
|
177
|
+
have convenience method for the execution of SQL statements and these are useful
|
178
|
+
for quick SQL. Where you want something that you can repeatedly reuse and,
|
179
|
+
optionally, pass parameters to then you need the Statement class.
|
180
|
+
|
181
|
+
The Statement class represents a SQL statement that has been validated and
|
182
|
+
prepared for execution. Here's an example of creating a SQL statement...
|
183
|
+
|
184
|
+
s = Statement.new(cxn, tx, 'SELECT * FROM MY_TABLE', 3)
|
185
|
+
|
186
|
+
In this example we have created a Statement object that wraps a SQL select from
|
187
|
+
a table called MY_TABLE. The first parameter to the constructor is a Connection
|
188
|
+
object and the second is a Transaction, both mandatory. You may be thinking
|
189
|
+
'why do I need a transaction here, I'm not changing anything?'. This is true
|
190
|
+
(well sort of) but it's a requirement of the underlying database system. This
|
191
|
+
is also the case for the final parameter to the constructor. The value 3 is
|
192
|
+
the SQL dialect to be used with the Statement. This exists for reason arising
|
193
|
+
from the move from closed source Interbase to open source Firebird. The
|
194
|
+
parameter should be given a value of between 1 and 3. If you're not sure what
|
195
|
+
this is and you're only using Firebird it's probably safe to use a value of
|
196
|
+
3 here. Other values are for backward compatibility. Consult the Firebird and
|
197
|
+
Interbase documentation for more details.
|
198
|
+
|
199
|
+
Anyway, now that we have our Statement how do we use it. Well, there are two
|
200
|
+
approaches to using the Statement object. For statements like the one used
|
201
|
+
above, queries that take no parameters, you can use the Statement object to
|
202
|
+
build a ResultSet object, like so...
|
203
|
+
|
204
|
+
r = ResultSet.new(s)
|
205
|
+
|
206
|
+
The ResultSet class will be covered in a little more detail below. The other
|
207
|
+
means by which a Statement can be used is to call one of it's execute methods.
|
208
|
+
The one to be called depends on whether the Statement requires parameters or
|
209
|
+
not. What are parameters you ask? Well, look at the following...
|
210
|
+
|
211
|
+
s = Statement.new(cxn, tx, 'SELECT * FROM MY_TABLE WHERE MYID = ?', 3)
|
212
|
+
|
213
|
+
Note that the SQL select for this Statement contains a '?'. This is a position
|
214
|
+
holder for a value that the statement expects to be provided later. A Statement
|
215
|
+
that wraps such a piece of SQL must be provided with the necessary parameters
|
216
|
+
to execute properly. Where a Statement object represents SQL that requires a
|
217
|
+
parameter then the execute_for method must be called, like this...
|
218
|
+
|
219
|
+
r = s.execute_for([25])
|
220
|
+
|
221
|
+
This code executes the SQL substituting the parameters from the array of data
|
222
|
+
passed to the function call. If a Statement object represents SQL that does not
|
223
|
+
require parameter values a call to the execute method will suffice, such as the
|
224
|
+
following...
|
225
|
+
|
226
|
+
r = s.execute
|
227
|
+
|
228
|
+
The execute methods for the Statement class, as with all of the execute methods
|
229
|
+
for the FireRuby library, have two potential return values. They will either
|
230
|
+
return nil or they will return a ResultSet object. A ResultSet object will only
|
231
|
+
be returned for SQL statements that constitute a query, irrespective of whether
|
232
|
+
that query returns any data. For all other SQL statements the various execute
|
233
|
+
method will return nil.
|
234
|
+
|
235
|
+
A ResultSet object represents a handle by which the data retrieved for a SQL
|
236
|
+
query can be accessed. To fetch a row of data from a ResultSet object you call
|
237
|
+
the fetch method, like the following...
|
238
|
+
|
239
|
+
row = r.fetch
|
240
|
+
|
241
|
+
This fetches a single row of data for a query represented as a Row object (which
|
242
|
+
will be covered shortly). The ResultSet class also provides for iteration across
|
243
|
+
the contents of a result set by providing an each method. The block to the each
|
244
|
+
method will be passed the data for the ResultSet, a row at a time.
|
245
|
+
|
246
|
+
It should be noted that both the Statement and ResultSet objects hold resources
|
247
|
+
while they are active. They both possess close methods and these should be
|
248
|
+
explicitly called to release the associated resources. The exception to this
|
249
|
+
rule is for ResultSets. If you select all of the rows from a ResultSet then the
|
250
|
+
resources for the ResultSet are automatically released. It is still safe to call
|
251
|
+
close on such a ResultSet as this will not cause errors.
|
252
|
+
|
253
|
+
Okay, so you've gotten a row of data in the form of a Row object from your
|
254
|
+
ResultSet, how do we get the data out of it? Well, there are a number of ways
|
255
|
+
of doing this. You can treat the Row object like an array and dereference the
|
256
|
+
columns of data within the row like this...
|
257
|
+
|
258
|
+
value = row[1]
|
259
|
+
|
260
|
+
The index specified to the array dereference operator specifies the column that
|
261
|
+
you want the data for. Column indices start at 0. Alternatively you can use the
|
262
|
+
column name to access the data, like this...
|
263
|
+
|
264
|
+
value = row['MYID']
|
265
|
+
|
266
|
+
This is beneficial as it frees you from the constraint of knowing the ordering
|
267
|
+
of the columns within the row. For more information of the Row class please
|
268
|
+
consult the API documentation.
|
269
|
+
|
270
|
+
Well that covers the bulk of the classes provided by the FireRuby library. The
|
271
|
+
three which haven't been touched upon are the Generator class, the Blob class
|
272
|
+
and the FireRubyException class.
|
273
|
+
|
274
|
+
The Generator class is a wrapper around the Firebird generator facility. A
|
275
|
+
generator, also known as a sequence, provides a means of creating a list of
|
276
|
+
numeric values in a way that is guaranteed to be thread and process safe. Used
|
277
|
+
properly generators can be employed to create unique sequences that make perfect
|
278
|
+
table keys. Consult the API documentation for more details on the Generator
|
279
|
+
class.
|
280
|
+
|
281
|
+
The Blob class is returned as part of the Row object data obtained from a
|
282
|
+
ResultSet. The class wraps the concept of a binary large object stored in the
|
283
|
+
database. Consult the API documentation for further information.
|
284
|
+
|
285
|
+
The FireRubyException class is the error class used by the FireRuby library
|
286
|
+
whenever it hits trouble. If an exception is raised by the FireRuby code then
|
287
|
+
its extremely likely that it will be an instance of this class. The class
|
288
|
+
provides a means of finding out a little more about what exactly has gone
|
289
|
+
wrong. Again, consult the API documentation for more details.
|