Struct yottadb::Context[][src]

pub struct Context { /* fields omitted */ }

A struct that keeps track of the current transaction and error buffer.

Since all functions in the YottaDB threaded API take a tptoken and error_buffer, it can be inconvenient to keep track of them manually, especially since

Passing in a different or incorrect tptoken can result in hard-to-debug application behavior, including deadlocks. 1

This struct keeps track of them for you so you don't have to clutter your application logic with resource management.

See also

Context is not thread-safe, async-safe, or re-entrant.

Example:

use yottadb::{Context, TransactionStatus, make_ckey};

let ctx = Context::new();
let mut key1 = make_ckey!(ctx, "key1");
let mut key2 = make_ckey!(ctx, "key2");
tokio::spawn(async {
    // error[E0277]: `dyn std::error::Error` cannot be sent between threads safely
    ctx.tp(|_| Ok(TransactionStatus::Ok), "BATCH", &[])
});

Implementations

impl Context[src]

Call-in functions

pub fn ci_tab_open(&self, file: &CStr) -> YDBResult<CallInTableDescriptor>[src]

Open the call-in table stored in file and return its file descriptor.

You can later switch the active call-in table by calling ci_tab_switch with the file descriptor.

See also

Errors

  • a negative error return code (for example, if the call-in table in the file had parse errors).

Example

use std::ffi::CString;
use yottadb::Context;

let ctx = Context::new();
let file = CString::new("examples/m-ffi/calltab.ci").unwrap();
let descriptor = ctx.ci_tab_open(&file)?;

pub fn ci_tab_switch(
    &self,
    new_handle: CallInTableDescriptor
) -> YDBResult<CallInTableDescriptor>
[src]

Switch the active call-in table to new_handle. Returns the previously active table.

new_handle is a file descriptor returned by ci_tab_open.

Errors

Example

use std::ffi::CString;
use yottadb::Context;

let ctx = Context::new();
let file = CString::new("examples/m-ffi/calltab.ci").unwrap();
let descriptor = ctx.ci_tab_open(&file)?;
let old_ci_table = ctx.ci_tab_switch(descriptor)?;

impl Context[src]

pub fn new() -> Context[src]

Create a new Context

pub fn new_key<K: Into<Key>>(&self, key: K) -> KeyContext[src]

pub fn tptoken(&self) -> TpToken[src]

Return the token for the transaction associated with this Context.

This allows calling yottadb functions in the craw API that have not yet been wrapped and require a tptoken from inside a transaction.

Example

tptoken() can be used to call M FFI from within a transaction:

use std::env;
use std::ffi::CStr;
use yottadb::{ci_t, Context, TransactionStatus, YDB_NOTTP};

env::set_var("ydb_routines", "examples/m-ffi");
env::set_var("ydb_ci", "examples/m-ffi/calltab.ci");
let ctx = Context::new();
ctx.tp(|ctx| {
    let tptoken = ctx.tptoken();
    assert_ne!(tptoken, YDB_NOTTP);
    let mut routine = CStr::from_bytes_with_nul(b"noop\0").unwrap();
    unsafe { ci_t!(tptoken, Vec::new(), routine)?; }
    Ok(TransactionStatus::Ok)
}, "BATCH", &[]).unwrap();

See also

pub fn tp<'a, F>(
    &'a self,
    f: F,
    trans_id: &str,
    locals_to_reset: &[&str]
) -> Result<(), Box<dyn Error + Send + Sync>> where
    F: FnMut(&'a Self) -> Result<TransactionStatus, Box<dyn Error + Send + Sync>>, 
[src]

Start a new transaction, where f is the transaction to execute.

tp stands for 'transaction processing'.

The parameter trans_id is the name logged for the transaction. If trans_id has the special value "BATCH", durability is not enforced by YottaDB. See the C documentation for details.

The argument passed to f is a transaction processing token.

Rollbacks and Restarts

Application code can return a TransactionStatus in order to rollback or restart. tp_st behaves as follows:

  • If f panics, the transaction is rolled back and the panic resumes afterwards.
  • If f returns Ok(TransactionStatus), the transaction will have the behavior documented under TransactionStatus (commit, restart, and rollback, respectively).
  • If f returns an Err(YDBError), the status from that error will be returned to the YottaDB engine. As a result, if the status for the YDBError is YDB_TP_RESTART, the transaction will be restarted. Otherwise, the transaction will be rolled back and the error returned from tp_st.
  • If f returns any other Err variant, the transaction will be rolled back and the error returned from tp_st.

f must be FnMut, not FnOnce, since the YottaDB engine may call f many times if necessary to ensure ACID properties. This may affect your application logic; if you need to know how many times the callback has been executed, get the intrinsic variable $trestart.

Errors

  • YDB_ERR_TPTIMEOUT - The transaction took more than $zmaxtptime seconds to execute, where $zmaxtptime is an intrinsic special variable.
  • YDB_TP_ROLLBACK — application logic indicates that the transaction should not be committed.
  • A YDBError returned by a YottaDB function called by f.
  • Another arbitrary error returned by f.

Examples

Rollback a transaction if an operation fails:

use yottadb::{Context, KeyContext, TpToken, TransactionStatus};

let ctx = Context::new();
let var = KeyContext::variable(&ctx, "tpRollbackTest");
var.set("initial value")?;
println!("starting tp");
let maybe_err = ctx.tp(|ctx| {
    println!("in tp");
    fallible_operation()?;
    println!("succeeded");
    var.set("new value")?;
    Ok(TransactionStatus::Ok)
}, "BATCH", &[]);
let expected_val: &[_] = if maybe_err.is_ok() {
    b"new value"
} else {
    b"initial value"
};
assert_eq!(var.get()?, expected_val);

fn fallible_operation() -> Result<(), &'static str> {
    if rand::random() {
        Ok(())
    } else {
        Err("the operation failed")
    }
}

