Cleanup and 'assert' error handling.

Wed, 26 Nov 2008 10:01:03 +0000

author
nrich@ii.net
date
Wed, 26 Nov 2008 10:01:03 +0000
changeset 3
b61020ca4753
parent 2
c4f02fc67e5a
child 4
c50b0e6f25d6

Cleanup and 'assert' error handling.

DBI.lua file | annotate | diff | comparison | revisions
dbd/mysql/connection.c file | annotate | diff | comparison | revisions
dbd/mysql/statement.c file | annotate | diff | comparison | revisions
dbd/postgresql/connection.c file | annotate | diff | comparison | revisions
dbd/postgresql/statement.c file | annotate | diff | comparison | revisions
dbd/sqlite3/connection.c file | annotate | diff | comparison | revisions
dbd/sqlite3/statement.c file | annotate | diff | comparison | revisions
--- a/DBI.lua	Sun Nov 23 04:12:04 2008 +0000
+++ b/DBI.lua	Wed Nov 26 10:01:03 2008 +0000
@@ -56,3 +56,12 @@
     return connection_class.New(name, username, password, host, port)
 end
 
+function Do(dbh, sql, ...)
+    local sth,err = dbh:prepare(sql)
+
+    if not sth then
+	return false, err
+    end
+
+    return sth:execute(...)
+end
--- a/dbd/mysql/connection.c	Sun Nov 23 04:12:04 2008 +0000
+++ b/dbd/mysql/connection.c	Wed Nov 26 10:01:03 2008 +0000
@@ -3,7 +3,7 @@
 int dbd_mysql_statement_create(lua_State *L, connection_t *conn, const char *sql_query);
 
 /*
- * connection = DBD.MySQl.New(dbname, user, password, host, port)
+ * connection,err = DBD.MySQl.New(dbname, user, password, host, port)
  */
 static int connection_new(lua_State *L) {
     int n = lua_gettop(L);
@@ -42,14 +42,15 @@
 
     conn->mysql = mysql_init(NULL);
 
-    if (mysql_real_connect(conn->mysql, host, user, password, db, port, unix_socket, client_flag)) {
-        luaL_getmetatable(L, DBD_MYSQL_CONNECTION);
-        lua_setmetatable(L, -2);
-    } else {
-	luaL_error(L, "Failed to connect to database: %s", mysql_error(conn->mysql));
+    if (!mysql_real_connect(conn->mysql, host, user, password, db, port, unix_socket, client_flag)) {
 	lua_pushnil(L);
+	lua_pushfstring(L, "Failed to connect to database: %s", mysql_error(conn->mysql));
+	return 2;
     }
 
+    luaL_getmetatable(L, DBD_MYSQL_CONNECTION);
+    lua_setmetatable(L, -2);
+
     return 1;
 }
 
@@ -63,6 +64,7 @@
     if (conn->mysql) {
 	mysql_close(conn->mysql);
 	disconnect = 1;
+	conn->mysql = NULL;
     }
 
     lua_pushboolean(L, disconnect);
@@ -85,7 +87,7 @@
 }
 
 /*
- * statement = connection:prepare(sql_string)
+ * statement,err = connection:prepare(sql_string)
  */
 static int connection_prepare(lua_State *L) {
     connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_MYSQL_CONNECTION);
@@ -95,7 +97,9 @@
     }
 
     lua_pushnil(L);    
-    return 1;
+    lua_pushstring(L, "Database not available");    
+
+    return 2;
 }
 
 /*
--- a/dbd/mysql/statement.c	Sun Nov 23 04:12:04 2008 +0000
+++ b/dbd/mysql/statement.c	Wed Nov 26 10:01:03 2008 +0000
@@ -34,22 +34,26 @@
 
     if (statement->metadata) {
 	mysql_free_result(statement->metadata);
+	statement->metadata = NULL;
     }
 
     if (statement->stmt) {
-	mysql_stmt_close(statement->stmt);	
+	mysql_stmt_close(statement->stmt);
+	statement->stmt = NULL;
     }
 
+    lua_pushboolean(L, 1);
     return 1;    
 }
 
 /*
- * success = statement:execute(...)
+ * success,err = statement:execute(...)
  */
 static int statement_execute(lua_State *L) {
     int n = lua_gettop(L);
     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); 
     int num_bind_params = n - 1;
+    int expected_params;
     
     MYSQL_BIND *bind = NULL;
     MYSQL_RES *metadata = NULL;
@@ -58,6 +62,24 @@
 
     int p;
 
+    if (!statement->stmt) {
+	lua_pushboolean(L, 0);
+	lua_pushstring(L, "execute called on a closed or invalid statement");
+	return 2;
+    }
+
+    expected_params = mysql_stmt_param_count(statement->stmt);
+
+    if (expected_params != num_bind_params) {
+	/*
+         * mysql_stmt_bind_param does not handle this conndition,
+         * and the client library will segfault if these do no match
+         */ 
+	lua_pushboolean(L, 0);
+	lua_pushfstring(L, "Statement expected %d paramaters but received %d", expected_params, num_bind_params); 
+	return 2;
+    }
+
     bind = malloc(sizeof(MYSQL_BIND) * num_bind_params);
     memset(bind, 0, sizeof(MYSQL_BIND) * num_bind_params);
 
@@ -117,12 +139,14 @@
 	free(bind);
 
     if (error_message) {
-	luaL_error(L, error_message, mysql_stmt_error(statement->stmt));
-	return 0;
+	lua_pushboolean(L, 0);
+	lua_pushfstring(L, error_message, mysql_stmt_error(statement->stmt));
+	return 2;
     }
 
     statement->metadata = metadata;
 
+    lua_pushboolean(L, 1);
     return 1;
 }
 
@@ -133,9 +157,13 @@
     const char *error_message = NULL;
 
     if (!statement->stmt) {
+	luaL_error(L, "fetch called on a closed or invalid statement");
+	return 0;
+    }
+
+    if (!statement->metadata) {
 	luaL_error(L, "fetch called before execute");
-	lua_pushnil(L);
-	return 1;
+	return 0;
     }
 
     if (!statement->metadata) {
@@ -268,13 +296,15 @@
     MYSQL_STMT *stmt = mysql_stmt_init(conn->mysql);
 
     if (!stmt) {
-	luaL_error(L, "Error allocating statement handle: %s", mysql_error(conn->mysql));
-	return 0;
+	lua_pushnil(L);
+	lua_pushfstring(L, "Error allocating statement handle: %s", mysql_error(conn->mysql));
+	return 2;
     }
 
     if (mysql_stmt_prepare(stmt, sql_query, sql_len)) {
-	luaL_error(L, "Error preparing statement handle: %s", mysql_stmt_error(stmt));
-	return 0;
+	lua_pushnil(L);
+	lua_pushfstring(L, "Error preparing statement handle: %s", mysql_stmt_error(stmt));
+	return 2;
     }
 
     statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t));
--- a/dbd/postgresql/connection.c	Sun Nov 23 04:12:04 2008 +0000
+++ b/dbd/postgresql/connection.c	Wed Nov 26 10:01:03 2008 +0000
@@ -53,14 +53,15 @@
     conn->postgresql = PQsetdbLogin(host, port, options, tty, db, user, password);
     conn->statement_id = 0;
 
-    if (PQstatus(conn->postgresql) == CONNECTION_OK) {
-        luaL_getmetatable(L, DBD_POSTGRESQL_CONNECTION);
-        lua_setmetatable(L, -2);
-    } else {
-	luaL_error(L, "Failed to connect to database: %s", PQerrorMessage(conn->postgresql));
+    if (PQstatus(conn->postgresql) != CONNECTION_OK) {
 	lua_pushnil(L);
+	lua_pushfstring(L, "Failed to connect to database: %s", PQerrorMessage(conn->postgresql));
+	return 2;
     }
 
+    luaL_getmetatable(L, DBD_POSTGRESQL_CONNECTION);
+    lua_setmetatable(L, -2);
+
     return 1;
 }
 
@@ -74,6 +75,7 @@
     if (conn->postgresql) {
 	PQfinish(conn->postgresql);
 	disconnect = 1;
+	conn->postgresql = NULL;
     }
 
     lua_pushboolean(L, disconnect);
