# HG changeset patch # User nrich@ii.net # Date 1228116164 0 # Node ID 3aa8a37a3dd8c54277f73233b6f3ba1e379b96b4 # Parent 06eb2850703f7762f3739aacf3dc51916030e7da Added new typechecks and errors diff -r 06eb2850703f -r 3aa8a37a3dd8 dbd/common.h --- a/dbd/common.h Mon Dec 01 02:56:40 2008 +0000 +++ b/dbd/common.h Mon Dec 01 07:22:44 2008 +0000 @@ -101,7 +101,6 @@ #define DBI_ERR_FETCH_INVALID "Fetch called on a closed or invalid statement" #define DBI_ERR_FETCH_FAILED "Fetch failed %s" #define DBI_ERR_PARAM_MISCOUNT "Statement expected %d parameters but received %d" -#define DBI_ERR_BINDING_UNKNOWN "Binding unknown or unsupported type" #define DBI_ERR_BINDING_PARAMS "Error binding statement parameters: %s" #define DBI_ERR_BINDING_EXEC "Error executing statement parameters: %s" #define DBI_ERR_FETCH_NO_EXECUTE "Fetch called before execute" @@ -111,3 +110,4 @@ #define DBI_ERR_PREP_STATEMENT "Error preparing statement handle: %s" #define DBI_ERR_INVALID_PORT "Invalid port: %d" #define DBI_ERR_ALLOC_RESULT "Error allocating result set: %s" +#define DBI_ERR_BINDING_TYPE_ERR "Unknown or unsupported type `%s'" diff -r 06eb2850703f -r 3aa8a37a3dd8 dbd/mysql/statement.c --- a/dbd/mysql/statement.c Mon Dec 01 02:56:40 2008 +0000 +++ b/dbd/mysql/statement.c Mon Dec 01 07:22:44 2008 +0000 @@ -59,6 +59,7 @@ MYSQL_RES *metadata = NULL; char *error_message = NULL; + char *errstr = NULL; int p; @@ -72,7 +73,7 @@ if (expected_params != num_bind_params) { /* - * mysql_stmt_bind_param does not handle this conndition, + * mysql_stmt_bind_param does not handle this condition, * and the client library will segfault if these do no match */ lua_pushboolean(L, 0); @@ -91,6 +92,7 @@ size_t *str_len = NULL; double *num = NULL; int *boolean = NULL; + char err[64]; switch(type) { case LUA_TNIL: @@ -132,7 +134,9 @@ break; default: - error_message = DBI_ERR_BINDING_UNKNOWN; + snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); + errstr = err; + error_message = DBI_ERR_BINDING_PARAMS; goto cleanup; } } @@ -175,7 +179,7 @@ if (error_message) { lua_pushboolean(L, 0); - lua_pushfstring(L, error_message, mysql_stmt_error(statement->stmt)); + lua_pushfstring(L, error_message, errstr ? errstr : mysql_stmt_error(statement->stmt)); return 2; } diff -r 06eb2850703f -r 3aa8a37a3dd8 dbd/postgresql/statement.c --- a/dbd/postgresql/statement.c Mon Dec 01 02:56:40 2008 +0000 +++ b/dbd/postgresql/statement.c Mon Dec 01 07:22:44 2008 +0000 @@ -131,6 +131,7 @@ int num_bind_params = n - 1; ExecStatusType status; int p; + const char *errstr = NULL; const char **params; PGresult *result = NULL; @@ -144,21 +145,31 @@ */ for (p = 2; p <= n; p++) { int i = p - 2; + int type = lua_type(L, p); + char err[64]; - if (lua_isnil(L, p)) { + switch(type) { + case LUA_TNIL: params[i] = NULL; - } else { - if (lua_isboolean(L, p)) - /* - * boolean values in postgresql can either be - * t/f or 1/0. Pass integer values rather than - * strings to maintain semantic compatibility - * with other DBD drivers that pass booleans - * as integers. - */ - params[i] = lua_toboolean(L, p) ? "1" : "0"; - else - params[i] = lua_tostring(L, p); + break; + case LUA_TBOOLEAN: + /* + * boolean values in postgresql can either be + * t/f or 1/0. Pass integer values rather than + * strings to maintain semantic compatibility + * with other DBD drivers that pass booleans + * as integers. + */ + params[i] = lua_toboolean(L, p) ? "1" : "0"; + break; + case LUA_TNUMBER: + case LUA_TSTRING: + params[i] = lua_tostring(L, p); + break; + default: + snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); + errstr = err; + goto cleanup; } } @@ -172,8 +183,15 @@ 0 ); +cleanup: free(params); + if (errstr) { + lua_pushboolean(L, 0); + lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); + return 2; + } + if (!result) { lua_pushboolean(L, 0); lua_pushfstring(L, DBI_ERR_ALLOC_RESULT, PQerrorMessage(statement->postgresql)); diff -r 06eb2850703f -r 3aa8a37a3dd8 dbd/sqlite3/statement.c --- a/dbd/sqlite3/statement.c Mon Dec 01 02:56:40 2008 +0000 +++ b/dbd/sqlite3/statement.c Mon Dec 01 07:22:44 2008 +0000 @@ -69,8 +69,10 @@ int n = lua_gettop(L); statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); int p; - int err = 0; - + int errflag = 0; + const char *errstr = NULL; + int expected_params; + int num_bind_params = n - 1; if (!statement->stmt) { lua_pushboolean(L, 0); @@ -89,39 +91,56 @@ return 2; } + expected_params = sqlite3_bind_parameter_count(statement->stmt); + if (expected_params != num_bind_params) { + /* + * sqlite3_reset does not handle this condition, + * and the client library will fill unset params + * with NULLs + */ + lua_pushboolean(L, 0); + lua_pushfstring(L, DBI_ERR_PARAM_MISCOUNT, expected_params, num_bind_params); + return 2; + } + for (p = 2; p <= n; p++) { int i = p - 1; - int type = lua_type(L, p); + char err[64]; switch(type) { case LUA_TNIL: - err = sqlite3_bind_null(statement->stmt, i) != SQLITE_OK; + errflag = sqlite3_bind_null(statement->stmt, i) != SQLITE_OK; break; case LUA_TNUMBER: - err = sqlite3_bind_double(statement->stmt, i, lua_tonumber(L, p)) != SQLITE_OK; + errflag = sqlite3_bind_double(statement->stmt, i, lua_tonumber(L, p)) != SQLITE_OK; break; case LUA_TSTRING: - err = sqlite3_bind_text(statement->stmt, i, lua_tostring(L, p), -1, SQLITE_STATIC) != SQLITE_OK; + errflag = sqlite3_bind_text(statement->stmt, i, lua_tostring(L, p), -1, SQLITE_STATIC) != SQLITE_OK; break; case LUA_TBOOLEAN: - err = sqlite3_bind_int(statement->stmt, i, lua_toboolean(L, p)) != SQLITE_OK; + errflag = sqlite3_bind_int(statement->stmt, i, lua_toboolean(L, p)) != SQLITE_OK; break; default: /* * Unknown/unsupported value type */ - err = 1; + errflag = 1; + snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); + errstr = err; } - - if (err) + if (errflag) break; } - if (err) { + if (errflag) { lua_pushboolean(L, 0); - lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, sqlite3_errmsg(statement->sqlite)); + if (errstr) + lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); + else + lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, sqlite3_errmsg(statement->sqlite)); + return 2; }