sedna 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
/*
|