@@ -109,7 +111,8 @@
     }
 
     lua_pushnil(L);    
-    return 1;
+    lua_pushstring(L, "Database not available");
+    return 2;
 }
 
 /*
--- a/dbd/postgresql/statement.c	Sun Nov 23 04:12:04 2008 +0000
+++ b/dbd/postgresql/statement.c	Wed Nov 26 10:01:03 2008 +0000
@@ -180,21 +180,22 @@
     free(params);
 
     if (!result) {
-	luaL_error(L, "Unable to allocate result handle");
 	lua_pushboolean(L, 0);
-	return 1;
+	lua_pushstring(L, "Unable to allocate result handle");
+	return 2;
     }
     
     status = PQresultStatus(result);
     if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
-	luaL_error(L, "Unable to execute statment: %s", PQresultErrorMessage(result));
 	lua_pushboolean(L, 0);
-	return 1;
+	lua_pushfstring(L, "Unable to execute statment: %s", PQresultErrorMessage(result));
+	return 2;
     }
     
     statement->result = result;
 
     lua_pushboolean(L, 1);
+    lua_pushnil(L);
     return 1;
 }
 
@@ -207,6 +208,11 @@
     int i;
     int num_columns;
 
+    if (!statement->result) {
+	luaL_error(L, "fetch called on a closed or invalid statement");
+	return 0;
+    }
+
     if (PQresultStatus(statement->result) != PGRES_TUPLES_OK) {
 	lua_pushnil(L);
 	return 1;
@@ -332,15 +338,19 @@
     free(new_sql);
 
     if (!result) {
-	luaL_error(L, "Unable to allocate prepare result handle");
+	lua_pushnil(L);
+	lua_pushstring(L, "Unable to allocate prepare result handle");
+	return 2;
     }
     
     status = PQresultStatus(result);
     if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) {
 	const char *err_string = PQresultErrorMessage(result);
 	PQclear(result);
-	luaL_error(L, "Unable to prepare statment: %s", err_string);
-	return 0;
+
+	lua_pushnil(L);
+	lua_pushfstring(L, "Unable to prepare statment: %s", err_string);
+	return 2;
     }
 
     PQclear(result);
--- a/dbd/sqlite3/connection.c	Sun Nov 23 04:12:04 2008 +0000
+++ b/dbd/sqlite3/connection.c	Wed Nov 26 10:01:03 2008 +0000
@@ -3,7 +3,7 @@
 int dbd_sqlite3_statement_create(lua_State *L, connection_t *conn, const char *sql_query);
 
 /* 
- * connection = DBD.SQLite3.New(dbfile)
+ * connection,err = DBD.SQLite3.New(dbfile)
  */
 static int connection_new(lua_State *L) {
     int n = lua_gettop(L);
@@ -13,21 +13,22 @@
 
     /* db */
     switch (n) {
-    default:
+    case 1:
 	if (lua_isnil(L, 1) == 0) 
 	    db = luaL_checkstring(L, 1);
     }
 
     conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t));
 
-    if (sqlite3_open(db, &conn->sqlite) == SQLITE_OK) {
-        luaL_getmetatable(L, DBD_SQLITE_CONNECTION);
-        lua_setmetatable(L, -2);
-    } else {
-	luaL_error(L, "Failed to connect to database: %s", sqlite3_errmsg(conn->sqlite));
+    if (sqlite3_open(db, &conn->sqlite) != SQLITE_OK) {
 	lua_pushnil(L);
+	lua_pushfstring(L, "Failed to connect to database: %s", sqlite3_errmsg(conn->sqlite));
+	return 2;
     }
 
+    luaL_getmetatable(L, DBD_SQLITE_CONNECTION);
+    lua_setmetatable(L, -2);
+
     return 1;
 }
 
@@ -39,15 +40,16 @@
     int disconnect = 0;   
 
     if (conn->sqlite) {
-	if (sqlite3_close(conn->sqlite) == SQLITE_OK) {
-	    disconnect = 1;
-	}
+	sqlite3_close(conn->sqlite);
+	disconnect = 1;
+	conn->sqlite = NULL;
     }
 
     lua_pushboolean(L, disconnect);
     return 1;
 }
 
