Programming in Lua

Programming YottaDB in Lua is provided by lua-yottadb, developed by Mitchell and sponsored by the University of Antwerp. We acknowledge their contribution and thank them for the value it adds to the YottaDB community.

lua-yottadb wraps the YottaDB Simple API to provide a Lua API.

Installation

The YottaDB Lua API requires a minimum YottaDB release of r1.32 and is tested with a minimum Lua version of 5.3.

If a different version of Lua is being used make sure to either modify the Makefile or pass CFLAGS=-I/path/to/lua to make, since the Makefile assumes that the Lua headers are installed at /usr/include/lua5.3.

$ sudo apt install lua5.4
$ sudo apt install liblua5.4-dev
$ git clone https://github.com/anet-be/lua-yottadb.git
$ cd lua-yottadb
$ sed -i 's/5.3/5.4/g' Makefile
$ sudo make install
$ make test
$

Lua API

Lua Wrapper Functions

data()

As a wrapper for ydb_data_s(), data() provides information about whether or not a global or local variable node has data and/or subtree.

data(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

Return value:

  • integer

Following are the possible return values:

  • 0.0 : there is neither a value nor a subtree; undefined variable node

  • 1.0 : there is a value but no subtree

  • 10.0 : there is no value but there is a subtree

  • 11.0 : there are both a value and a subtree

Example:

> ydb = require('yottadb')
> ydb.data('^Population')
10.0
> ydb.data('^Population', {'USA'})
11.0

To better understand the structure of the Population global variable node refer to the Concepts section. The Population global variable has been set as follows:

ydb.set('^Population', {'Belgium'}, 1367000)
ydb.set('^Population', {'Thailand'}, 8414000)
ydb.set('^Population', {'USA'}, 325737000)
ydb.set('^Population', {'USA', '17900802'}, 3929326)
ydb.set('^Population', {'USA', '18000804'}, 5308483)

delete_node()

As a wrapper for the C function ydb_delete_s(), delete_node() deletes a global or local variable node.

delete_node(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

Example:

> ydb = require('yottadb')
> ydb.set('^Population', {'Belgium'}, 1367000)
> ydb.delete_node('^Population', {'Belgium'})
> ydb.get('^Population', {'Belgium'})
nil

delete_tree()

As a wrapper for the C function ydb_delete_s(), delete_tree() deletes the entire global or local variable node tree.

delete_tree(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

Example:

> ydb = require('yottadb')
> ydb.get('^Population', {'USA'})
325737000
> ydb.get('^Population', {'USA', '17900802'})
3929326
> ydb.get('^Population', {'USA', '18000804'})
5308483
> ydb.delete_tree('^Population', {'USA'})
> ydb.data('^Population', {'USA'})
0.0

get()

As a wrapper for the C function ydb_get_s(), get() returns the value of a global or local variable node or an intrinsic variable.

get(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

Return value:

  • string or nil

The return value is nil if the variable node does not exist.

Example:

> ydb = require('yottadb')
> ydb.get('^Population')
nil
> ydb.get('^Population', {'Belgium'})
1367000
> ydb.get('$zgbldir')
/home/ydbuser/.yottadb/r1.34_x86_64/g/yottadb.gld

incr()

As a wrapper for the C function ydb_incr_s(), increment() increments the value in a global or local variable node.

incr(varname, subsarray, increment)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

  • increment : Optional string or number amount to increment by

The default value of increment parameter is one.

Return value:

  • incremented value

Example:

> ydb = require('yottadb')
> ydb.get('num')
4
> ydb.incr('num', 3)
7
> ydb.incr('num')
8

lock()

As a wrapper for the C function ydb_lock_s(), lock() releases any locks held by the process and attempts to acquire all the requested locks.

lock(keys, timeout)

Parameters:

  • keys : Optional list of variable nodes {varname[, subs]} to lock

  • timeout : Optional timeout in seconds to wait for the lock

The default value of timeout parameter is zero.

If keys is omitted then lock() just releases all the locks. The keys parameter refers to the YottaDB key object. For more information on the key object refer key() API function.

lock_decr()

As a wrapper for C function ydb_lock_decr_s, lock_decr() decrements the count of the specified lock held by the process, releasing it if the count goes to zero or ignoring the invocation if the process does not hold the lock.

lock_decr(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

lock_incr()

As a wrapper for the C function ydb_lock_incr_s(), lock_incr() attempts to acquire the requested lock without releasing any locks, incrementing the count if already held.

lock_incr(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

  • timeout : Optional timeout in seconds to wait for the lock

node_next()

As a wrapper for the C function ydb_node_next_s(), node_next() returns the next global or local variable node.

node_next(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

Return value:

  • list or nil

The return value is nil if there is no next node.

Example:

> ydb = require('yottadb')
> print(table.concat(ydb.node_next('^Population'), ', '))
Belgium
> print(table.concat(ydb.node_next('^Population', {'Belgium'}), ', '))
Thailand
> print(table.concat(ydb.node_next('^Population', {'Thailand'}), ', '))
USA
> print(table.concat(ydb.node_next('^Population', {'USA'}), ', '))
USA, 17900802
> print(table.concat(ydb.node_next('^Population', {'USA', '17900802'}), ', '))
USA, 18000804

Note

The format used above to print the next node will give an error if there is no next node, i.e., the value returned is nil. This case will have to be handled gracefully. The following code snippet is one way to handle nil as the return value:
local ydb = require('yottadb')

next = ydb.node_next('^Population', {'USA', '18000804'})

if next ~= nil then
   print(table.concat(next, ', '))
else
   print(next)
end

node_previous()

As a wrapper for the C function ydb_node_previous_s(), node_previous() returns the previous global or local variable node.

node_previous(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

Return value:

  • list or nil

The return value is nil if there is no previous node.

Example:

> ydb = require('yottadb')
> print(table.concat(ydb.node_previous('^Population', {'USA', '18000804'}), ', '))
USA, 17900802
> print(table.concat(ydb.node_previous('^Population', {'USA', '17900802'}), ', '))
USA
> print(table.concat(ydb.node_previous('^Population', {'USA'}), ', '))
Thailand
> print(table.concat(ydb.node_previous('^Population', {'Thailand'}), ', '))
Belgium

Note

The note on handling nil return values in node_next() applies to node_previous() as well.

set()

As a wrapper for the C function ydb_set_s(), set() sets the value of the global variable node, local variable node or intrinsic special variable.

set(varname, subsarray, value)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

  • value : String value to set, if number is provided it is converted to a string

Example:

> ydb = require('yottadb')
> ydb.set('^Population', {'Belgium'}, 1367000)
> ydb.set('^Population', {'Thailand'}, 8414000)
> ydb.set('^Population', {'USA'}, 325737000)
> ydb.set('^Population', {'USA', '17900802'}, 3929326)
> ydb.set('^Population', {'USA', '18000804'}, 5308483)

str2zwr()

As a wrapper for the C function ydb_str2zwr_s(), str2zwr() returns the zwrite formatted version of the string provided.

strzwr(s)

Parameters:

  • s: String to format

Return value:

  • zwrite formatted string

Example:

> ydb=require('yottadb')
> str='The quick brown dog\b\b\bfox jumps over the lazy fox\b\b\bdog.'
> print(str)
The quick brown fox jumps over the lazy dog.
> ydb.str2zwr(str)
"The quick brown dog"_$C(8,8,8)_"fox jumps over the lazy fox"_$C(8,8,8)_"dog."

In the above example the escape sequence b (backspace) is used.

subscript_next()

As a wrapper for the C function ydb_subscript_next_s(), subscript_next() returns the next subscript, at the same level, of a global or local variable node.

subscript_next(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

Return value:

  • string (subscript name) or nil

The return value is nil if there is no next subscript.

Example:

> ydb=require('yottadb')
> ydb.subscript_next('^Population', {''})
Belgium
> ydb.subscript_next('^Population', {'Belgium'})
Thailand
> ydb.subscript_next('^Population', {'Thailand'})
USA

subscript_previous()

As a wrapper for the C function ydb_subscript_previous_s(), subscript_previous() returns the previous subscript, at the same level, of a global or local variable node.

subscript_previous(varname, subsarray)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

Return value:

  • string (subscript name) or nil

The return value is nil if there is no previous subscript.

Example:

> ydb=require('yottadb')
> ydb.subscript_previous('^Population', {'USA', ''})
18000804
> ydb.subscript_previous('^Population', {'USA', '18000804'})
17900802
> ydb.subscript_previous('^Population', {'USA', '17900802'})
nil
> ydb.subscript_previous('^Population', {'USA'})
Thailand
>

tp()

As a wrapper for the C function ydb_tp_s() , it provides support for full ACID transactions.

tp(id, varnames, f, ...)

Parameters:

  • id : Optional string transaction id

  • varnames : Optional list of variable names to restore on transaction restart

  • f : Function to call

  • … : Optional arguments to pass to f

Example:

local ydb = require('yottadb')

function transfer_to_savings(t)
   local ok, e = pcall(ydb.incr, '^checking', -t)
   if (ydb.get_error_code(e) == ydb.YDB_TP_RESTART) then
      return ydb.YDB_TP_RESTART
   end
   if (not ok or tonumber(e)<0) then
      return ydb.YDB_TP_ROLLBACK
   end
   local ok, e = pcall(ydb.incr, '^savings', t)
   if (ydb.get_error_code(e) == ydb.YDB_TP_RESTART) then
      return ydb.YDB_TP_RESTART
   end
   if (not ok) then
      return ydb.YDB_TP_ROLLBACK
   end
   return ydb.YDB_OK
end

ydb.set('^checking', 200)
ydb.set('^savings', 85000)

print("Amount currently in checking account: $" .. ydb.get('^checking'))
print("Amount currently in savings account: $" .. ydb.get('^savings'))

print("Transferring $10 from checking to savings")
local ok, e = pcall(ydb.tp, '', {'*'}, transfer_to_savings, 10)
if (not e) then
   print("Transfer successful")
elseif (ydb.get_error_code(e) == ydb.YDB_TP_ROLLBACK) then
   print("Transfer not possible. Insufficient funds")
end

print("Amount in checking account: $" .. ydb.get('^checking'))
print("Amount in savings account: $" .. ydb.get('^savings'))

print("Transferring $1000 from checking to savings")
local ok, e = pcall(ydb.tp, '', {'*'}, transfer_to_savings, 1000)
if (not e) then
   print("Transfer successful")
elseif (ydb.get_error_code(e) == ydb.YDB_TP_ROLLBACK) then
   print("Transfer not possible. Insufficient funds")
end

print("Amount in checking account: $" .. ydb.get('^checking'))
print("Amount in savings account: $" .. ydb.get('^savings'))

Output:

Amount currently in checking account: $200
Amount currently in savings account: $85000
Transferring $10 from checking to savings
Transfer successful
Amount in checking account: $190
Amount in savings account: $85010
Transferring $1000 from checking to savings
Transfer not possible. Insufficient funds
Amount in checking account: $190
Amount in savings account: $85010

Note

When using the tp() function, restarts and rollbacks need to be handled appropriately.

zwr2str()

As a wrapper for the C function ydb_zwr2str_s(), zwr2str() provides the string format of the zwrite formatted string.

zwr2str(s)

Parameters:

  • s : String in zwrite format

Return value:

  • string

Example:

> ydb=require('yottadb')
> str1='The quick brown dog\b\b\bfox jumps over the lazy fox\b\b\bdog.'
> zwr_str=ydb.str2zwr(str1)
> print(zwr_str)
"The quick brown dog"_$C(8,8,8)_"fox jumps over the lazy fox"_$C(8,8,8)_"dog."
> str2=ydb.zwr2str(zwr_str)
> print(str2)
The quick brown fox jumps over the lazy dog.
> str1==str2
true
>

Other API Functions

get_error_code()

Returns the YottaDB error code (if any) for the given error message.

get_error_code(message)

Parameters:

  • message : String error message

Return value:

  • numeric YottaDB error code or nil

The return value is nil if the message is not a YDB error.

get_error_code() expects the error message string to start with YDB Error:.

Example:

> ydb=require('yottadb')
> ydb.get_error_code('YDB Error: -150374122: %YDB-E-ZGBLDIRACC, Cannot access global directory !AD!AD!AD.')
-150374122

key()

Creates and returns a new YottaDB key object.

Parameters:

  • varname : String variable name

Return value:

  • key

The YottaDB object key has the following fields available:

  • name : key’s subscript or variable name

  • value : key’s value in the YottaDB database

  • data : refer data()

  • has_value : checks whether or not the key has a value

  • has_tree : checks whether or not the key has a subtree

The YottaDB key object can access other API functions in the following manner, key:func().

Example:

> ydb=require('yottadb')
> belgium = ydb.key('^Population')('Belgium')
> belgium.value
1367000
> thailand = ydb.key('^Population')('Thailand')
> thailand.value
8414000
> usa = ydb.key('^Population')('USA')
> usa.value
325737000
> print(usa.has_tree)
true
> for val in usa(''):subscripts() do
>> print(val)
>> end
17900802
18000804

nodes()

Returns an iterator for iterating over all the nodes of a global or local variable node.

nodes(varname, subsarray, reverse)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

  • reverse : Optional flag that indicates whether to iterate backwards. The default value is false.

Return value:

  • iterator

Example:

> ydb=require('yottadb')
> for nodes in ydb.nodes('^Population') do
>> print(table.concat(nodes, ', '))
>> end
Belgium
Thailand
USA
USA, 17900802
USA, 18000804
> for usa_nodes in ydb.nodes('^Population', {'USA'}) do
>> print(table.concat(usa_nodes, ', '))
>> end
USA, 17900802
USA, 18000804

subscripts()

Returns an iterator for iterating over all subscripts in a global or local variable node.

subscripts(varname, subsarray, reverse)

Parameters:

  • varname : String variable name

  • subsarray : Optional list of subscripts

  • reverse : Optional flag that indicates whether to iterate backwards. The default value is false.

Return value:

  • iterator

Example:

> ydb=require('yottadb')
> for subs in ydb.subscripts('^Population', {''}) do
>> print(subs)
>> end
Belgium
Thailand
USA
> for subs in ydb.subscripts('^Population', {'USA', ''}) do
>> print(subs)
>> end
17900802
18000804
>

transaction()

Returns a transaction-safe version of the given functions such that it can be called with YottaDB Transaction Processing.

transaction(f)

Parameters:

  • f : Function to convert

The transaction is committed if the function returns nothing or yottadb.YDB_OK, restarted if the function returns yottadb.YDB_TP_RESTART (f will be called again), or not committed if the function returns yottadb.YDB_TP_ROLLBACK or errors.

Return value:

  • transaction-safe function