Retry a transaction until it succeeds:

use yottadb::{Context, TpToken, TransactionStatus};

let ctx = Context::new();
ctx.tp(|tptoken| {
    if fallible_operation().is_ok() {
        Ok(TransactionStatus::Ok)
    } else {
        Ok(TransactionStatus::Restart)
    }
}, "BATCH", &[]).unwrap();

fn fallible_operation() -> Result<(), ()> {
    if rand::random() {
        Ok(())
    } else {
        Err(())
    }
}

See Also

pub fn delete_excl(&self, saved_variables: &[&str]) -> YDBResult<()>[src]

Delete all local variables except for those passed in saved_variable.

Passing an empty saved_variables slice deletes all local variables. Attempting to save a global or intrinsic variable is an error.

Errors

  • YDB_ERR_NAMECOUNT2HI if saved_variables.len() > YDB_MAX_NAMES
  • YDB_ERR_INVVARNAME if attempting to save a global or intrinsic variable
  • Another system error return code

Examples

use yottadb::{Context, KeyContext, TpToken, YDB_ERR_LVUNDEF};

// Create three variables and set all
let ctx = Context::new();
let a = KeyContext::variable(&ctx, "deleteExclTestA");
a.set("test data")?;
let b = KeyContext::variable(&ctx, "deleteExclTestB");
b.set("test data 2")?;
let c = KeyContext::variable(&ctx, "deleteExclTestC");
c.set("test data 3")?;

// Delete all variables except `a`
ctx.delete_excl(&[&a.variable])?;
assert_eq!(a.get()?, b"test data");
assert_eq!(b.get().unwrap_err().status, YDB_ERR_LVUNDEF);
assert_eq!(c.get().unwrap_err().status, YDB_ERR_LVUNDEF);

// Delete `a` too
ctx.delete_excl(&[])?;
assert_eq!(a.get().unwrap_err().status, YDB_ERR_LVUNDEF);

See also

pub fn eintr_handler(&self) -> YDBResult<()>[src]

Runs the YottaDB deferred signal handler (if necessary).

This function must be called if an application has a tight loop inside a transaction which never calls a YDB function.

See also

pub fn str2zwr(&self, original: &[u8]) -> YDBResult<Vec<u8>>[src]

Given a binary sequence, serialize it to 'Zwrite format', which is ASCII printable.

Errors

Examples

When ydb_chset=UTF-8 is set, this will preserve UTF-8 characters:

use yottadb::Context;

let ctx = Context::new();
let str2zwr = ctx.str2zwr("💖".as_bytes())?;
if std::env::var("ydb_chset").as_deref() == Ok("UTF-8") {
    assert_eq!(str2zwr, "\"💖\"".as_bytes());
} else {
    // Note: The "$C" below cannot be expanded to "$CH" or "$CHAR" as that is the output returned by "str2zwr()" in M mode.
    assert_eq!(str2zwr, b"\"\xf0\"_$C(159,146,150)");
}

When the input is invalid UTF-8, it will use the more verbose Zwrite format:

use yottadb::Context;

let ctx = Context::new();
let input = b"\xff";
assert!(std::str::from_utf8(input).is_err());
assert_eq!(ctx.str2zwr(input)?, b"$ZCH(255)");

See also

pub fn zwr2str(&self, serialized: &[u8]) -> Result<Vec<u8>, YDBError>[src]

