Class: Sedna
- Inherits:
-
Object
- Object
- Sedna
- Defined in:
- ext/sedna/sedna.c
Defined Under Namespace
Classes: AuthenticationError, ConnectionError, Exception, TransactionError
Instance Attribute Summary collapse
-
#autocommit ⇒ Object
When autocommit is set to
true
(default), database queries can be run without explicitly wrapping them in a transaction.
Class Method Summary collapse
-
.blocking? ⇒ Boolean
Returns
true
if connecting with Sedna.connect or querying the database with Sedna#execute will block other threads. -
.connect(options) ⇒ Object
Establishes a new connection to a Sedna XML database.
-
.version ⇒ String
Returns the current version of the Sedna client protocol.
Instance Method Summary collapse
-
#close ⇒ nil
Closes an open Sedna connection.
-
#commit ⇒ nil
Commits a currently active transaction.
-
#connected? ⇒ Boolean
Returns
true
if the connection is connected and functioning properly. -
#execute(query) ⇒ Object
Executes the given
query
against a Sedna database. -
#initialize(options) ⇒ Object
constructor
:nodoc:.
-
#load_document(document, doc_name, col_name = nil) ⇒ nil
Creates a new document named
doc_name
in collectioncol_name
, or as a stand-alone document ifcol_name
isnil
. -
#reset ⇒ nil
Closes an open Sedna connection and reconnects.
-
#rollback ⇒ nil
Rolls back a currently active transaction.
-
#transaction ⇒ Object
Wraps the given block in a transaction.
Constructor Details
#initialize(options) ⇒ Object
:nodoc:
Initialize a new instance of Sedna. Undocumented, because Sedna.connect should be used instead.
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 |
# File 'ext/sedna/sedna.c', line 402
static VALUE cSedna_initialize(VALUE self, VALUE options)
{
VALUE host_k, db_k, user_k, pw_k,
host_v, db_v, user_v, pw_v;
char *host, *db, *user, *pw;
// Ensure the argument is a Hash.
Check_Type(options, T_HASH);
// Store the symbols of the valid hash keys.
host_k = ID2SYM(rb_intern("host"));
db_k = ID2SYM(rb_intern("database"));
user_k = ID2SYM(rb_intern("username"));
pw_k = ID2SYM(rb_intern("password"));
// Get the connection details or set them to the default values if not given.
if(NIL_P(host_v = rb_hash_aref(options, host_k))) host = strdup(DEFAULT_HOST); else host = StringValuePtr(host_v);
if(NIL_P(db_v = rb_hash_aref(options, db_k ))) db = strdup(DEFAULT_DB); else db = StringValuePtr(db_v);
if(NIL_P(user_v = rb_hash_aref(options, user_k))) user = strdup(DEFAULT_USER); else user = StringValuePtr(user_v);
if(NIL_P(pw_v = rb_hash_aref(options, pw_k ))) pw = strdup(DEFAULT_PW); else pw = StringValuePtr(pw_v);
// Save all connection details to instance variables.
rb_iv_set(self, IV_HOST, rb_str_new2(host));
rb_iv_set(self, IV_DB, rb_str_new2(db));
rb_iv_set(self, IV_USER, rb_str_new2(user));
rb_iv_set(self, IV_PW, rb_str_new2(pw));
#ifdef NON_BLOCKING
// Create a mutex if this build supports non-blocking queries.
rb_iv_set(self, IV_MUTEX, rb_mutex_new());
#endif
// Connect to the database.
SCA c = { sedna_struct(self), host, db, user, pw };
sedna_connect(self, &c);
// Initialize @autocommit to true.
rb_iv_set(self, IV_AUTOCOMMIT, Qtrue);
return self;
}
|
Instance Attribute Details
#autocommit ⇒ Object
When autocommit is set to true
(default), database queries can be run without explicitly wrapping them in a transaction. Each query that is not part of a transaction is automatically committed to the database. Explicit transactions in auto-commit mode will still be committed atomically.
When autocommit is set to false
, queries can only be run inside an explicit transaction. Queries run outside transactions will fail with a Sedna::Exception.
775 776 777 778 |
# File 'ext/sedna/sedna.c', line 775
static VALUE cSedna_autocommit_get(VALUE self)
{
return rb_iv_get(self, IV_AUTOCOMMIT);
}
|
Class Method Details
.blocking? ⇒ Boolean
Returns true
if connecting with Sedna.connect or querying the database with Sedna#execute will block other threads. Returns false
if multiple queries can be run or multiple connections can be made simultaneously in different threads. Sedna will not block other threads (this method returns false
) when compiled against Ruby 1.9.1+.
589 590 591 592 |
# File 'ext/sedna/sedna.c', line 589
static VALUE cSedna_s_blocking(VALUE klass)
{
return SEDNA_BLOCKING;
}
|
.connect(details) ⇒ Sedna instance .connect(details) {|sedna| ... } ⇒ nil
Establishes a new connection to a Sedna XML database. Accepts a hash that describes which database to connect to.
If a block is given, the block is executed if a connection was successfully established. The connection is closed at the end of the block or if the stack is unwinded (if an exception is raised, for example). If called without a block, a Sedna object that represents the connection is returned. The connection should be closed by calling Sedna#close.
If a connection cannot be initiated, a Sedna::ConnectionError is raised. If the authentication fails, a Sedna::AuthenticationError is raised.
This method does not block other threads in Ruby 1.9.1+ – connections that are initiated in different threads will be created concurrently. You can use Sedna.blocking? to verify if the extension supports non-blocking behaviour.
Valid connection details keys
-
:host
- Host name or IP address to which to connect to (defaults tolocalhost
). -
:database
- Name of the database to connect to (defaults totest
). -
:username
- User name to authenticate with (defaults toSYSTEM
). -
:password
- Password to authenticate with (defaults toMANAGER
).
Examples
Call without a block and close the connection afterwards.
sedna = Sedna.connect :database => "my_db", :host => "my_host"
# Query the database and close afterwards.
sedna.close
Call with a block. The connection is closed automatically.
Sedna.connect :database => "my_db", :host => "my_host" do |sedna|
# Query the database.
# The connection is closed automatically.
end
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 |
# File 'ext/sedna/sedna.c', line 543
static VALUE cSedna_s_connect(VALUE klass, VALUE options)
{
int status;
// Create a new instance.
VALUE obj = rb_funcall(klass, rb_intern("new"), 1, options);
if(rb_block_given_p()) {
// If a block is given, yield the instance, and make sure we always return...
rb_protect(rb_yield, obj, &status);
// ...to ensure that the connection is closed afterwards.
cSedna_close(obj);
// Re-raise any exception.
if(status != 0) rb_jump_tag(status);
// Always return nil if successful.
return Qnil;
} else {
// If no block is given, simply return the instance.
return obj;
}
}
|
.version ⇒ String
Returns the current version of the Sedna client protocol.
574 575 576 577 |
# File 'ext/sedna/sedna.c', line 574
static VALUE cSedna_s_version(VALUE klass)
{
return rb_str_new2(PROTOCOL_VERSION);
}
|
Instance Method Details
#close ⇒ nil
Closes an open Sedna connection. If the connection is already closed when this method is called, nothing happens. A Sedna::ConnectionError is raised if the connection was open but could not be closed.
452 453 454 455 456 457 458 459 460 461 |
# File 'ext/sedna/sedna.c', line 452
static VALUE cSedna_close(VALUE self)
{
SC *conn = sedna_struct(self);
// Ensure the connection is closed.
sedna_close(conn);
// Always return nil if successful.
return Qnil;
}
|
#commit ⇒ nil
Commits a currently active transaction. Only use this method if you are specifying a transaction declaratively. Invoking Sedna#transaction with a block will automatically commit the transaction if the block finishes successfully.
This method will raise a Sedna::TransactionError if no transaction is in progress when it is called.
901 902 903 904 905 906 907 908 909 910 |
# File 'ext/sedna/sedna.c', line 901
static VALUE cSedna_commit(VALUE self)
{
SC *conn = sedna_struct(self);
// Attempt to commit.
sedna_commit(conn, self);
// Always return nil if successful.
return Qnil;
}
|
#connected? ⇒ Boolean
Returns true
if the connection is connected and functioning properly. Returns false
if the connection has been closed.
601 602 603 604 605 606 607 608 |
# File 'ext/sedna/sedna.c', line 601
static VALUE cSedna_connected(VALUE self)
{
SC *conn = sedna_struct(self);
// Return true if the connection status is OK. This only indicates that the
// client still thinks it is connected.
return (SEconnectionStatus(conn) == SEDNA_CONNECTION_OK) ? Qtrue : Qfalse;
}
|
#execute(query) ⇒ Array? #query(query) ⇒ Array?
Executes the given query
against a Sedna database. Returns an array if the given query is a select query. The elements of the array are strings that correspond to each result in the result set. If the query is an update query or a (bulk) load query, nil
is returned. When attempting to execute a query on a closed connection, a Sedna::ConnectionError will be raised. A Sedna::Exception is raised if the query fails or is invalid.
This method does not block other threads in Ruby 1.9.1+ – database queries that are run in different threads with different connections will run concurrently. You can use Sedna.blocking? to verify if the extension supports non-blocking behaviour. Database queries run from different threads, but on the same connection will still block and be executed serially.
Examples
Create a new document.
sedna.execute "create document 'mydoc'"
#=> nil
Update the newly created document with a root node.
sedna.execute "update insert <message>Hello world!</message> into doc('mydoc')"
#=> nil
Select a node in a document using XPath.
sedna.execute "doc('mydoc')/message/text()"
#=> ["Hello world!"]
Further reading
For more information about Sedna’s database query syntax and support, see the Database language section of the official documentation of the Sedna project at modis.ispras.ru/sedna/progguide/ProgGuidese2.html
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
# File 'ext/sedna/sedna.c', line 651
static VALUE cSedna_execute(VALUE self, VALUE query)
{
SC *conn = sedna_struct(self);
// Prepare query arguments.
SQ q = { conn, StringValuePtr(query) };
// Verify that the connection is OK.
if(SEconnectionStatus(conn) != SEDNA_CONNECTION_OK) rb_raise(cSednaConnError, "Connection is closed.");
// Execute query.
int res = SEDNA_EXECUTE(self, &q);
switch(res) {
case SEDNA_QUERY_SUCCEEDED:
// Return the results if this was a query.
return sedna_get_results(conn);
case SEDNA_UPDATE_SUCCEEDED:
case SEDNA_BULK_LOAD_SUCCEEDED:
// Return nil if this was an update or bulk load.
return Qnil;
default:
// Raise an exception if something else happened.
sedna_err(conn, res);
return Qnil;
}
}
|
#load_document(document, doc_name, col_name = nil) ⇒ nil
Creates a new document named doc_name
in collection col_name
, or as a stand-alone document if col_name
is nil
. The string document
is subsequently loaded into the newly created document. As an alternative, the argument document
may be an IO object (or any descendant, such as a File object).
If the document was successfully loaded, this method returns nil
. If an error occurs, a Sedna::Exception is raised.
Examples
Create a new document and retrieve its contents.
sedna.load_document "<my_document>Hello world!</my_document>", "my_doc"
#=> nil
sedna.execute "doc('my_doc')"
#=> ["<?xml version=\"1.0\" standalone=\"yes\"?><my_document>Hello world!</my_document>"]
Open a file and import its contents into a new document in an existing collection.
File.open "document.xml" do |file|
sedna.load_document file, "my_doc", "my_col"
end
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 |
# File 'ext/sedna/sedna.c', line 707
static VALUE cSedna_load_document(int argc, VALUE *argv, VALUE self)
{
int res = 0;
SC *conn = sedna_struct(self);
VALUE document, doc_name, col_name, buf;
char *doc_name_c, *col_name_c;
// Verify that the connection is OK.
if(SEconnectionStatus(conn) != SEDNA_CONNECTION_OK) rb_raise(cSednaConnError, "Connection is closed.");
// 2 mandatory arguments, 1 optional.
rb_scan_args(argc, argv, "21", &document, &doc_name, &col_name);
doc_name_c = StringValuePtr(doc_name);
col_name_c = NIL_P(col_name) ? NULL : StringValuePtr(col_name);
if(TYPE(document) == T_FILE) {
// If the document is an IO object...
while(!NIL_P(buf = rb_funcall(document, rb_intern("read"), 1, INT2NUM(LOAD_BUF_LEN)))) {
// ...read from it until we reach EOF and load the data.
res = SEloadData(conn, StringValuePtr(buf), RSTRING_LEN(buf), doc_name_c, col_name_c);
VERIFY_RES(SEDNA_DATA_CHUNK_LOADED, res, conn);
}
// If there is no data, raise an exception.
if(res == 0) rb_raise(cSednaException, "Document is empty.");
} else {
// If the document is not an IO object, verify it is a string instead.
Check_Type(document, T_STRING);
// If there is no data, raise an exception.
if(RSTRING_LEN(document) == 0) rb_raise(cSednaException, "Document is empty.");
// Load the data.
res = SEloadData(conn, StringValuePtr(document), RSTRING_LEN(document), doc_name_c, col_name_c);
VERIFY_RES(SEDNA_DATA_CHUNK_LOADED, res, conn);
}
// Signal that we're finished.
res = SEendLoadData(conn);
VERIFY_RES(SEDNA_BULK_LOAD_SUCCEEDED, res, conn);
// Always return nil if successful.
return Qnil;
}
|
#reset ⇒ nil
Closes an open Sedna connection and reconnects. If the connection is already closed when this method is called, the connection is just reestablished. When reconnecting, the same connection details are used that were given when initially connecting with the connect method.
If the connection could not be closed or reopened, a Sedna::ConnectionError is raised. If the authentication fails when reconnecting, a Sedna::AuthenticationError is raised.
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
# File 'ext/sedna/sedna.c', line 476
static VALUE cSedna_reset(VALUE self)
{
VALUE host_v, db_v, user_v, pw_v;
SC *conn = sedna_struct(self);
// First ensure the current connection is closed.
sedna_close(conn);
// Retrieve stored connection details.
host_v = rb_iv_get(self, IV_HOST);
db_v = rb_iv_get(self, IV_DB);
user_v = rb_iv_get(self, IV_USER);
pw_v = rb_iv_get(self, IV_PW);
SCA c = { conn, StringValuePtr(host_v), StringValuePtr(db_v), StringValuePtr(user_v), StringValuePtr(pw_v) };
// Connect to the database.
sedna_connect(self, &c);
// Always return nil if successful.
return Qnil;
}
|
#rollback ⇒ nil
Rolls back a currently active transaction. Only use this method if you are specifying a transaction declaratively. Invoking Sedna#transaction with a block will automatically roll back the transaction if an exception is raised or if the stack is unwinded for whatever reason.
This method will do nothing if no transaction is in progress when it is called.
924 925 926 927 928 929 930 931 932 933 |
# File 'ext/sedna/sedna.c', line 924
static VALUE cSedna_rollback(VALUE self)
{
SC *conn = sedna_struct(self);
// Attempt to roll back.
sedna_rollback(conn, self);
// Always return nil if successful.
return Qnil;
}
|
#transaction { ... } ⇒ nil #transaction ⇒ nil
Wraps the given block in a transaction. If the block runs completely, the transaction is committed. If the stack is unwinded prematurely, the transaction is rolled back. This typically happens when an exception is raised by calling raise
or a Symbol is thrown by invoking throw
. Note that exceptions will not be rescued – they will be re-raised after rolling back the transaction.
This method returns nil
if the transaction is successfully committed to the database. If the given block completes successfully, but the transaction fails to be committed, a Sedna::TransactionError will be raised.
Transactions cannot be nested or executed simultaneously with the same connection. Calling this method inside a block that is passed to another transaction, or with the same connection in two concurrent threads will raise a Sedna::TransactionError on the second invocation.
If no block is given, this method only signals the beginning of a new transaction. A subsequent call to Sedna#commit or Sedna#rollback is required to end the transaction. Note that invoking this method with a block is the preferred way of executing transactions, because any exceptions that may be raised will automatically trigger a proper transaction rollback. Only call commit
and rollback
directly if you cannot use a block to wrap your transaction in.
Examples
Transactions are committed after the given block ends.
sedna.transaction do
amount = 100
sedna.execute "update replace $balance in doc('my_account')/balance
with <balance>{$balance - #{amount}}</balance>"
sedna.execute "update replace $balance in doc('your_account')/balance
with <balance>{$balance + #{amount}}</balance>"
# ...
end
# Transaction is committed.
Transactions are rolled back if something is thrown from inside the block.
sedna.transaction do
articles = sedna.execute "for $a in collection('articles')
where $a/article/author = 'me' return $a"
throw :no_articles if articles.empty?
# ... never get here
end
# Transaction is rolled back.
Transactions are also rolled back if an exception is raised inside the block.
sedna.transaction do
amount = 100
sedna.execute "update replace $balance in doc('my_account')/balance
with <balance>{$balance - #{amount}}</balance>"
new_balance = sedna.execute "doc('my_account')/balance"
raise "Insufficient funds" if new_balance.to_i < 0
# ... never get here
end
# Transaction is rolled back.
If you really have to, you can also use transactions declaratively. Make sure to roll back the transaction if something goes wrong!
sedna.transaction
begin
amount = 100
sedna.execute "update replace $balance in doc('my_account')/balance
with <balance>{$balance - #{amount}}</balance>"
sedna.execute "update replace $balance in doc('your_account')/balance
with <balance>{$balance + #{amount}}</balance>"
rescue Exception
sedna.rollback
else
sedna.commit
end
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 |
# File 'ext/sedna/sedna.c', line 861
static VALUE cSedna_transaction(VALUE self)
{
int status;
SC *conn = sedna_struct(self);
// Begin the transaction.
sedna_begin(conn);
if(rb_block_given_p()) {
// Yield to the given block and protect it so we can always commit or rollback.
rb_protect(rb_yield, Qnil, &status);
if(status == 0) {
// Attempt to commit if block completed successfully.
sedna_commit(conn, self);
} else {
// Stack has unwinded, attempt to roll back!
sedna_rollback(conn, self);
// Re-raise any exception or re-throw whatever was thrown.
rb_jump_tag(status);
}
}
// Always return nil if successful.
return Qnil;
}
|