Monthly Archives: December 2017


The Tarantool SQL Alpha

Tarantool, a Lua application server plus NoSQL DBMS, is now an SQL DBMS too, in alpha version 1.8. I was interested in how the combination "Lua + NoSQL + SQL" works. Disclaimer: I do paid work related to Tarantool but it has nothing to do with this blog.

First let's verify that it's really SQL. The illustrations are all unretouched screenshots from ocelotgui for Windows, connected to a Tarantool 1.8 server on Linux, which I built from a source download on github.

Example of SELECT

tarantool2

Yes, the "history" below the query window shows successful CREATE and INSERT statements, the "result set" at the bottom shows a successful SELECT statement's output. A close look at the clauses shows that there's support for constraints, foreign keys, triggers, ... and so on. In all, it's a reasonable subset of the SQL standard, pretty well the same as what I found for SQLite in an earlier post.

That's not surprising because Tarantool started with SQLite's parser; however, the storage layer is Tarantool's NoSQL.

Combine Lua with SQL

Now it's time for the first "combination". I want to store and retrieve pictures, which are in .png and .jpg files. With MySQL/MariaDB I'd use load_file() but that's a built-in function that Tarantool doesn't have. Am I daunted? No, because I can write such a function in Lua -- or actually I can copy such a function because it's one of the examples in the Tarantool manual.

-- Lua function to set a variable to a file's contents
function load_file(file_name)
  local fio = require('fio')
  local errno = require('errno')
  local f = fio.open(file_name, {'O_RDONLY' })
  if not f then
    error("Failed to open file: "..errno.strerror())
  end
  local data = f:read(1000000)
  f:close()
  return data
end;

Not a difficult matter. As is clear from the display,
tarantool4
the function is syntactically okay (there would be squiggly red lines under the error if my Lua was bad). To explain the function: it says "read a file and return either an error message or the whole contents".

I can't call Lua functions directly from SQL yet, but I can do so from NoSQL, and with NoSQL I can INSERT into the same table that I created with SQL ...
box.space.timages:insert{1,load_file('shot1.jpg'),'shot1');
And then go back to SQL to handle the retrieval ...
SELECT * FROM "timages";
and the .jpg image is at the bottom of the screen.

So, although they're not standard SQL/PSM or Oracle-like PL/SQL, Tarantool does have server-side stored procedures.

Combine NoSQL With SQL

Now it's time for the second "combination". I want to read some NoSQL data that was not produced or populated with SQL in mind. Specifically we've got: a variable number of fields, some of which are unnamed, and they're not all scalar, there are arrays and structures. A typical tuple related to index metadata looks like this:

[[ Example of tuple ]]
  - [312, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]]
  - [312, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'unsigned']]]
  - [313, 0, 'primary', 'tree', {'unique': true}, [[1, 'unsigned'], [2, 'string'], [3, 'unsigned']]]
  - [313, 1, 'owner', 'tree', {'unique': false}, [[0, 'unsigned']]]
  - [313, 2, 'object', 'tree', {'unique': false}, [[2, 'string'], [3, 'unsigned']]]
  - [320, 0, 'primary', 'tree', {'unique': true}, [[0, 'unsigned']]]
  - [320, 1, 'uuid', 'tree', {'unique': true}, [[1, 'string']]]

For this I wrote some C code in the client instead of on the server, but I don't think that's cheating -- it doesn't show a Tarantool feature, but it does show that one can transfer the data into an SQL table and go from there. The syntax added to the client looks like this:

CREATE SERVER id FOREIGN DATA WRAPPER ocelot_tarantool
 OPTIONS (PORT 3301, HOST 'localhost', USER 'guest');
CREATE TABLE convertee SERVER id LUA 'return box.space._index:select()';
SELECT * FROM convertee;

The selection after converting looks like this:
tarantool6

(I'm changing the fonts and the window order now to make relevant parts look bigger.)

I wish I could call this "flattening", but that term has been hijacked for other concepts. Anyway, whatever it can be called, it's the reason that schemaless data doesn't need a new query language.

Things You Don't Always See Elsewhere

I'll mention a few things that are in Tarantool SQL that are not in MySQL/MariaDB, or are fairly new in MySQL/MariaDB. This short list does not mean Tarantool is "ahead", I'm talking about an alpha where many things are to-be-announced. I like to look at what's new and different.

COLLATE

tarantool8

The point isn't that there's a COLLATE clause, the point is that the collation is ICU. I've talked about the advantages of ICU earlier. The collation name will change soon, probably to 'unicode_s1' or 'unicode_ci'.

WITH

tarantool9

A non-recursive WITH clause is the same thing as a temporary view that lasts only for the statement that encloses it.
A recursive WITH clause is a temporary view that is populated by taking a seed (the query to the left of the UNION) and adding to it with a populator (the query to the right of the UNION), repeatedly, until some condition fails. I find it hard to understand, I suppose my problem is that this is procedural (a loop), and for procedural problems I prefer C or Lua or SQL/PSM.

EXCEPT and INTERSECT

SELECT * FROM "t" EXCEPT SELECT * FROM f;

These operators can fit in the same place as UNION, but have different effects. In the example, the EXCEPT would mean "take out the rows that match" instead of "add rows that do not match".

NaN and Inf

tarantool10

This is a differentiator, since in standard SQL and in some implementations these values are not supported, even though they're supported in IEEE 754.

CHECK

tarantool11

A constraint's effect is: "if the condition inside the parentheses is true or unknown, then and only then it is legal to have this row." This feature is also in MariaDB 10.2.1.

INDEXED BY

tarantool12

This is non-standard (and obviously always will be): you can force Tarantool to use a particular index, or no index at all, bypassing the optimizer.

VALUES

tarantool13

This means: return a result set containing a row with three columns containing 1, 2, 3. MySQL and MariaDB have a non-standard way to do this:
SELECT 1,2,3;
I like the logic of VALUES and the fact that I can say
VALUES (1,2,3),(4,5,6);
but Tarantool also supports the MySQL/MariaDB way, and I expect that it will always be more popular.

Game Changer?

Tarantool's aiming high and Tarantool's owner has a $9-billion market cap so the resources are there, but I'm not sure that Oracle sees them on its threat radar just yet. Tarantool SQL is not a drop-in replacement for all the code you've written for Oracle or MySQL/MariaDB, and the distinguishing features that I've mentioned are only going to cause a few people to migrate, at least in 2018. Other people will use Tarantool as an "add-on" or "engine".

I do see that this is close enough to SQLite that it will probably be reasonable to switch from there, if people need the extra multi-user / replication capabilities and the Lua integration and the speed (the main engine is an in-memory DBMS).

More dimly, I see some other NoSQL DBMSs looking bad compared to Tarantool because their SQL support is trivial by comparison. I'm thinking especially of the ones that already get beaten by Tarantool in YCSB tests of NoSQL performance.

Tarantool's licence is BSD.

Alphas Are Not Betas

Everything I've described above might change before Tarantool SQL is ready for use in production.

If you want to try to replicate the examples exactly, start with the old version-1.7 manual, move up to the SQL tutorial for version-1.8. The ocelotgui client additional instructions for connecting to Tarantool are here.

UPDATE: Tarantool's SQL feature is now part of Tarantool 2.0 instead of Tarantool 1.8. The SQL tutorial is now here. The instructions for connecting ocelotgui to Tarantool are the same as before, except for the change in version number.