[tarantool-patches] [PATCH 3/4] sql: simplify lua SQL executor
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Tue Apr 3 18:34:14 MSK 2018
1) Code is completely unreadable and complicated by strange
optimizations;
2) It still supposes, that there can be multiple statements in a
single string;
3) It pushes first letter of affinity together with column names
- why? It is not used anywhere.
Lets remove prepared statements list, affinity first letters
pushing.
---
src/box/lua/sql.c | 239 ++++++++----------------------------------------------
1 file changed, 35 insertions(+), 204 deletions(-)
diff --git a/src/box/lua/sql.c b/src/box/lua/sql.c
index 12b81383d..e693aeaad 100644
--- a/src/box/lua/sql.c
+++ b/src/box/lua/sql.c
@@ -6,132 +6,12 @@
#include "lua/utils.h"
#include "info.h"
-struct prep_stmt
-{
- sqlite3_stmt *stmt;
-};
-
-struct prep_stmt_list
-{
- uint8_t *mem_end; /* denotes actual size of sql_ctx struct */
- uint32_t pool_size; /* mem at the end used for aux allocations;
- pool grows from mem_end
- towards stmt[] array */
- uint32_t last_select_stmt_index; /* UINT32_MAX if no selects */
- uint32_t column_count; /* in last select stmt */
- uint32_t stmt_count;
- struct prep_stmt stmt[6]; /* overlayed with the mem pool;
- actual size could be larger or smaller */
- /* uint8_t mem_pool[] */
-};
-
-static inline int
-prep_stmt_list_needs_free(struct prep_stmt_list *l)
-{
- return (uint8_t *)(l + 1) != l->mem_end;
-}
-
-/* Release resources and free the list itself, unless it was preallocated
- * (i.e. l points to an automatic variable) */
-static void
-prep_stmt_list_free(struct prep_stmt_list *l)
-{
- if (l == NULL)
- return;
- for (size_t i = 0, n = l->stmt_count; i < n; i++)
- sqlite3_finalize(l->stmt[i].stmt);
- if (prep_stmt_list_needs_free(l))
- free(l);
-}
-
-static struct prep_stmt_list *
-prep_stmt_list_init(struct prep_stmt_list *prealloc)
-{
- prealloc->mem_end = (uint8_t *)(prealloc + 1);
- prealloc->pool_size = 0;
- prealloc->last_select_stmt_index = UINT32_MAX;
- prealloc->column_count = 0;
- prealloc->stmt_count = 0;
- return prealloc;
-}
-
-/* Allocate mem from the prep_stmt_list pool.
- * If not enough space is available, reallocates the list.
- * If reallocation is needed but l was preallocated, old mem is left
- * intact and a new memory chunk is allocated. */
-static void *
-prep_stmt_list_palloc(struct prep_stmt_list **pl,
- size_t size, size_t alignment)
-{
- assert((alignment & (alignment - 1)) == 0); /* 2 ^ k */
- assert(alignment <= __alignof__((*pl)->stmt[0]));
-
- struct prep_stmt_list *l = *pl;
- uint32_t pool_size = l->pool_size;
- uint32_t pool_size_max = (uint32_t)(
- l->mem_end - (uint8_t *)(l->stmt + l->stmt_count)
- );
-
- assert(UINT32_MAX - pool_size >= size);
- pool_size += size;
-
- assert(UINT32_MAX - pool_size >= alignment - 1);
- pool_size += alignment - 1;
- pool_size &= ~(alignment - 1);
-
- if (pool_size > pool_size_max) {
- size_t prev_size = l->mem_end - (uint8_t *)l;
- size_t size = prev_size;
- while (size < prev_size + (pool_size - pool_size_max)) {
- assert(SIZE_MAX - size >= size);
- size += size;
- }
- if (prep_stmt_list_needs_free(l)) {
- l = realloc(l, size);
- if (l == NULL)
- return NULL;
- } else {
- l = malloc(size);
- if (l == NULL)
- return NULL;
- memcpy(l, *pl, prev_size);
- }
- l->mem_end = (uint8_t *)l + size;
- /* move the pool data */
- memmove((uint8_t *)l + prev_size - l->pool_size,
- l->mem_end - l->pool_size,
- l->pool_size);
- *pl = l;
- }
-
- l->pool_size = pool_size;
- return l->mem_end - pool_size;
-}
-
-/* push new stmt; reallocate memory if needed
- * returns a pointer to the new stmt or NULL if out of memory.
- * If reallocation is needed but l was preallocated, old mem is left
- * intact and a new memory chunk is allocated. */
-static struct prep_stmt *
-prep_stmt_list_push(struct prep_stmt_list **pl)
-{
- struct prep_stmt_list *l;
- /* make sure we don't collide with the pool */
- if (prep_stmt_list_palloc(pl, sizeof(l->stmt[0]), 1
- ) == NULL)
- return NULL;
- l = *pl;
- l->pool_size -= sizeof(l->stmt[0]);
- return l->stmt + (l->stmt_count++);
-}
-
static void
-lua_push_column_names(struct lua_State *L, struct prep_stmt_list *l)
+lua_push_column_names(struct lua_State *L, struct sqlite3_stmt *stmt)
{
- sqlite3_stmt *stmt = l->stmt[l->last_select_stmt_index].stmt;
- int n = l->column_count;
- lua_createtable(L, n, 0);
- for (int i = 0; i < n; i++) {
+ int column_count = sqlite3_column_count(stmt);
+ lua_createtable(L, column_count, 0);
+ for (int i = 0; i < column_count; i++) {
const char *name = sqlite3_column_name(stmt, i);
lua_pushstring(L, name == NULL ? "" : name);
lua_rawseti(L, -2, i+1);
@@ -139,11 +19,9 @@ lua_push_column_names(struct lua_State *L, struct prep_stmt_list *l)
}
static void
-lua_push_row(struct lua_State *L, struct prep_stmt_list *l)
+lua_push_row(struct lua_State *L, struct sqlite3_stmt *stmt)
{
- sqlite3_stmt *stmt = l->stmt[l->last_select_stmt_index].stmt;
- int column_count = l->column_count;
- char *typestr = (void *)(l->mem_end - column_count);
+ int column_count = sqlite3_column_count(stmt);
lua_createtable(L, column_count, 0);
lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_array_metatable_ref);
@@ -153,124 +31,77 @@ lua_push_row(struct lua_State *L, struct prep_stmt_list *l)
int type = sqlite3_column_type(stmt, i);
switch (type) {
case SQLITE_INTEGER:
- typestr[i] = 'i';
- luaL_pushint64(L, sqlite3_column_int64(stmt, i));
+ luaL_pushint64(L, sqlite3_column_int64(stmt, i));
break;
case SQLITE_FLOAT:
- typestr[i] = 'f';
lua_pushnumber(L, sqlite3_column_double(stmt, i));
break;
case SQLITE_TEXT: {
const void *text = sqlite3_column_text(stmt, i);
- typestr[i] = 's';
lua_pushlstring(L, text,
sqlite3_column_bytes(stmt, i));
break;
}
case SQLITE_BLOB: {
const void *blob = sqlite3_column_blob(stmt, i);
- typestr[i] = 'b';
lua_pushlstring(L, blob,
sqlite3_column_bytes(stmt, i));
break;
}
case SQLITE_NULL:
- typestr[i] = '-';
lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_nil_ref);
break;
default:
- typestr[i] = '?';
assert(0);
}
lua_rawseti(L, -2, i+1);
}
-
- lua_pushlstring(L, typestr, column_count);
- lua_rawseti(L, -2, 0);
}
static int
lua_sql_execute(struct lua_State *L)
{
- int rc;
sqlite3 *db = sql_get();
- struct prep_stmt_list *l = NULL, stock_l;
- size_t length;
- const char *sql, *sql_end;
-
if (db == NULL)
return luaL_error(L, "not ready");
- sql = lua_tolstring(L, 1, &length);
+ size_t length;
+ const char *sql = lua_tolstring(L, 1, &length);
if (sql == NULL)
return luaL_error(L, "usage: box.sql.execute(sqlstring)");
- assert(length <= INT_MAX);
- sql_end = sql + length;
+ struct sqlite3_stmt *stmt;
+ if (sqlite3_prepare_v2(db, sql, length, &stmt, &sql) != SQLITE_OK)
+ goto sqlerror;
+ assert(stmt != NULL);
- l = prep_stmt_list_init(&stock_l);
- do {
-
- struct prep_stmt *ps = prep_stmt_list_push(&l);
- if (ps == NULL)
- goto outofmem;
- rc = sqlite3_prepare_v2(db, sql, (int)(sql_end - sql),
- &ps->stmt, &sql);
- if (rc != SQLITE_OK)
- goto sqlerror;
-
- if (ps->stmt == NULL) {
- /* only whitespace */
- assert(sql == sql_end);
- l->stmt_count --;
- break;
- }
-
- int column_count = sqlite3_column_count(ps->stmt);
- if (column_count == 0) {
- while ((rc = sqlite3_step(ps->stmt)) == SQLITE_ROW) { ; }
- } else {
- char *typestr;
- l->column_count = column_count;
- l->last_select_stmt_index = l->stmt_count - 1;
-
- assert(l->pool_size == 0);
- /* This might possibly call realloc() and ruin *ps. */
- typestr = prep_stmt_list_palloc(&l, column_count, 1);
- if (typestr == NULL)
- goto outofmem;
- /* Refill *ps. */
- ps = l->stmt + l->stmt_count - 1;
-
- lua_settop(L, 1); /* discard any results */
-
- /* create result table */
- lua_createtable(L, 7, 0);
- lua_pushvalue(L, lua_upvalueindex(1));
- lua_setmetatable(L, -2);
- lua_push_column_names(L, l);
- lua_rawseti(L, -2, 0);
-
- int row_count = 0;
- while ((rc = sqlite3_step(ps->stmt)) == SQLITE_ROW) {
- lua_push_row(L, l);
- row_count++;
- lua_rawseti(L, -2, row_count);
- }
- l->pool_size = 0;
+ int rc;
+ int retval_count;
+ if (sqlite3_column_count(stmt) == 0) {
+ while ((rc = sqlite3_step(stmt)) == SQLITE_ROW);
+ retval_count = 0;
+ } else {
+ lua_newtable(L);
+ lua_pushvalue(L, lua_upvalueindex(1));
+ lua_setmetatable(L, -2);
+ lua_push_column_names(L, stmt);
+ lua_rawseti(L, -2, 0);
+
+ int row_count = 0;
+ while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
+ lua_push_row(L, stmt);
+ lua_rawseti(L, -2, ++row_count);
}
+ retval_count = 1;
+ }
if (rc != SQLITE_OK && rc != SQLITE_DONE)
- goto sqlerror;
- } while (sql != sql_end);
- prep_stmt_list_free(l);
- return lua_gettop(L) - 1;
+ goto sqlerror;
+ sqlite3_finalize(stmt);
+ return retval_count;
sqlerror:
lua_pushstring(L, sqlite3_errmsg(db));
- prep_stmt_list_free(l);
+ sqlite3_finalize(stmt);
return lua_error(L);
-outofmem:
- prep_stmt_list_free(l);
- return luaL_error(L, "out of memory");
}
static int
--
2.14.3 (Apple Git-98)
More information about the Tarantool-patches
mailing list