Given a buffer in 'Zwrite format', deserialize it to the original binary buffer.

zwr2str_st writes directly to out_buf to avoid returning multiple output buffers.

Errors

This function returns an empty array if serialized is not in Zwrite format. It can also return another error code.

Examples

use yottadb::Context;

let ctx = Context::new();
// Use "$ZCH" (instead of "$C") below as that will work in both M and UTF-8 modes (of "ydb_chset" env var)
// Note: Cannot use "$ZCHAR" below as "$ZCH" is the only input format recognized by "zwr2str()".
let out_buf = ctx.zwr2str(b"\"\xf0\"_$ZCH(159,146,150)")?;
assert_eq!(out_buf.as_slice(), "💖".as_bytes());

See also

pub fn lock(&self, timeout: Duration, locks: &[Key]) -> YDBResult<()>[src]

Acquires locks specified in locks and releases all others.

This operation is atomic. If any lock cannot be acquired, all locks are released. The timeout specifies the maximum time to wait before returning an error. If no locks are specified, all locks are released.

Note that YottaDB locks are per-process, not per-thread.

Limitations

For implementation reasons, there is a hard limit to the number of Keys that can be passed in locks:

  • 64-bit: 10 Keys
  • 32-bit: 9 Keys

If more than this number of keys are passed, lock_st will return YDB_ERR_MAXARGCNT.

For implementation reasons, lock_st only works on 64-bit platforms, or on 32-bit ARM.

lock_st will not be compiled on 16, 8, or 128 bit platforms (i.e. will fail with 'cannot find function lock_st in module yottadb::simple_api').

On non-ARM 32-bit platforms, the compiler will allow lock_st to be called, but it will have unspecified behavior and has not been tested. Use KeyContext::lock_incr and KeyContext::lock_decr instead.

Errors

Possible errors for this function include:

  • YDB_LOCK_TIMEOUT if all locks could not be acquired within the timeout period. In this case, no locks are acquired.
  • YDB_ERR_TIME2LONG if timeout is greater than YDB_MAX_TIME_NSEC
  • YDB_ERR_MAXARGCNT if too many locks have been passed (see Limitations)
  • error return codes

Examples

use std::slice;
use std::time::Duration;
use yottadb::{Context, KeyContext, Key, TpToken};

// You can use either a `Key` or a `KeyContext` to acquire a lock.
// This uses a `KeyContext` to show that you need to use `.key` to get the inner `Key`.
let ctx = Context::new();
let a = KeyContext::variable(&ctx, "lockA");

// Acquire a new lock
// using `from_ref` here allows us to use `a` later without moving it
ctx.lock(Duration::from_secs(1), slice::from_ref(&a.key)).unwrap();

// Acquire multiple locks
let locks = vec![a.key, Key::variable("lockB")];
ctx.lock(Duration::from_secs(1), &locks).unwrap();

// Release all locks
ctx.lock(Duration::from_secs(1), &[]).unwrap();

See also

impl Context[src]

Utility functions

pub fn message(&self, status: i32) -> YDBResult<Vec<u8>>[src]

Return the message corresponding to a YottaDB error code

Errors

  • YDB_ERR_UNKNOWNSYSERR if status is an unrecognized status code

See also

Example

Look up the error message for an undefined local variable:

use yottadb::{Context, KeyContext, TpToken, YDB_ERR_LVUNDEF};

let ctx = Context::new();
let key = KeyContext::variable(&ctx, "oopsNotDefined");

let err = key.get().unwrap_err();
assert_eq!(err.status, YDB_ERR_LVUNDEF);

let buf = ctx.message(err.status).unwrap();
let msg = String::from_utf8(buf).unwrap();
assert!(msg.contains("Undefined local variable"));

pub fn release(&self) -> YDBResult<String>[src]

Return a string in the format rustwr <rust wrapper version> <$ZYRELEASE>

$ZYRELEASE is the intrinsic variable containing the version of the underlying C database and <rust wrapper version> is the version of yottadb published to crates.io.

Errors

No errors should occur in normal operation. However, in case of system failure, an error code may be returned.

Example

use yottadb::Context;
let ctx = Context::new();
let release = ctx.release()?;

Trait Implementations

impl Clone for Context[src]

impl Debug for Context[src]

impl Default for Context[src]

impl Eq for Context[src]

impl PartialEq<Context> for Context[src]

impl StructuralEq for Context[src]

impl StructuralPartialEq for Context[src]

Auto Trait Implementations

impl !RefUnwindSafe for Context[src]

impl !Send for Context[src]

impl !Sync for Context[src]

impl Unpin for Context[src]

impl !UnwindSafe for Context[src]

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.