sedna 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +18 -0
- data/README +35 -13
- data/Rakefile +3 -3
- data/ext/extconf.rb +4 -9
- data/ext/sedna.c +429 -118
- data/test/sedna_test.rb +447 -317
- metadata +2 -2
data/CHANGES
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
=== 0.4.0
|
2
|
+
|
3
|
+
* Released on January 4th, 2009.
|
4
|
+
* Added Sedna#reset, which closes the current connection and reconnects.
|
5
|
+
* Added Sedna#connected?, which returns whether or not the current connection
|
6
|
+
is still active.
|
7
|
+
* Sedna#transaction can now also be used without a block. Use the newly added
|
8
|
+
methods Sedna#commit and Sedna#rollback to finish such a declarative
|
9
|
+
transaction. Note that this style is not recommended if a transaction can
|
10
|
+
be wrapped in a block.
|
11
|
+
* Sedna.connect no longer blocks other threads in Ruby 1.9.1+. Use Sedna.blocking?
|
12
|
+
to discover if support for non-blocking behaviour is enabled.
|
13
|
+
* Strings in the result Array of Sedna#execute are now in UTF-8 encoding in
|
14
|
+
Ruby 1.9, rather than binary.
|
15
|
+
* Fully tested in Ruby 1.8.5+ (including the latest version, 1.9.1 RC1).
|
16
|
+
* Now also compiles with Ruby 1.9.0.x, but non-blocking behaviour is disabled
|
17
|
+
for these versions.
|
18
|
+
|
1
19
|
=== 0.3.0
|
2
20
|
|
3
21
|
* Released on December 21st, 2008.
|
data/README
CHANGED
@@ -16,7 +16,7 @@ at http://modis.ispras.ru/sedna
|
|
16
16
|
|
17
17
|
Author: Rolf Timmermans (r.timmermans <i>at</i> voormedia.com)
|
18
18
|
|
19
|
-
Copyright 2008 Voormedia B.V.
|
19
|
+
Copyright 2008, 2009 Voormedia B.V.
|
20
20
|
|
21
21
|
Licensed under the Apache License, Version 2.0 (the "License");
|
22
22
|
you may not use this file except in compliance with the License.
|
@@ -32,9 +32,8 @@ limitations under the License.
|
|
32
32
|
|
33
33
|
=== Current version
|
34
34
|
|
35
|
-
The current version of this library is 0.
|
36
|
-
|
37
|
-
all recent and previous changes, see CHANGES.
|
35
|
+
The current version of this library is 0.4.0. This release is a <b>beta version</b>.
|
36
|
+
For a complete overview all recent and previous changes, see CHANGES.
|
38
37
|
|
39
38
|
=== Requirements
|
40
39
|
|
@@ -43,8 +42,7 @@ header files of the C driver. They are shipped and installed as part of the bina
|
|
43
42
|
distribution of \Sedna. When installing, choose either <tt>/usr/local/sedna</tt> or
|
44
43
|
<tt>/opt/sedna</tt> as target locations.
|
45
44
|
|
46
|
-
The library has been tested with Ruby 1.8.5 and above, including Ruby 1.9.
|
47
|
-
(preview 2), but excluding Ruby 1.9.0.
|
45
|
+
The library has been tested with Ruby 1.8.5 and above, including Ruby 1.9.
|
48
46
|
|
49
47
|
=== Installation
|
50
48
|
|
@@ -69,7 +67,8 @@ using it.
|
|
69
67
|
|
70
68
|
To start querying a database, create a new connection with the Sedna.connect
|
71
69
|
method. When a block is given, the Sedna connection object will be returned
|
72
|
-
which can be used to execute database statements.
|
70
|
+
which can be used to execute database statements. See the documentation of the
|
71
|
+
Sedna class for more details.
|
73
72
|
|
74
73
|
connection_details = {
|
75
74
|
:database => "my_db",
|
@@ -77,13 +76,36 @@ which can be used to execute database statements.
|
|
77
76
|
:username => "SYSTEM",
|
78
77
|
:password => "MANAGER",
|
79
78
|
}
|
80
|
-
|
79
|
+
|
80
|
+
Sedna.connect connection_details do |sedna|
|
81
81
|
# Start querying the database.
|
82
|
-
sedna.execute
|
83
|
-
sedna.execute
|
84
|
-
sedna.execute
|
82
|
+
sedna.execute "create document 'my_doc'" #=> nil
|
83
|
+
sedna.execute "update insert <msg>Hello world!</msg> into doc('my_doc')" #=> nil
|
84
|
+
sedna.execute "doc('my_doc')/msg/text()" #=> ["Hello world!"]
|
85
85
|
# The connection is closed automatically for us.
|
86
86
|
end
|
87
87
|
|
88
|
-
|
89
|
-
|
88
|
+
Use Sedna#load_document to load a document into the database from a string or
|
89
|
+
file.
|
90
|
+
|
91
|
+
sedna.load_document "<msg>Hello world!</msg>", "my_doc", "my_collection"
|
92
|
+
sedna.execute "doc('my_doc', 'my_collection')/msg/text()" #=> ["Hello world!"]
|
93
|
+
|
94
|
+
File.open "document.xml" do |file|
|
95
|
+
sedna.load_document file, "my_doc2", "my_collection"
|
96
|
+
end
|
97
|
+
|
98
|
+
Use Sedna#transaction to wrap multiple database statements in a transaction.
|
99
|
+
This ensures that either all or none of these statements are executed. If
|
100
|
+
something goes wrong halfway, the previously executed statements that are part
|
101
|
+
of the transaction will be rolled back.
|
102
|
+
|
103
|
+
sedna.transaction do
|
104
|
+
amount = 100
|
105
|
+
sedna.execute "update replace $balance in doc('my_account')/balance
|
106
|
+
with <balance>{$balance - #{amount}}</balance>"
|
107
|
+
sedna.execute "update replace $balance in doc('your_account')/balance
|
108
|
+
with <balance>{$balance + #{amount}}</balance>"
|
109
|
+
# If the second statement fails, the first will be rolled back. Only if
|
110
|
+
# both statements succeed will the changes become permanent.
|
111
|
+
end
|
data/Rakefile
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2008 Voormedia B.V.
|
1
|
+
# Copyright 2008, 2009 Voormedia B.V.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -30,7 +30,7 @@ RDOC_FILES = FileList["[A-Z][A-Z]*", "ext/**/*.c"].to_a
|
|
30
30
|
task :default => [:rebuild, :test]
|
31
31
|
|
32
32
|
task :multi do
|
33
|
-
exec "
|
33
|
+
exec "multiruby -S rake"
|
34
34
|
end
|
35
35
|
|
36
36
|
desc "Build the Ruby extension"
|
@@ -57,7 +57,7 @@ end
|
|
57
57
|
|
58
58
|
gem_spec = Gem::Specification.new do |s|
|
59
59
|
s.name = "sedna"
|
60
|
-
s.version = "0.
|
60
|
+
s.version = "0.4.0"
|
61
61
|
|
62
62
|
s.summary = "Sedna XML DBMS client library."
|
63
63
|
s.description = %{Ruby extension that provides a client library for the Sedna XML DBMS, making use of the official C driver of the Sedna project.}
|
data/ext/extconf.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright 2008 Voormedia B.V.
|
1
|
+
# Copyright 2008, 2009 Voormedia B.V.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -68,13 +68,8 @@ passing the -fPIC option to gcc.
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
newer version of Ruby (1.9.1+).
|
75
|
-
==============================================================================
|
76
|
-
}
|
77
|
-
exit 5
|
78
|
-
end
|
71
|
+
have_func "rb_thread_blocking_region"
|
72
|
+
have_func "rb_mutex_synchronize"
|
73
|
+
have_func "rb_enc_str_buf_cat"
|
79
74
|
|
80
75
|
create_makefile "sedna"
|
data/ext/sedna.c
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright 2008 Voormedia B.V.
|
2
|
+
* Copyright 2008, 2009 Voormedia B.V.
|
3
3
|
*
|
4
4
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
5
5
|
* you may not use this file except in compliance with the License.
|
@@ -49,31 +49,73 @@
|
|
49
49
|
#define PROTO_TO_STRING(s) PROTO_STRINGIFY(s)
|
50
50
|
#define PROTOCOL_VERSION PROTO_TO_STRING(SE_CURRENT_SOCKET_PROTOCOL_VERSION_MAJOR) "." PROTO_TO_STRING(SE_CURRENT_SOCKET_PROTOCOL_VERSION_MINOR)
|
51
51
|
|
52
|
-
// Default connection arguments
|
52
|
+
// Default connection arguments.
|
53
53
|
#define DEFAULT_HOST "localhost"
|
54
|
-
#define
|
54
|
+
#define DEFAULT_DB "test"
|
55
55
|
#define DEFAULT_USER "SYSTEM"
|
56
|
-
#define
|
56
|
+
#define DEFAULT_PW "MANAGER"
|
57
|
+
|
58
|
+
// Instance variable names.
|
59
|
+
#define IV_HOST "@host"
|
60
|
+
#define IV_DB "@database"
|
61
|
+
#define IV_USER "@username"
|
62
|
+
#define IV_PW "@password"
|
63
|
+
#define IV_AUTOCOMMIT "@autocommit"
|
64
|
+
#define IV_MUTEX "@mutex"
|
57
65
|
|
58
66
|
// Define a shorthand for the common SednaConnection structure.
|
59
67
|
typedef struct SednaConnection SC;
|
60
68
|
|
61
|
-
|
62
|
-
|
63
|
-
|
69
|
+
// Define a struct for database queries.
|
70
|
+
struct SednaQuery {
|
71
|
+
void *conn;
|
72
|
+
void *query;
|
73
|
+
};
|
74
|
+
typedef struct SednaQuery SQ;
|
75
|
+
|
76
|
+
// Define a struct for database connection arguments.
|
77
|
+
struct SednaConnArgs {
|
78
|
+
void *conn;
|
79
|
+
void *host;
|
80
|
+
void *db;
|
81
|
+
void *user;
|
82
|
+
void *pw;
|
83
|
+
};
|
84
|
+
typedef struct SednaConnArgs SCA;
|
85
|
+
|
86
|
+
// Always create UTF-8 strings with STR_CAT, if supported (Ruby 1.9).
|
87
|
+
#ifdef HAVE_RB_ENC_STR_BUF_CAT
|
88
|
+
#ifndef RUBY_ENCODING_H
|
89
|
+
#include "ruby/encoding.h"
|
90
|
+
#endif
|
91
|
+
#define STR_CAT(str, buf, bytes) rb_enc_str_buf_cat(str, buf, bytes, rb_utf8_encoding())
|
92
|
+
#else
|
93
|
+
#define STR_CAT(str, buf, bytes) rb_str_buf_cat(str, buf, bytes)
|
94
|
+
#endif
|
64
95
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
typedef struct SednaQuery SQ;
|
96
|
+
// Define whether or not non-blocking behaviour will be built in.
|
97
|
+
#if defined(HAVE_RB_THREAD_BLOCKING_REGION) && defined(HAVE_RB_MUTEX_SYNCHRONIZE)
|
98
|
+
#define NON_BLOCKING 1
|
99
|
+
#define SEDNA_BLOCKING Qfalse
|
70
100
|
#else
|
71
101
|
#define SEDNA_BLOCKING Qtrue
|
72
102
|
#endif
|
73
103
|
|
104
|
+
// Define execute and connect functions.
|
105
|
+
#ifdef NON_BLOCKING
|
106
|
+
// Non-blocking variants for >= 1.9.
|
107
|
+
// Synchronize across threads using this instance and execute.
|
108
|
+
#define SEDNA_CONNECT(self, c) rb_mutex_synchronize(rb_iv_get(self, IV_MUTEX), (void*)sedna_non_blocking_connect, (VALUE)c);
|
109
|
+
#define SEDNA_EXECUTE(self, q) rb_mutex_synchronize(rb_iv_get(self, IV_MUTEX), (void*)sedna_non_blocking_execute, (VALUE)q);
|
110
|
+
#else
|
111
|
+
// Blocking variants for < 1.9.
|
112
|
+
#define SEDNA_CONNECT(self, c) sedna_blocking_connect(c);
|
113
|
+
#define SEDNA_EXECUTE(self, q) sedna_blocking_execute(q);
|
114
|
+
#endif
|
115
|
+
|
74
116
|
// Ruby classes.
|
75
117
|
static VALUE cSedna;
|
76
|
-
//static VALUE cSednaSet; //
|
118
|
+
//static VALUE cSednaSet; // Stick to Array for result sets.
|
77
119
|
static VALUE cSednaException;
|
78
120
|
static VALUE cSednaAuthError;
|
79
121
|
static VALUE cSednaConnError;
|
@@ -146,18 +188,44 @@ static void sedna_free(SC *conn)
|
|
146
188
|
static void sedna_mark(SC *conn)
|
147
189
|
{ /* Unused. */ }
|
148
190
|
|
149
|
-
|
150
|
-
static int
|
191
|
+
// Connect to the server.
|
192
|
+
static int sedna_blocking_connect(SCA *c)
|
151
193
|
{
|
152
|
-
return
|
194
|
+
return SEconnect(c->conn, c->host, c->db, c->user, c->pw);
|
153
195
|
}
|
154
196
|
|
155
|
-
|
197
|
+
#ifdef NON_BLOCKING
|
198
|
+
static int sedna_non_blocking_connect(SCA *c)
|
156
199
|
{
|
157
|
-
return rb_thread_blocking_region((void*)
|
200
|
+
return rb_thread_blocking_region((void*)sedna_blocking_connect, c, RUBY_UBF_IO, NULL);
|
158
201
|
}
|
159
202
|
#endif
|
160
203
|
|
204
|
+
static void sedna_connect(VALUE self, SCA *c)
|
205
|
+
{
|
206
|
+
int res = SEDNA_CONNECT(self, c);
|
207
|
+
if(res != SEDNA_SESSION_OPEN) {
|
208
|
+
// We have to set the connection status to closed explicitly here,
|
209
|
+
// because the GC routine sedna_free() will test for this status, but
|
210
|
+
// the socket is already closed by SEconnect(). If we do not change the
|
211
|
+
// status, sedna_free() will attempt to close the connection again by
|
212
|
+
// calling SEclose(), which will definitely lead to unpredictable
|
213
|
+
// results.
|
214
|
+
((SC*)c->conn)->isConnectionOk = SEDNA_CONNECTION_CLOSED;
|
215
|
+
sedna_err(c->conn, res);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
|
219
|
+
// Close the connection to the server.
|
220
|
+
static void sedna_close(SC *conn)
|
221
|
+
{
|
222
|
+
int res;
|
223
|
+
if(SEconnectionStatus(conn) != SEDNA_CONNECTION_CLOSED) {
|
224
|
+
res = SEclose(conn);
|
225
|
+
VERIFY_RES(SEDNA_SESSION_CLOSED, res, conn);
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
161
229
|
// Read one record completely and return it as a Ruby String object.
|
162
230
|
static VALUE sedna_read(SC *conn, int strip_n)
|
163
231
|
{
|
@@ -177,11 +245,11 @@ static VALUE sedna_read(SC *conn, int strip_n)
|
|
177
245
|
// except the first. Strip them! This a known issue in the
|
178
246
|
// network protocol and serialization mechanism.
|
179
247
|
// See: http://sourceforge.net/mailarchive/forum.php?thread_name=3034886f0812030132v3bbd8e2erd86480d3dc640664%40mail.gmail.com&forum_name=sedna-discussion
|
180
|
-
|
248
|
+
STR_CAT(str, buffer + 1, bytes_read - 1);
|
181
249
|
// Do not strip newlines from subsequent buffer reads.
|
182
250
|
strip_n = 0;
|
183
251
|
} else {
|
184
|
-
|
252
|
+
STR_CAT(str, buffer, bytes_read);
|
185
253
|
}
|
186
254
|
}
|
187
255
|
}
|
@@ -194,6 +262,7 @@ static VALUE sedna_read(SC *conn, int strip_n)
|
|
194
262
|
static VALUE sedna_get_results(SC *conn)
|
195
263
|
{
|
196
264
|
int res, strip_n = 0;
|
265
|
+
// Can be replaced with: rb_funcall(cSednaSet, rb_intern("new"), 0, NULL);
|
197
266
|
VALUE set = rb_ary_new();
|
198
267
|
|
199
268
|
while((res = SEnext(conn)) != SEDNA_RESULT_END) {
|
@@ -207,6 +276,18 @@ static VALUE sedna_get_results(SC *conn)
|
|
207
276
|
return set;
|
208
277
|
}
|
209
278
|
|
279
|
+
static int sedna_blocking_execute(SQ *q)
|
280
|
+
{
|
281
|
+
return SEexecute(q->conn, q->query);
|
282
|
+
}
|
283
|
+
|
284
|
+
#ifdef NON_BLOCKING
|
285
|
+
static int sedna_non_blocking_execute(SQ *q)
|
286
|
+
{
|
287
|
+
return rb_thread_blocking_region((void*)sedna_blocking_execute, q, RUBY_UBF_IO, NULL);
|
288
|
+
}
|
289
|
+
#endif
|
290
|
+
|
210
291
|
// Enable or disable autocommit.
|
211
292
|
static void sedna_autocommit(SC *conn, int value)
|
212
293
|
{
|
@@ -215,24 +296,73 @@ static void sedna_autocommit(SC *conn, int value)
|
|
215
296
|
}
|
216
297
|
|
217
298
|
// Begin a transaction.
|
218
|
-
static void
|
299
|
+
static void sedna_begin(SC *conn)
|
219
300
|
{
|
220
|
-
int res
|
301
|
+
int res;
|
302
|
+
|
303
|
+
// Disable autocommit mode.
|
304
|
+
SEDNA_AUTOCOMMIT_DISABLE(conn);
|
305
|
+
|
306
|
+
// Start the transaction.
|
307
|
+
res = SEbegin(conn);
|
221
308
|
VERIFY_RES(SEDNA_BEGIN_TRANSACTION_SUCCEEDED, res, conn);
|
222
309
|
}
|
223
310
|
|
224
311
|
// Commit a transaction.
|
225
312
|
static void sedna_tr_commit(SC *conn)
|
226
313
|
{
|
227
|
-
int res
|
228
|
-
|
314
|
+
int res;
|
315
|
+
|
316
|
+
if(SEtransactionStatus(conn) == SEDNA_TRANSACTION_ACTIVE) {
|
317
|
+
// Commit if a transaction was in progres.
|
318
|
+
res = SEcommit(conn);
|
319
|
+
VERIFY_RES(SEDNA_COMMIT_TRANSACTION_SUCCEEDED, res, conn);
|
320
|
+
} else {
|
321
|
+
// If there is no current transaction, raise an error.
|
322
|
+
rb_raise(cSednaTrnError, "No transaction in progress, cannot commit.");
|
323
|
+
}
|
324
|
+
}
|
325
|
+
|
326
|
+
// Commit a transaction and reset autocommit mode.
|
327
|
+
static void sedna_commit(SC *conn, VALUE self)
|
328
|
+
{
|
329
|
+
int status;
|
330
|
+
|
331
|
+
// Roll back.
|
332
|
+
rb_protect((void*)sedna_tr_commit, (VALUE)conn, &status);
|
333
|
+
|
334
|
+
// Turn autocommit back on if it was set.
|
335
|
+
SWITCH_SEDNA_AUTOCOMMIT(conn, rb_iv_get(self, IV_AUTOCOMMIT));
|
336
|
+
|
337
|
+
// Re-raise any exception.
|
338
|
+
if(status != 0) rb_jump_tag(status);
|
229
339
|
}
|
230
340
|
|
231
341
|
// Rollback a transaction.
|
232
342
|
static void sedna_tr_rollback(SC *conn)
|
233
343
|
{
|
234
|
-
int res
|
235
|
-
|
344
|
+
int res;
|
345
|
+
|
346
|
+
// Roll back if a transaction was in progress.
|
347
|
+
if(SEtransactionStatus(conn) == SEDNA_TRANSACTION_ACTIVE) {
|
348
|
+
res = SErollback(conn);
|
349
|
+
VERIFY_RES(SEDNA_ROLLBACK_TRANSACTION_SUCCEEDED, res, conn);
|
350
|
+
}
|
351
|
+
}
|
352
|
+
|
353
|
+
// Rollback a transaction and reset autocommit mode.
|
354
|
+
static void sedna_rollback(SC *conn, VALUE self)
|
355
|
+
{
|
356
|
+
int status;
|
357
|
+
|
358
|
+
// Roll back.
|
359
|
+
rb_protect((void*)sedna_tr_rollback, (VALUE)conn, &status);
|
360
|
+
|
361
|
+
// Turn autocommit back on if it was set.
|
362
|
+
SWITCH_SEDNA_AUTOCOMMIT(conn, rb_iv_get(self, IV_AUTOCOMMIT));
|
363
|
+
|
364
|
+
// Re-raise any exception.
|
365
|
+
if(status != 0) rb_jump_tag(status);
|
236
366
|
}
|
237
367
|
|
238
368
|
|
@@ -251,45 +381,47 @@ static VALUE cSedna_s_new(VALUE klass)
|
|
251
381
|
|
252
382
|
/* :nodoc:
|
253
383
|
*
|
254
|
-
* Initialize a new instance of Sedna.
|
384
|
+
* Initialize a new instance of Sedna. Undocumented, because Sedna.connect should
|
385
|
+
* be used instead.
|
255
386
|
*/
|
256
387
|
static VALUE cSedna_initialize(VALUE self, VALUE options)
|
257
388
|
{
|
258
|
-
int res;
|
259
389
|
VALUE host_k, db_k, user_k, pw_k, host_v, db_v, user_v, pw_v;
|
260
390
|
char *host, *db, *user, *pw;
|
261
|
-
SC *conn = sedna_struct(self);
|
262
391
|
|
392
|
+
// Ensure the argument is a Hash.
|
263
393
|
Check_Type(options, T_HASH);
|
394
|
+
|
395
|
+
// Store the symbols of the valid hash keys.
|
264
396
|
host_k = ID2SYM(rb_intern("host"));
|
265
397
|
db_k = ID2SYM(rb_intern("database"));
|
266
398
|
user_k = ID2SYM(rb_intern("username"));
|
267
399
|
pw_k = ID2SYM(rb_intern("password"));
|
268
400
|
|
401
|
+
// Get the connection details or set them to the default values if not given.
|
269
402
|
if(NIL_P(host_v = rb_hash_aref(options, host_k))) host = DEFAULT_HOST; else host = STR2CSTR(host_v);
|
270
|
-
if(NIL_P(db_v = rb_hash_aref(options, db_k))) db =
|
403
|
+
if(NIL_P(db_v = rb_hash_aref(options, db_k))) db = DEFAULT_DB; else db = STR2CSTR(db_v);
|
271
404
|
if(NIL_P(user_v = rb_hash_aref(options, user_k))) user = DEFAULT_USER; else user = STR2CSTR(user_v);
|
272
|
-
if(NIL_P(pw_v = rb_hash_aref(options, pw_k))) pw =
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
// status, sedna_free() will attempt to close the connection again by
|
280
|
-
// calling SEclose(), which will definitely lead to unpredictable
|
281
|
-
// results.
|
282
|
-
conn->isConnectionOk = SEDNA_CONNECTION_CLOSED;
|
283
|
-
sedna_err(conn, res);
|
284
|
-
}
|
285
|
-
|
286
|
-
// Initialize @autocommit to true (default argument).
|
287
|
-
rb_iv_set(self, "@autocommit", Qtrue);
|
405
|
+
if(NIL_P(pw_v = rb_hash_aref(options, pw_k))) pw = DEFAULT_PW; else pw = STR2CSTR(pw_v);
|
406
|
+
|
407
|
+
// Save all connection details to instance variables.
|
408
|
+
rb_iv_set(self, IV_HOST, rb_str_new2(host));
|
409
|
+
rb_iv_set(self, IV_DB, rb_str_new2(db));
|
410
|
+
rb_iv_set(self, IV_USER, rb_str_new2(user));
|
411
|
+
rb_iv_set(self, IV_PW, rb_str_new2(pw));
|
288
412
|
|
289
413
|
#ifdef NON_BLOCKING
|
290
|
-
|
414
|
+
// Create a mutex if this build supports non-blocking queries.
|
415
|
+
rb_iv_set(self, IV_MUTEX, rb_mutex_new());
|
291
416
|
#endif
|
292
417
|
|
418
|
+
// Connect to the database.
|
419
|
+
SCA c = { sedna_struct(self), host, db, user, pw };
|
420
|
+
sedna_connect(self, &c);
|
421
|
+
|
422
|
+
// Initialize @autocommit to true.
|
423
|
+
rb_iv_set(self, IV_AUTOCOMMIT, Qtrue);
|
424
|
+
|
293
425
|
return self;
|
294
426
|
}
|
295
427
|
|
@@ -297,20 +429,48 @@ static VALUE cSedna_initialize(VALUE self, VALUE options)
|
|
297
429
|
* call-seq:
|
298
430
|
* sedna.close -> nil
|
299
431
|
*
|
300
|
-
* Closes an open Sedna connection. If the connection
|
432
|
+
* Closes an open Sedna connection. If the connection is already closed when
|
301
433
|
* this method is called, nothing happens. A Sedna::ConnectionError is raised
|
302
434
|
* if the connection was open but could not be closed.
|
303
435
|
*/
|
304
436
|
static VALUE cSedna_close(VALUE self)
|
305
437
|
{
|
306
|
-
int res;
|
307
438
|
SC *conn = sedna_struct(self);
|
439
|
+
|
440
|
+
// Ensure the connection is closed.
|
441
|
+
sedna_close(conn);
|
442
|
+
|
443
|
+
// Always return nil if successful.
|
444
|
+
return Qnil;
|
445
|
+
}
|
446
|
+
|
447
|
+
/*
|
448
|
+
* call-seq:
|
449
|
+
* sedna.reset -> nil
|
450
|
+
*
|
451
|
+
* Closes an open Sedna connection and reconnects. If the connection is already
|
452
|
+
* closed when this method is called, the connection is just reestablished. When
|
453
|
+
* reconnecting, the same connection details are used that were given when initially
|
454
|
+
* connecting with the connect method.
|
455
|
+
*
|
456
|
+
* If the connection could not be closed or reopened, a Sedna::ConnectionError is
|
457
|
+
* raised. If the authentication fails when reconnecting, a
|
458
|
+
* Sedna::AuthenticationError is raised.
|
459
|
+
*/
|
460
|
+
static VALUE cSedna_reset(VALUE self)
|
461
|
+
{
|
462
|
+
SC *conn = sedna_struct(self);
|
463
|
+
|
464
|
+
// First ensure the current connection is closed.
|
465
|
+
sedna_close(conn);
|
308
466
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
467
|
+
// Retrieve stored connection details.
|
468
|
+
SCA c = { conn, STR2CSTR(rb_iv_get(self, IV_HOST)), STR2CSTR(rb_iv_get(self, IV_DB)), STR2CSTR(rb_iv_get(self, IV_USER)), STR2CSTR(rb_iv_get(self, IV_PW)) };
|
469
|
+
|
470
|
+
// Connect to the database.
|
471
|
+
sedna_connect(self, &c);
|
313
472
|
|
473
|
+
// Always return nil if successful.
|
314
474
|
return Qnil;
|
315
475
|
}
|
316
476
|
|
@@ -320,32 +480,40 @@ static VALUE cSedna_close(VALUE self)
|
|
320
480
|
* Sedna.connect(details) {|sedna| ... } -> nil
|
321
481
|
*
|
322
482
|
* Establishes a new connection to a \Sedna XML database. Accepts a hash that
|
323
|
-
* describes which database to
|
483
|
+
* describes which database to connect to.
|
324
484
|
*
|
325
485
|
* If a block is given, the block is executed if a connection was successfully
|
326
|
-
* established. The connection is closed at the end of the block
|
486
|
+
* established. The connection is closed at the end of the block or if the
|
487
|
+
* stack is unwinded (if an exception is raised, for example). If called
|
327
488
|
* without a block, a Sedna object that represents the connection is returned.
|
328
489
|
* The connection should be closed by calling Sedna#close.
|
329
490
|
*
|
330
491
|
* If a connection cannot be initiated, a Sedna::ConnectionError is raised.
|
331
492
|
* If the authentication fails, a Sedna::AuthenticationError is raised.
|
332
493
|
*
|
494
|
+
* This method does not block other threads in Ruby 1.9.1+ -- connections that
|
495
|
+
* are initiated in different threads will be created concurrently. You can
|
496
|
+
* use Sedna.blocking? to verify if the extension supports non-blocking
|
497
|
+
* behaviour.
|
498
|
+
*
|
333
499
|
* ==== Valid connection details keys
|
334
500
|
*
|
335
|
-
* * <tt>:host</tt> - Host name or IP address to which to
|
336
|
-
* * <tt>:database</tt> - Name of the database to
|
501
|
+
* * <tt>:host</tt> - Host name or IP address to which to connect to (defaults to +localhost+).
|
502
|
+
* * <tt>:database</tt> - Name of the database to connect to (defaults to +test+).
|
337
503
|
* * <tt>:username</tt> - User name to authenticate with (defaults to +SYSTEM+).
|
338
504
|
* * <tt>:password</tt> - Password to authenticate with (defaults to +MANAGER+).
|
339
505
|
*
|
340
506
|
* ==== Examples
|
341
507
|
*
|
342
508
|
* Call without a block and close the connection afterwards.
|
343
|
-
*
|
509
|
+
*
|
510
|
+
* sedna = Sedna.connect :database => "my_db", :host => "my_host"
|
344
511
|
* # Query the database and close afterwards.
|
345
512
|
* sedna.close
|
346
513
|
*
|
347
514
|
* Call with a block. The connection is closed automatically.
|
348
|
-
*
|
515
|
+
*
|
516
|
+
* Sedna.connect :database => "my_db", :host => "my_host" do |sedna|
|
349
517
|
* # Query the database.
|
350
518
|
* # The connection is closed automatically.
|
351
519
|
* end
|
@@ -353,15 +521,24 @@ static VALUE cSedna_close(VALUE self)
|
|
353
521
|
static VALUE cSedna_s_connect(VALUE klass, VALUE options)
|
354
522
|
{
|
355
523
|
int status;
|
524
|
+
|
525
|
+
// Create a new instance.
|
356
526
|
VALUE obj = rb_funcall(klass, rb_intern("new"), 1, options);
|
357
527
|
|
358
528
|
if(rb_block_given_p()) {
|
529
|
+
// If a block is given, yield the instance, and make sure we always return...
|
359
530
|
rb_protect(rb_yield, obj, &status);
|
531
|
+
|
532
|
+
// ...to ensure that the connection is closed afterwards.
|
360
533
|
cSedna_close(obj);
|
361
|
-
|
534
|
+
|
535
|
+
// Re-raise any exception.
|
536
|
+
if(status != 0) rb_jump_tag(status);
|
362
537
|
|
538
|
+
// Always return nil if successful.
|
363
539
|
return Qnil;
|
364
540
|
} else {
|
541
|
+
// If no block is given, simply return the instance.
|
365
542
|
return obj;
|
366
543
|
}
|
367
544
|
}
|
@@ -381,16 +558,33 @@ static VALUE cSedna_s_version(VALUE klass)
|
|
381
558
|
* call-seq:
|
382
559
|
* Sedna.blocking? -> true or false
|
383
560
|
*
|
384
|
-
* Returns +true+ if
|
385
|
-
* threads. Returns +false+ if multiple
|
386
|
-
*
|
387
|
-
*
|
561
|
+
* Returns +true+ if connecting with Sedna.connect or querying the database
|
562
|
+
* with Sedna#execute will block other threads. Returns +false+ if multiple
|
563
|
+
* queries can be run or multiple connections can be made simultaneously in
|
564
|
+
* different threads. \Sedna will not block other threads (this method returns
|
565
|
+
* +false+) when compiled against Ruby 1.9.1+.
|
388
566
|
*/
|
389
567
|
static VALUE cSedna_s_blocking(VALUE klass)
|
390
568
|
{
|
391
569
|
return SEDNA_BLOCKING;
|
392
570
|
}
|
393
571
|
|
572
|
+
/*
|
573
|
+
* call-seq:
|
574
|
+
* sedna.connected? -> true or false
|
575
|
+
*
|
576
|
+
* Returns +true+ if the connection is connected and functioning properly. Returns
|
577
|
+
* +false+ if the connection has been closed.
|
578
|
+
*/
|
579
|
+
static VALUE cSedna_connected(VALUE self)
|
580
|
+
{
|
581
|
+
SC *conn = sedna_struct(self);
|
582
|
+
|
583
|
+
// Return true if the connection status is OK. This only indicates that the
|
584
|
+
// client still thinks it is connected.
|
585
|
+
return (SEconnectionStatus(conn) == SEDNA_CONNECTION_OK) ? Qtrue : Qfalse;
|
586
|
+
}
|
587
|
+
|
394
588
|
/*
|
395
589
|
* call-seq:
|
396
590
|
* sedna.execute(query) -> array or nil
|
@@ -399,11 +593,11 @@ static VALUE cSedna_s_blocking(VALUE klass)
|
|
399
593
|
* Executes the given +query+ against a \Sedna database. Returns an array if the
|
400
594
|
* given query is a select query. The elements of the array are strings that
|
401
595
|
* correspond to each result in the result set. If the query is an update query
|
402
|
-
* or a (bulk) load query, +nil+ is returned. When attempting to
|
596
|
+
* or a (bulk) load query, +nil+ is returned. When attempting to execute a
|
403
597
|
* query on a closed connection, a Sedna::ConnectionError will be raised. A
|
404
598
|
* Sedna::Exception is raised if the query fails or is invalid.
|
405
599
|
*
|
406
|
-
* This method does not block other threads in Ruby 1.9 -- database queries that
|
600
|
+
* This method does not block other threads in Ruby 1.9.1+ -- database queries that
|
407
601
|
* are run in different threads with different connections will run concurrently.
|
408
602
|
* You can use Sedna.blocking? to verify if the extension supports non-blocking
|
409
603
|
* behaviour. Database queries run from different threads, but on the same
|
@@ -412,12 +606,17 @@ static VALUE cSedna_s_blocking(VALUE klass)
|
|
412
606
|
* ==== Examples
|
413
607
|
*
|
414
608
|
* Create a new document.
|
609
|
+
*
|
415
610
|
* sedna.execute "create document 'mydoc'"
|
416
611
|
* #=> nil
|
612
|
+
*
|
417
613
|
* Update the newly created document with a root node.
|
614
|
+
*
|
418
615
|
* sedna.execute "update insert <message>Hello world!</message> into doc('mydoc')"
|
419
616
|
* #=> nil
|
617
|
+
*
|
420
618
|
* Select a node in a document using XPath.
|
619
|
+
*
|
421
620
|
* sedna.execute "doc('mydoc')/message/text()"
|
422
621
|
* #=> ["Hello world!"]
|
423
622
|
*
|
@@ -429,27 +628,27 @@ static VALUE cSedna_s_blocking(VALUE klass)
|
|
429
628
|
*/
|
430
629
|
static VALUE cSedna_execute(VALUE self, VALUE query)
|
431
630
|
{
|
432
|
-
int res;
|
433
631
|
SC *conn = sedna_struct(self);
|
434
632
|
|
435
|
-
|
436
|
-
|
437
|
-
#ifdef NON_BLOCKING
|
438
|
-
// Non-blocking variant for >= 1.9.
|
633
|
+
// Prepare query arguments.
|
439
634
|
SQ q = { conn, STR2CSTR(query) };
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
635
|
+
|
636
|
+
// Verify that the connection is OK.
|
637
|
+
if(SEconnectionStatus(conn) != SEDNA_CONNECTION_OK) rb_raise(cSednaConnError, "Connection is closed.");
|
638
|
+
|
639
|
+
// Execute query.
|
640
|
+
int res = SEDNA_EXECUTE(self, &q);
|
445
641
|
|
446
642
|
switch(res) {
|
447
643
|
case SEDNA_QUERY_SUCCEEDED:
|
644
|
+
// Return the results if this was a query.
|
448
645
|
return sedna_get_results(conn);
|
449
646
|
case SEDNA_UPDATE_SUCCEEDED:
|
450
647
|
case SEDNA_BULK_LOAD_SUCCEEDED:
|
648
|
+
// Return nil if this was an update or bulk load.
|
451
649
|
return Qnil;
|
452
650
|
default:
|
651
|
+
// Raise an exception if something else happened.
|
453
652
|
sedna_err(conn, res);
|
454
653
|
return Qnil;
|
455
654
|
}
|
@@ -470,7 +669,7 @@ static VALUE cSedna_execute(VALUE self, VALUE query)
|
|
470
669
|
*
|
471
670
|
* ==== Examples
|
472
671
|
*
|
473
|
-
* Create a new
|
672
|
+
* Create a new document and retrieve its contents.
|
474
673
|
*
|
475
674
|
* sedna.load_document "<my_document>Hello world!</my_document>", "my_doc"
|
476
675
|
* #=> nil
|
@@ -490,29 +689,41 @@ static VALUE cSedna_load_document(int argc, VALUE *argv, VALUE self)
|
|
490
689
|
VALUE document, doc_name, col_name, buf;
|
491
690
|
char *doc_name_c, *col_name_c;
|
492
691
|
|
692
|
+
// Verify that the connection is OK.
|
493
693
|
if(SEconnectionStatus(conn) != SEDNA_CONNECTION_OK) rb_raise(cSednaConnError, "Connection is closed.");
|
494
694
|
|
495
|
-
|
695
|
+
// 2 mandatory arguments, 1 optional.
|
696
|
+
rb_scan_args(argc, argv, "21", &document, &doc_name, &col_name);
|
496
697
|
doc_name_c = STR2CSTR(doc_name);
|
497
698
|
col_name_c = NIL_P(col_name) ? NULL : STR2CSTR(col_name);
|
498
699
|
|
499
700
|
if(TYPE(document) == T_FILE) {
|
701
|
+
// If the document is an IO object...
|
500
702
|
while(!NIL_P(buf = rb_funcall(document, rb_intern("read"), 1, INT2NUM(LOAD_BUF_LEN)))) {
|
703
|
+
// ...read from it until we reach EOF and load the data.
|
501
704
|
res = SEloadData(conn, STR2CSTR(buf), RSTRING_LEN(buf), doc_name_c, col_name_c);
|
502
705
|
VERIFY_RES(SEDNA_DATA_CHUNK_LOADED, res, conn);
|
503
706
|
}
|
707
|
+
|
708
|
+
// If there is no data, raise an exception.
|
504
709
|
if(res == 0) rb_raise(cSednaException, "Document is empty.");
|
505
710
|
} else {
|
711
|
+
// If the document is not an IO object, verify it is a string instead.
|
506
712
|
Check_Type(document, T_STRING);
|
713
|
+
|
714
|
+
// If there is no data, raise an exception.
|
507
715
|
if(RSTRING_LEN(document) == 0) rb_raise(cSednaException, "Document is empty.");
|
508
716
|
|
717
|
+
// Load the data.
|
509
718
|
res = SEloadData(conn, STR2CSTR(document), RSTRING_LEN(document), doc_name_c, col_name_c);
|
510
719
|
VERIFY_RES(SEDNA_DATA_CHUNK_LOADED, res, conn);
|
511
720
|
}
|
512
721
|
|
722
|
+
// Signal that we're finished.
|
513
723
|
res = SEendLoadData(conn);
|
514
724
|
VERIFY_RES(SEDNA_BULK_LOAD_SUCCEEDED, res, conn);
|
515
725
|
|
726
|
+
// Always return nil if successful.
|
516
727
|
return Qnil;
|
517
728
|
}
|
518
729
|
|
@@ -525,9 +736,13 @@ static VALUE cSedna_autocommit_set(VALUE self, VALUE auto_commit)
|
|
525
736
|
int val = (RTEST(auto_commit) ? Qtrue : Qfalse);
|
526
737
|
SC *conn = sedna_struct(self);
|
527
738
|
|
739
|
+
// Switch autocommit mode on or off.
|
528
740
|
SWITCH_SEDNA_AUTOCOMMIT(conn, val);
|
529
|
-
|
741
|
+
|
742
|
+
// Set the instance variable accordingly so it can be re-set after a transaction.
|
743
|
+
rb_iv_set(self, IV_AUTOCOMMIT, val);
|
530
744
|
|
745
|
+
// Always return nil if successful.
|
531
746
|
return Qnil;
|
532
747
|
}
|
533
748
|
|
@@ -537,74 +752,163 @@ static VALUE cSedna_autocommit_set(VALUE self, VALUE auto_commit)
|
|
537
752
|
*/
|
538
753
|
static VALUE cSedna_autocommit_get(VALUE self)
|
539
754
|
{
|
540
|
-
return rb_iv_get(self,
|
755
|
+
return rb_iv_get(self, IV_AUTOCOMMIT);
|
541
756
|
}
|
542
757
|
|
543
758
|
/*
|
544
759
|
* call-seq:
|
545
760
|
* sedna.transaction { ... } -> nil
|
761
|
+
* sedna.transaction -> nil
|
546
762
|
*
|
547
|
-
* Wraps the given block in a
|
548
|
-
*
|
549
|
-
*
|
550
|
-
*
|
551
|
-
*
|
552
|
-
*
|
763
|
+
* Wraps the given block in a transaction. If the block runs completely, the
|
764
|
+
* transaction is committed. If the stack is unwinded prematurely, the
|
765
|
+
* transaction is rolled back. This typically happens when an exception is
|
766
|
+
* raised by calling +raise+ or a Symbol is thrown by invoking +throw+. Note
|
767
|
+
* that exceptions will not be rescued -- they will be re-raised after rolling
|
768
|
+
* back the transaction.
|
553
769
|
*
|
554
|
-
* This method returns +nil+ if the
|
770
|
+
* This method returns +nil+ if the transaction is successfully committed
|
555
771
|
* to the database. If the given block completes successfully, but the
|
556
|
-
*
|
557
|
-
*
|
772
|
+
* transaction fails to be committed, a Sedna::TransactionError will be raised.
|
773
|
+
*
|
774
|
+
* Transactions cannot be nested or executed simultaneously with the same
|
775
|
+
* connection. Calling this method inside a block that is passed to another
|
776
|
+
* transaction, or with the same connection in two concurrent threads will
|
777
|
+
* raise a Sedna::TransactionError on the second invocation.
|
558
778
|
*
|
559
|
-
*
|
560
|
-
*
|
561
|
-
*
|
562
|
-
*
|
779
|
+
* If no block is given, this method only signals the beginning of a new
|
780
|
+
* transaction. A subsequent call to Sedna#commit or Sedna#rollback is required
|
781
|
+
* to end the transaction. Note that invoking this method with a block is the
|
782
|
+
* preferred way of executing transactions, because any exceptions that may be
|
783
|
+
* raised will automatically trigger a proper transaction rollback. Only call
|
784
|
+
* +commit+ and +rollback+ directly if you cannot use a block to wrap your
|
785
|
+
* transaction in.
|
563
786
|
*
|
564
787
|
* ==== Examples
|
565
788
|
*
|
789
|
+
* Transactions are committed after the given block ends.
|
790
|
+
*
|
566
791
|
* sedna.transaction do
|
567
|
-
*
|
568
|
-
* sedna.execute "update
|
792
|
+
* amount = 100
|
793
|
+
* sedna.execute "update replace $balance in doc('my_account')/balance
|
794
|
+
* with <balance>{$balance - #{amount}}</balance>"
|
795
|
+
* sedna.execute "update replace $balance in doc('your_account')/balance
|
796
|
+
* with <balance>{$balance + #{amount}}</balance>"
|
569
797
|
* # ...
|
570
798
|
* end
|
571
799
|
* # Transaction is committed.
|
572
800
|
*
|
801
|
+
* Transactions are rolled back if something is thrown from inside the block.
|
802
|
+
*
|
803
|
+
* sedna.transaction do
|
804
|
+
* articles = sedna.execute "for $a in collection('articles')
|
805
|
+
* where $a/article/author = 'me' return $a"
|
806
|
+
* throw :no_articles if articles.empty?
|
807
|
+
* # ... never get here
|
808
|
+
* end
|
809
|
+
* # Transaction is rolled back.
|
810
|
+
*
|
811
|
+
* Transactions are also rolled back if an exception is raised inside the block.
|
812
|
+
*
|
573
813
|
* sedna.transaction do
|
574
|
-
*
|
575
|
-
*
|
814
|
+
* amount = 100
|
815
|
+
* sedna.execute "update replace $balance in doc('my_account')/balance
|
816
|
+
* with <balance>{$balance - #{amount}}</balance>"
|
817
|
+
* new_balance = sedna.execute "doc('my_account')/balance"
|
818
|
+
* raise "Insufficient funds" if new_balance.to_i < 0
|
576
819
|
* # ... never get here
|
577
820
|
* end
|
578
821
|
* # Transaction is rolled back.
|
822
|
+
*
|
823
|
+
* If you really have to, you can also use transactions declaratively. Make
|
824
|
+
* sure to roll back the transaction if something goes wrong!
|
825
|
+
*
|
826
|
+
* sedna.transaction
|
827
|
+
* begin
|
828
|
+
* amount = 100
|
829
|
+
* sedna.execute "update replace $balance in doc('my_account')/balance
|
830
|
+
* with <balance>{$balance - #{amount}}</balance>"
|
831
|
+
* sedna.execute "update replace $balance in doc('your_account')/balance
|
832
|
+
* with <balance>{$balance + #{amount}}</balance>"
|
833
|
+
* rescue Exception
|
834
|
+
* sedna.rollback
|
835
|
+
* else
|
836
|
+
* sedna.commit
|
837
|
+
* end
|
579
838
|
*/
|
580
839
|
static VALUE cSedna_transaction(VALUE self)
|
581
840
|
{
|
582
841
|
int status;
|
583
842
|
SC *conn = sedna_struct(self);
|
584
843
|
|
585
|
-
|
586
|
-
|
844
|
+
// Begin the transaction.
|
845
|
+
sedna_begin(conn);
|
587
846
|
|
588
|
-
|
847
|
+
if(rb_block_given_p()) {
|
848
|
+
// Yield to the given block and protect it so we can always commit or rollback.
|
849
|
+
rb_protect(rb_yield, Qnil, &status);
|
589
850
|
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
else
|
851
|
+
if(status == 0) {
|
852
|
+
// Attempt to commit if block completed successfully.
|
853
|
+
sedna_commit(conn, self);
|
854
|
+
} else {
|
855
|
+
// Stack has unwinded, attempt to roll back!
|
856
|
+
sedna_rollback(conn, self);
|
594
857
|
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
858
|
+
// Re-raise any exception or re-throw whatever was thrown.
|
859
|
+
rb_jump_tag(status);
|
860
|
+
}
|
861
|
+
}
|
599
862
|
|
600
|
-
|
863
|
+
// Always return nil if successful.
|
864
|
+
return Qnil;
|
865
|
+
}
|
601
866
|
|
602
|
-
|
603
|
-
|
867
|
+
/*
|
868
|
+
* call-seq:
|
869
|
+
* sedna.commit -> nil
|
870
|
+
*
|
871
|
+
* Commits a currently active transaction. Only use this method if you are
|
872
|
+
* specifying a transaction declaratively. Invoking Sedna#transaction with a
|
873
|
+
* block will automatically commit the transaction if the block finishes
|
874
|
+
* successfully.
|
875
|
+
*
|
876
|
+
* This method will raise a Sedna::TransactionError if no transaction is in
|
877
|
+
* progress when it is called.
|
878
|
+
*/
|
879
|
+
static VALUE cSedna_commit(VALUE self)
|
880
|
+
{
|
881
|
+
SC *conn = sedna_struct(self);
|
604
882
|
|
883
|
+
// Attempt to commit.
|
884
|
+
sedna_commit(conn, self);
|
885
|
+
|
886
|
+
// Always return nil if successful.
|
605
887
|
return Qnil;
|
606
888
|
}
|
607
889
|
|
890
|
+
/*
|
891
|
+
* call-seq:
|
892
|
+
* sedna.rollback -> nil
|
893
|
+
*
|
894
|
+
* Rolls back a currently active transaction. Only use this method if you are
|
895
|
+
* specifying a transaction declaratively. Invoking Sedna#transaction with a
|
896
|
+
* block will automatically roll back the transaction if an exception is raised
|
897
|
+
* or if the stack is unwinded for whatever reason.
|
898
|
+
*
|
899
|
+
* This method will do nothing if no transaction is in progress when it is
|
900
|
+
* called.
|
901
|
+
*/
|
902
|
+
static VALUE cSedna_rollback(VALUE self)
|
903
|
+
{
|
904
|
+
SC *conn = sedna_struct(self);
|
905
|
+
|
906
|
+
// Attempt to roll back.
|
907
|
+
sedna_rollback(conn, self);
|
908
|
+
|
909
|
+
// Always return nil if successful.
|
910
|
+
return Qnil;
|
911
|
+
}
|
608
912
|
|
609
913
|
// Initialize the extension ==============================================
|
610
914
|
|
@@ -621,7 +925,8 @@ void Init_sedna()
|
|
621
925
|
* :username => "SYSTEM",
|
622
926
|
* :password => "MANAGER",
|
623
927
|
* }
|
624
|
-
*
|
928
|
+
*
|
929
|
+
* Sedna.connect connection_details do |sedna|
|
625
930
|
* # Query the database.
|
626
931
|
* # The connection is closed automatically.
|
627
932
|
* end
|
@@ -636,19 +941,22 @@ void Init_sedna()
|
|
636
941
|
rb_define_singleton_method(cSedna, "blocking?", cSedna_s_blocking, 0);
|
637
942
|
|
638
943
|
rb_define_method(cSedna, "initialize", cSedna_initialize, 1);
|
639
|
-
rb_define_method(cSedna, "
|
640
|
-
rb_define_method(cSedna, "load_document", cSedna_load_document, -1);
|
944
|
+
rb_define_method(cSedna, "connected?", cSedna_connected, 0);
|
641
945
|
rb_define_method(cSedna, "close", cSedna_close, 0);
|
946
|
+
rb_define_method(cSedna, "reset", cSedna_reset, 0);
|
642
947
|
rb_define_method(cSedna, "transaction", cSedna_transaction, 0);
|
643
|
-
|
948
|
+
rb_define_method(cSedna, "commit", cSedna_commit, 0);
|
949
|
+
rb_define_method(cSedna, "rollback", cSedna_rollback, 0);
|
950
|
+
rb_define_method(cSedna, "execute", cSedna_execute, 1);
|
644
951
|
rb_define_undocumented_alias(cSedna, "query", "execute");
|
952
|
+
rb_define_method(cSedna, "load_document", cSedna_load_document, -1);
|
645
953
|
|
646
954
|
/*
|
647
955
|
* Document-attr: autocommit
|
648
956
|
*
|
649
957
|
* When autocommit is set to +true+ (default), database queries can be run
|
650
958
|
* without explicitly wrapping them in a transaction. Each query that is not
|
651
|
-
* part of a
|
959
|
+
* part of a transaction is automatically committed to the database.
|
652
960
|
* Explicit transactions in auto-commit mode will still be committed
|
653
961
|
* atomically.
|
654
962
|
*
|
@@ -664,9 +972,12 @@ void Init_sedna()
|
|
664
972
|
rb_define_method(cSedna, "autocommit", cSedna_autocommit_get, 0);
|
665
973
|
|
666
974
|
/*
|
667
|
-
* The result
|
975
|
+
* The result of a database query is stored in a Sedna::Set object, which
|
976
|
+
* is a subclass of Array. Additional details about the executed query, such
|
977
|
+
* as timing and debug information, may be added to Sedna::Set objects in
|
978
|
+
* future versions of this library.
|
668
979
|
*/
|
669
|
-
//
|
980
|
+
// Stick to Array for result sets.
|
670
981
|
//cSednaSet = rb_define_class_under(cSedna, "Set", rb_cArray);
|
671
982
|
|
672
983
|
/*
|