Skip to content

Instantly share code, notes, and snippets.

@R-omk
Last active November 3, 2016 16:15
Show Gist options
  • Save R-omk/551dd0b77b563c3919c77a3f534810e4 to your computer and use it in GitHub Desktop.
Save R-omk/551dd0b77b563c3919c77a3f534810e4 to your computer and use it in GitHub Desktop.
tarantool get c function, get tuple with selected fields only remote:call('get' , 'spacename', fieldbitMask, 'key1')
#include "module.h"
#include "msgpuck.h"
int get(box_function_ctx_t *ctx, const char *args, const char *args_end) {
// primary index is 0
uint32_t index_id = 0;
uint32_t arg_count = mp_decode_array(&args);
uint32_t space_name_len;
const char *space_name;
// space name
space_name = mp_decode_str(&args, &space_name_len);
// space id
uint32_t space_id = box_space_id_by_name(space_name, space_name_len);
if (space_id == BOX_ID_NIL) {
box_error_raise(ER_PROC_C, "space not found");
return -1;
}
// read field bitmask
uint64_t bitmask = mp_decode_uint(&args);
uint32_t key_len;
const char *key;
box_tuple_t *tuple = NULL;
// get primary text key
key = mp_decode_str(&args, &key_len);
//load tuple by key
uint32_t len = mp_sizeof_array(1) +
mp_sizeof_str(key_len);
char *begin = (char *) box_txn_alloc(len);
if (begin == NULL) {
return -1;
}
char *end = NULL;
end = mp_encode_array(begin, 1);
end = mp_encode_str(end, key, key_len);
if (box_index_get(space_id, index_id, begin, end, &tuple) == -1) {
return -1;
}
if (tuple == NULL) {
return 0;
}
// tuple size
size_t tuple_bsize = box_tuple_bsize(tuple);
// buffer for msgpack from original tuple
char *orig_tuple_buf = (char *) box_txn_alloc(tuple_bsize);
// buffer for new tuple
char *new_tuple_buf = (char *) box_txn_alloc(tuple_bsize);
if (orig_tuple_buf == NULL || new_tuple_buf == NULL) {
return -1;
}
// write tuple to buffer
if (box_tuple_to_buf(tuple, orig_tuple_buf, tuple_bsize) == -1) {
return -1;
}
// read original msgpack
const char *orig_tuple_buf_cursor = orig_tuple_buf;
uint32_t field_count = mp_decode_array(&orig_tuple_buf_cursor);
const char *lastpos = orig_tuple_buf_cursor;
char *new_tuple_buf_cursor = new_tuple_buf;
uint32_t field_pos = 0;
uint32_t real_field_count = 0;
for (; field_pos < field_count; field_pos++) {
if (bitmask & (1 << field_pos)) {
real_field_count++;
}
}
// create msgpack array
new_tuple_buf_cursor = mp_encode_array(new_tuple_buf, real_field_count);
for (field_pos = 0; field_pos < field_count; field_pos++) {
// for next to calculate previous field size
mp_next(&orig_tuple_buf_cursor);
// write field to new tuple
if (bitmask & (1 << field_pos)) {
memcpy(new_tuple_buf_cursor, lastpos, orig_tuple_buf_cursor - lastpos);
new_tuple_buf_cursor = new_tuple_buf_cursor + (orig_tuple_buf_cursor - lastpos);
}
lastpos = orig_tuple_buf_cursor;
}
box_tuple_format_t *fmt = box_tuple_format_default();
box_tuple_t *newtuple = box_tuple_new(fmt, new_tuple_buf, new_tuple_buf_cursor);
if (newtuple == NULL) return -1;
return box_return_tuple(ctx, newtuple);
}
@R-omk
Copy link
Author

R-omk commented Aug 25, 2016

box.schema.space.create('get_test', { temporary = true })
box.space.get_test:create_index('primary', { type = 'TREE', parts = { 1, 'STR' }, if_not_exists = true })

box.schema.func.create('get', { language = 'C' })
box.schema.user.grant('guest', 'execute', 'function', 'get')

box.space.get_test:insert { 'key1', 'v1' }
box.space.get_test:insert { 'key2', 'v2' }
box.space.get_test:insert { 'key3', 'v3', 3 }

local net_box = require('net.box')
local capi_connection = net_box:new(3301)

capi_connection:call('get' , 'get_test', 3, "key1")
--   [['key1', 'v1']]

capi_connection:call('get' , 'get_test', 2, "key2")
--   [['v2']]

capi_connection:call('get' , 'get_test', 6, "key3")
--   [['v3', 3]]

capi_connection:call('get', 'get_test', 5, "key3")
--   [['key3', 3]]

capi_connection:call('get' , 'get_test', 0x00, "key3")
--   [[]]

capi_connection:call('get' , 'get_test', 0x00, "nokey")
--   []

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment