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