diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/common.c luadbi/dbd/common.c --- lua-dbi-0.5/dbd/common.c 2009-06-13 04:50:59.000000000 -0400 +++ luadbi/dbd/common.c 2015-01-15 13:38:28.163032130 -0500 @@ -52,9 +52,12 @@ /* * allocate a new string for the converted SQL statement */ - newsql = malloc(sizeof(char) * (len+extra_space+1)); - memset(newsql, 0, sizeof(char) * (len+extra_space+1)); - + newsql = calloc(len+extra_space+1, sizeof(char)); + if(!newsql) { + lua_pushliteral(L, "out of memory"); + return lua_error(L); + } + /* * copy first char. In valid SQL this cannot be a placeholder */ diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/common.h luadbi/dbd/common.h --- lua-dbi-0.5/dbd/common.h 2010-05-01 00:25:11.000000000 -0400 +++ luadbi/dbd/common.h 2015-01-15 13:38:28.163032130 -0500 @@ -39,6 +39,11 @@ lua_pushnumber(L, v); \ lua_rawset(L, -3); +#define LUA_PUSH_ATTRIB_STRING_BY_LENGTH(n, v, len) \ + lua_pushstring(L, n); \ + lua_pushlstring(L, v, len); \ + lua_rawset(L, -3); + #define LUA_PUSH_ATTRIB_STRING(n, v) \ lua_pushstring(L, n); \ lua_pushstring(L, v); \ @@ -71,6 +76,11 @@ lua_rawseti(L, -2, n); \ n++; +#define LUA_PUSH_ARRAY_STRING_BY_LENGTH(n, v, len) \ + lua_pushlstring(L, v, len); \ + lua_rawseti(L, -2, n); \ + n++; + #define LUA_PUSH_ARRAY_BOOL(n, v) \ lua_pushboolean(L, v); \ lua_rawseti(L, -2, n); \ diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/mysql/connection.c luadbi/dbd/mysql/connection.c --- lua-dbi-0.5/dbd/mysql/connection.c 2010-05-01 00:25:12.000000000 -0400 +++ luadbi/dbd/mysql/connection.c 2015-01-15 13:38:28.171032087 -0500 @@ -16,7 +16,7 @@ const char *db = NULL; int port = 0; - const char *unix_socket = NULL; /* TODO always NULL */ + const char *unix_socket = NULL; int client_flag = 0; /* TODO always 0, set flags from options table */ /* db, user, password, host, port */ @@ -27,6 +27,10 @@ case 4: if (lua_isnil(L, 4) == 0) host = luaL_checkstring(L, 4); + if (host[0] == '/') { + unix_socket = host; + host = NULL; + }; case 3: if (lua_isnil(L, 3) == 0) password = luaL_checkstring(L, 3); @@ -178,6 +182,16 @@ } /* + * last_id = statement:last_id() + */ +static int connection_lastid(lua_State *L) { + connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION); + + lua_pushinteger(L, mysql_insert_id( conn->mysql )); + return 1; +} + +/* * __gc */ static int connection_gc(lua_State *L) { @@ -207,6 +221,7 @@ {"prepare", connection_prepare}, {"quote", connection_quote}, {"rollback", connection_rollback}, + {"last_id", connection_lastid}, {NULL, NULL} }; diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/mysql/dbd_mysql.h luadbi/dbd/mysql/dbd_mysql.h --- lua-dbi-0.5/dbd/mysql/dbd_mysql.h 2010-05-01 00:25:12.000000000 -0400 +++ luadbi/dbd/mysql/dbd_mysql.h 2015-01-15 13:38:28.172032081 -0500 @@ -22,6 +22,10 @@ typedef struct _statement { MYSQL *mysql; MYSQL_STMT *stmt; - MYSQL_RES *metadata; /* result dataset metadata */ + MYSQL_RES *metadata; /* result dataset metadata */ + + unsigned long *lengths; /* length of retrieved data + we have to keep this from bind time to + result retrival time */ } statement_t; diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/mysql/statement.c luadbi/dbd/mysql/statement.c --- lua-dbi-0.5/dbd/mysql/statement.c 2010-05-21 18:49:59.000000000 -0400 +++ luadbi/dbd/mysql/statement.c 2015-01-15 13:38:28.173032076 -0500 @@ -11,10 +11,12 @@ case MYSQL_TYPE_TINY: case MYSQL_TYPE_YEAR: case MYSQL_TYPE_SHORT: - case MYSQL_TYPE_LONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_LONG: lua_type = LUA_PUSH_INTEGER; break; + case MYSQL_TYPE_FLOAT: case MYSQL_TYPE_DOUBLE: case MYSQL_TYPE_LONGLONG: lua_type = LUA_PUSH_NUMBER; @@ -89,13 +91,18 @@ statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); if (statement->metadata) { - mysql_free_result(statement->metadata); - statement->metadata = NULL; + mysql_free_result(statement->metadata); + statement->metadata = NULL; } + if (statement->lengths) { + free(statement->lengths); + statement->lengths = NULL; + } + if (statement->stmt) { - mysql_stmt_close(statement->stmt); - statement->stmt = NULL; + mysql_stmt_close(statement->stmt); + statement->stmt = NULL; } lua_pushboolean(L, 1); @@ -286,7 +293,7 @@ } static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { - int column_count; + int column_count, fetch_result_ok; MYSQL_BIND *bind = NULL; const char *error_message = NULL; @@ -306,6 +313,13 @@ int i; MYSQL_FIELD *fields; + if (statement->lengths) { + free(statement->lengths); + statement->lengths = NULL; + } + + statement->lengths = calloc(column_count, sizeof(unsigned long)); + bind = malloc(sizeof(MYSQL_BIND) * column_count); memset(bind, 0, sizeof(MYSQL_BIND) * column_count); @@ -313,12 +327,19 @@ for (i = 0; i < column_count; i++) { unsigned int length = mysql_buffer_size(&fields[i]); - char *buffer = (char *)malloc(length); - memset(buffer, 0, length); + if (length > sizeof(MYSQL_TIME)) { + bind[i].buffer = NULL; + bind[i].buffer_length = 0; + } else { + char *buffer = (char *)malloc(length); + memset(buffer, 0, length); + + bind[i].buffer = buffer; + bind[i].buffer_length = length; + } bind[i].buffer_type = fields[i].type; - bind[i].buffer = buffer; - bind[i].buffer_length = length; + bind[i].length = &(statement->lengths[i]); } if (mysql_stmt_bind_result(statement->stmt, bind)) { @@ -326,7 +347,8 @@ goto cleanup; } - if (!mysql_stmt_fetch(statement->stmt)) { + fetch_result_ok = mysql_stmt_fetch(statement->stmt); + if (fetch_result_ok == 0 || fetch_result_ok == MYSQL_DATA_TRUNCATED) { int d = 1; lua_newtable(L); @@ -334,6 +356,13 @@ lua_push_type_t lua_push = mysql_to_lua_push(fields[i].type); const char *name = fields[i].name; + if (bind[i].buffer == NULL) { + char *buffer = (char *)calloc(statement->lengths[i]+1, sizeof(char)); + bind[i].buffer = buffer; + bind[i].buffer_length = statement->lengths[i]; + mysql_stmt_fetch_column(statement->stmt, &bind[i], i, 0); + } + if (lua_push == LUA_PUSH_NIL) { if (named_columns) { LUA_PUSH_ATTRIB_NIL(name); @@ -361,11 +390,25 @@ } } } else if (lua_push == LUA_PUSH_NUMBER) { - if (named_columns) { - LUA_PUSH_ATTRIB_FLOAT(name, *(double *)(bind[i].buffer)); - } else { - LUA_PUSH_ARRAY_FLOAT(d, *(double *)(bind[i].buffer)); - } + if (fields[i].type == MYSQL_TYPE_FLOAT) { + if (named_columns) { + LUA_PUSH_ATTRIB_FLOAT(name, *(float *)(bind[i].buffer)); + } else { + LUA_PUSH_ARRAY_FLOAT(d, *(float *)(bind[i].buffer)); + } + } else if (fields[i].type == MYSQL_TYPE_DOUBLE) { + if (named_columns) { + LUA_PUSH_ATTRIB_FLOAT(name, *(double *)(bind[i].buffer)); + } else { + LUA_PUSH_ARRAY_FLOAT(d, *(double *)(bind[i].buffer)); + } + } else { + if (named_columns) { + LUA_PUSH_ATTRIB_FLOAT(name, *(long long *)(bind[i].buffer)); + } else { + LUA_PUSH_ARRAY_FLOAT(d, *(long long *)(bind[i].buffer)); + } + } } else if (lua_push == LUA_PUSH_STRING) { if (fields[i].type == MYSQL_TYPE_TIMESTAMP || fields[i].type == MYSQL_TYPE_DATETIME) { @@ -404,9 +447,9 @@ } else { if (named_columns) { - LUA_PUSH_ATTRIB_STRING(name, bind[i].buffer); + LUA_PUSH_ATTRIB_STRING_BY_LENGTH(name, bind[i].buffer, *bind[i].length); } else { - LUA_PUSH_ARRAY_STRING(d, bind[i].buffer); + LUA_PUSH_ARRAY_STRING_BY_LENGTH(d, bind[i].buffer, *bind[i].length); } } } else if (lua_push == LUA_PUSH_BOOLEAN) { @@ -425,6 +468,7 @@ } cleanup: + if (bind) { int i; @@ -535,6 +579,7 @@ statement->mysql = conn->mysql; statement->stmt = stmt; statement->metadata = NULL; + statement->lengths = NULL; /* mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (my_bool*)0); diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/postgresql/connection.c luadbi/dbd/postgresql/connection.c --- lua-dbi-0.5/dbd/postgresql/connection.c 2010-05-01 00:25:12.000000000 -0400 +++ luadbi/dbd/postgresql/connection.c 2015-01-15 13:38:28.176032059 -0500 @@ -109,10 +109,12 @@ int err = 0; if (conn->postgresql) { - if (on) - err = rollback(conn); - else - err = begin(conn); + if (on != conn->autocommit) { + if (on) + err = rollback(conn); + else + err = begin(conn); + } conn->autocommit = on; } diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/postgresql/dbd_postgresql.h luadbi/dbd/postgresql/dbd_postgresql.h --- lua-dbi-0.5/dbd/postgresql/dbd_postgresql.h 2010-05-01 00:25:12.000000000 -0400 +++ luadbi/dbd/postgresql/dbd_postgresql.h 2015-01-15 13:38:28.176032059 -0500 @@ -1,5 +1,4 @@ #include -#include #include /* diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/sqlite3/connection.c luadbi/dbd/sqlite3/connection.c --- lua-dbi-0.5/dbd/sqlite3/connection.c 2010-05-01 00:25:12.000000000 -0400 +++ luadbi/dbd/sqlite3/connection.c 2015-01-15 13:38:28.178032048 -0500 @@ -9,19 +9,33 @@ } static int commit(connection_t *conn) { - return run(conn, "COMMIT"); + return run(conn, "COMMIT TRANSACTION"); } static int begin(connection_t *conn) { - return run(conn, "BEGIN"); -} + int err = 0; + if (sqlite3_get_autocommit(conn->sqlite)) { + err = run(conn, "BEGIN TRANSACTION"); + } else { + err = 0; + } + + return err; +} static int rollback(connection_t *conn) { - return run(conn, "ROLLBACK"); + return run(conn, "ROLLBACK TRANSACTION"); } +int try_begin_transaction(connection_t *conn) { + if (conn->autocommit) { + return 1; + } + + return begin(conn) == 0; +} /* * connection,err = DBD.SQLite3.New(dbfile) @@ -50,7 +64,6 @@ } conn->autocommit = 0; - begin(conn); luaL_getmetatable(L, DBD_SQLITE_CONNECTION); lua_setmetatable(L, -2); @@ -67,10 +80,9 @@ int err = 1; if (conn->sqlite) { - if (on) + if (on) { err = rollback(conn); - else - err = begin(conn); + } conn->autocommit = on; } @@ -88,6 +100,7 @@ int disconnect = 0; if (conn->sqlite) { + rollback(conn); sqlite3_close(conn->sqlite); disconnect = 1; conn->sqlite = NULL; @@ -105,12 +118,7 @@ int err = 1; if (conn->sqlite) { - commit(conn); - - if (!conn->autocommit) - err = begin(conn); - else - err = 1; + err = commit(conn); } lua_pushboolean(L, !err); @@ -176,12 +184,7 @@ int err = 1; if (conn->sqlite) { - rollback(conn); - - if (!conn->autocommit) - err = begin(conn); - else - err = 1; + err =rollback(conn); } lua_pushboolean(L, !err); diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/sqlite3/dbd_sqlite3.h luadbi/dbd/sqlite3/dbd_sqlite3.h --- lua-dbi-0.5/dbd/sqlite3/dbd_sqlite3.h 2008-12-19 01:33:32.000000000 -0500 +++ luadbi/dbd/sqlite3/dbd_sqlite3.h 2015-01-15 13:38:28.178032048 -0500 @@ -10,14 +10,15 @@ typedef struct _connection { sqlite3 *sqlite; int autocommit; +// int txn_in_progress; } connection_t; /* * statement object */ typedef struct _statement { + connection_t *conn; sqlite3_stmt *stmt; - sqlite3 *sqlite; int more_data; int affected; } statement_t; diff -urP '--exclude=.hg' lua-dbi-0.5/dbd/sqlite3/statement.c luadbi/dbd/sqlite3/statement.c --- lua-dbi-0.5/dbd/sqlite3/statement.c 2010-05-01 00:25:12.000000000 -0400 +++ luadbi/dbd/sqlite3/statement.c 2015-01-15 13:38:28.179032043 -0500 @@ -1,5 +1,8 @@ #include "dbd_sqlite3.h" +extern int try_begin_transaction(connection_t *conn); +extern int try_end_transaction(connection_t *conn); + /* * Converts SQLite types to Lua types */ @@ -128,10 +131,12 @@ */ if (sqlite3_reset(statement->stmt) != SQLITE_OK) { lua_pushboolean(L, 0); - lua_pushfstring(L, DBI_ERR_EXECUTE_FAILED, sqlite3_errmsg(statement->sqlite)); + lua_pushfstring(L, DBI_ERR_EXECUTE_FAILED, sqlite3_errmsg(statement->conn->sqlite)); return 2; } + sqlite3_clear_bindings(statement->stmt); + expected_params = sqlite3_bind_parameter_count(statement->stmt); if (expected_params != num_bind_params) { /* @@ -156,10 +161,13 @@ case LUA_TNUMBER: errflag = sqlite3_bind_double(statement->stmt, i, lua_tonumber(L, p)) != SQLITE_OK; break; - case LUA_TSTRING: - errflag = sqlite3_bind_text(statement->stmt, i, lua_tostring(L, p), -1, SQLITE_STATIC) != SQLITE_OK; + case LUA_TSTRING: { + size_t len = -1; + const char *str = lua_tolstring(L, p, &len); + errflag = sqlite3_bind_text(statement->stmt, i, str, len, SQLITE_STATIC) != SQLITE_OK; break; - case LUA_TBOOLEAN: + } + case LUA_TBOOLEAN: errflag = sqlite3_bind_int(statement->stmt, i, lua_toboolean(L, p)) != SQLITE_OK; break; default: @@ -180,18 +188,20 @@ if (errstr) lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); else - lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, sqlite3_errmsg(statement->sqlite)); + lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, sqlite3_errmsg(statement->conn->sqlite)); return 2; } + + try_begin_transaction(statement->conn); if (!step(statement)) { lua_pushboolean(L, 0); - lua_pushfstring(L, DBI_ERR_EXECUTE_FAILED, sqlite3_errmsg(statement->sqlite)); + lua_pushfstring(L, DBI_ERR_EXECUTE_FAILED, sqlite3_errmsg(statement->conn->sqlite)); return 2; } - statement->affected = sqlite3_changes(statement->sqlite); + statement->affected = sqlite3_changes(statement->conn->sqlite); lua_pushboolean(L, 1); return 1; @@ -283,7 +293,7 @@ /* * reset needs to be called to retrieve the 'real' error message */ - luaL_error(L, DBI_ERR_FETCH_FAILED, sqlite3_errmsg(statement->sqlite)); + luaL_error(L, DBI_ERR_FETCH_FAILED, sqlite3_errmsg(statement->conn->sqlite)); } } @@ -327,9 +337,9 @@ * num_rows = statement:rowcount() */ static int statement_rowcount(lua_State *L) { - luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_SQLITE_STATEMENT, "rowcount"); - - return 0; + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); + lua_pushinteger(L, sqlite3_data_count(statement->stmt)); + return 1; } /* @@ -357,14 +367,14 @@ statement_t *statement = NULL; statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); - statement->sqlite = conn->sqlite; + statement->conn = conn; statement->stmt = NULL; statement->more_data = 0; statement->affected = 0; - if (sqlite3_prepare_v2(statement->sqlite, sql_query, strlen(sql_query), &statement->stmt, NULL) != SQLITE_OK) { + if (sqlite3_prepare_v2(statement->conn->sqlite, sql_query, strlen(sql_query), &statement->stmt, NULL) != SQLITE_OK) { lua_pushnil(L); - lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, sqlite3_errmsg(statement->sqlite)); + lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, sqlite3_errmsg(statement->conn->sqlite)); return 2; }