+
 /*
  * ok = connection:ping()
  */
@@ -64,7 +66,7 @@
 }
 
 /*
- * statement = connection:prepare(sql_str)
+ * statement,err = connection:prepare(sql_str)
  */
 static int connection_prepare(lua_State *L) {
     connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_SQLITE_CONNECTION);
@@ -74,7 +76,8 @@
     }
 
     lua_pushnil(L);    
-    return 1;
+    lua_pushstring(L, "Connection not available");
+    return 2;
 }
 
 /*
--- a/dbd/sqlite3/statement.c	Sun Nov 23 04:12:04 2008 +0000
+++ b/dbd/sqlite3/statement.c	Wed Nov 26 10:01:03 2008 +0000
@@ -46,7 +46,7 @@
 /*
  * success = statement:close()
  */
-static int statement_close(lua_State *L) {
+int statement_close(lua_State *L) {
     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT);
     int ok = 0;
 
@@ -54,20 +54,29 @@
 	if (sqlite3_finalize(statement->stmt) == SQLITE_OK) {
 	    ok = 1;
 	}
+
+	statement->stmt = NULL;
     }
 
     lua_pushboolean(L, ok);
-
     return 1;
 }
 
 /*
- * success = statement:execute(...)
+ * success,err = statement:execute(...)
  */
-static int statement_execute(lua_State *L) {
+int statement_execute(lua_State *L) {
     int n = lua_gettop(L);
     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT);
     int p;
+    int err = 0;
+
+
+    if (!statement->stmt) {
+	lua_pushboolean(L, 0);
+	lua_pushstring(L, "execute called on a closed or invalid handle");
+	return 2;
+    }
 
     /*
      * reset the handle before binding params
@@ -76,7 +85,8 @@
      */
     if (sqlite3_reset(statement->stmt) != SQLITE_OK) {
 	lua_pushboolean(L, 0);
-	return 1;
+	lua_pushfstring(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite));
+	return 2;
     }
 
     for (p = 2; p <= n; p++) {
@@ -84,20 +94,29 @@
 
 	if (lua_isnil(L, p)) {
 	    if (sqlite3_bind_null(statement->stmt, i) != SQLITE_OK) {
-		luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite));
+		err = 1;
 	    }
 	} else if (lua_isnumber(L, p)) {
 	    if (sqlite3_bind_double(statement->stmt, i, luaL_checknumber(L, p)) != SQLITE_OK) {
-		luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite));
+		err = 1;
 	    }
 	} else if (lua_isstring(L, p)) {
 	    if (sqlite3_bind_text(statement->stmt, i, luaL_checkstring(L, p), -1, SQLITE_STATIC) != SQLITE_OK) {
-		luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite));
+		err = 1;
 	    }
 	}
+
+	if (err)
+	    break;
     }   
 
-    lua_pushboolean(L, step(statement));
+    if (err || step(statement) == 0) {
+	lua_pushboolean(L, 0);
+	lua_pushfstring(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite));
+	return 2;
+    }
+
+    lua_pushboolean(L, 1);
     return 1;
 }
 
@@ -108,6 +127,11 @@
     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT);
     int num_columns;
 
+    if (!statement->stmt) {
+	luaL_error(L, "fetch called on a closed or invalid handle");
+	return 0;
+    }
+
     if (!statement->more_data) {
 	/* 
          * Result set is empty, or not result set returned
@@ -223,14 +247,13 @@
     statement->more_data = 0;
 
     if (sqlite3_prepare_v2(statement->sqlite, sql_query, strlen(sql_query), &statement->stmt, NULL) != SQLITE_OK) {
-	luaL_error(L, "Failed to prepare statement: %s", sqlite3_errmsg(statement->sqlite));	
 	lua_pushnil(L);
-	return 1;
+	lua_pushfstring(L, "Failed to prepare statement: %s", sqlite3_errmsg(statement->sqlite));	
+	return 2;
     } 
 
     luaL_getmetatable(L, DBD_SQLITE_STATEMENT);
     lua_setmetatable(L, -2);
-
     return 1;
 } 
 

mercurial