# HG changeset patch # User nrich@ii.net # Date 1240011972 0 # Node ID 8599f34c139b715b9306b92a08b4c438117dfe53 # Parent 9b9d85320bc3140f1088a6be785f8c4ac3bb68e5 Add 'columns' method to statement handles to retrieve column names from a result set diff -r 9b9d85320bc3 -r 8599f34c139b dbd/db2/statement.c --- a/dbd/db2/statement.c Tue Feb 17 00:23:00 2009 +0000 +++ b/dbd/db2/statement.c Fri Apr 17 23:46:12 2009 +0000 @@ -75,6 +75,15 @@ } /* + * column_names = statement:columns() + */ +static int statement_rowcount(lua_State *L) { + luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_DB2_STATEMENT, "columns"); + + return 0; +} + +/* * success = statement:execute(...) */ static int statement_execute(lua_State *L) { @@ -468,6 +477,7 @@ static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, + {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rowcount", statement_rowcount}, diff -r 9b9d85320bc3 -r 8599f34c139b dbd/mysql/statement.c --- a/dbd/mysql/statement.c Tue Feb 17 00:23:00 2009 +0000 +++ b/dbd/mysql/statement.c Fri Apr 17 23:46:12 2009 +0000 @@ -62,6 +62,35 @@ } /* + * column_names = statement:columns() + */ +static int statement_columns(lua_State *L) { + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); + + MYSQL_FIELD *fields; + int i; + int num_columns; + int d = 1; + + if (!statement->stmt) { + luaL_error(L, DBI_ERR_INVALID_STATEMENT); + return 0; + } + + fields = mysql_fetch_fields(statement->metadata); + num_columns = mysql_num_fields(statement->metadata); + lua_newtable(L); + for (i = 0; i < num_columns; i++) { + const char *name = fields[i].name; + + LUA_PUSH_ARRAY_STRING(d, name); + } + + return 1; +} + + +/* * success,err = statement:execute(...) */ static int statement_execute(lua_State *L) { @@ -222,12 +251,6 @@ return 0; } - if (!statement->metadata) { - lua_pushnil(L); - return 1; - } - - column_count = mysql_num_fields(statement->metadata); if (column_count > 0) { @@ -413,6 +436,7 @@ static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, + {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rowcount", statement_rowcount}, diff -r 9b9d85320bc3 -r 8599f34c139b dbd/oracle/statement.c --- a/dbd/oracle/statement.c Tue Feb 17 00:23:00 2009 +0000 +++ b/dbd/oracle/statement.c Fri Apr 17 23:46:12 2009 +0000 @@ -78,6 +78,16 @@ } /* + * column_names = statement:columns() + */ +static int statement_rowcount(lua_State *L) { + luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_ORACLE_STATEMENT, "columns"); + + return 0; +} + + +/* * success,err = statement:execute(...) */ int statement_execute(lua_State *L) { @@ -452,6 +462,7 @@ static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, + {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rowcount", statement_rowcount}, diff -r 9b9d85320bc3 -r 8599f34c139b dbd/postgresql/dbd_postgresql.h --- a/dbd/postgresql/dbd_postgresql.h Tue Feb 17 00:23:00 2009 +0000 +++ b/dbd/postgresql/dbd_postgresql.h Fri Apr 17 23:46:12 2009 +0000 @@ -5,9 +5,9 @@ /* * length of a prepared statement ID - * \d{17}\0 + * dbd-postgresql-\d{17}\0 */ -#define IDLEN 18 +#define IDLEN 15+17+1 #define DBD_POSTGRESQL_CONNECTION "DBD.PostgreSQL.Connection" #define DBD_POSTGRESQL_STATEMENT "DBD.PostgreSQL.Statement" diff -r 9b9d85320bc3 -r 8599f34c139b dbd/postgresql/statement.c --- a/dbd/postgresql/statement.c Tue Feb 17 00:23:00 2009 +0000 +++ b/dbd/postgresql/statement.c Fri Apr 17 23:46:12 2009 +0000 @@ -16,8 +16,8 @@ break; case BOOLOID: - lua_type = LUA_PUSH_BOOLEAN; - break; + lua_type = LUA_PUSH_BOOLEAN; + break; default: lua_type = LUA_PUSH_STRING; @@ -26,6 +26,27 @@ return lua_type; } +static int deallocate(statement_t *statement) { + char command[IDLEN+11]; + + snprintf(command, IDLEN+11, "DEALLOCATE %s", statement->name); + + PGresult *result = PQexec(statement->postgresql, command); + ExecStatusType status; + + if (!result) + return 1; + + status = PQresultStatus(result); + PQclear(result); + + if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) + return 1; + + return 0; +} + + /* * num_affected_rows = statement:affected() */ @@ -48,6 +69,12 @@ statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); if (statement->result) { + /* + * Deallocate prepared statement on the + * server side + */ + deallocate(statement); + PQclear(statement->result); statement->result = NULL; } @@ -56,6 +83,32 @@ } /* + * column_names = statement:columns() + */ +static int statement_columns(lua_State *L) { + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_STATEMENT); + + int i; + int num_columns; + int d = 1; + + if (!statement->result) { + luaL_error(L, DBI_ERR_INVALID_STATEMENT); + return 0; + } + + num_columns = PQnfields(statement->result); + lua_newtable(L); + for (i = 0; i < num_columns; i++) { + const char *name = PQfname(statement->result, i); + + LUA_PUSH_ARRAY_STRING(d, name); + } + + return 1; +} + +/* * success = statement:execute(...) */ static int statement_execute(lua_State *L) { @@ -78,41 +131,41 @@ * convert and copy parameters into a string array */ for (p = 2; p <= n; p++) { - int i = p - 2; - int type = lua_type(L, p); - char err[64]; + int i = p - 2; + int type = lua_type(L, p); + char err[64]; - switch(type) { - case LUA_TNIL: - params[i] = NULL; - 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; - } + switch(type) { + case LUA_TNIL: + params[i] = NULL; + 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; + } } result = PQexecPrepared( - statement->postgresql, + statement->postgresql, statement->name, num_bind_params, (const char **)params, - NULL, + NULL, NULL, 0 ); @@ -121,22 +174,22 @@ free(params); if (errstr) { - lua_pushboolean(L, 0); - lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); - return 2; + 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)); - return 2; + lua_pushboolean(L, 0); + lua_pushfstring(L, DBI_ERR_ALLOC_RESULT, PQerrorMessage(statement->postgresql)); + return 2; } status = PQresultStatus(result); if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { - lua_pushboolean(L, 0); - lua_pushfstring(L, DBI_ERR_BINDING_EXEC, PQresultErrorMessage(result)); - return 2; + lua_pushboolean(L, 0); + lua_pushfstring(L, DBI_ERR_BINDING_EXEC, PQresultErrorMessage(result)); + return 2; } statement->result = result; @@ -146,7 +199,7 @@ } /* - * must be called after an execute + * can only be called after an execute */ static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { int tuple = statement->tuple++; @@ -155,36 +208,36 @@ int d = 1; if (!statement->result) { - luaL_error(L, DBI_ERR_FETCH_INVALID); - return 0; + luaL_error(L, DBI_ERR_FETCH_INVALID); + return 0; } if (PQresultStatus(statement->result) != PGRES_TUPLES_OK) { - lua_pushnil(L); - return 1; + lua_pushnil(L); + return 1; } if (tuple >= PQntuples(statement->result)) { - lua_pushnil(L); /* no more results */ - return 1; + lua_pushnil(L); /* no more results */ + return 1; } num_columns = PQnfields(statement->result); lua_newtable(L); for (i = 0; i < num_columns; i++) { - const char *name = PQfname(statement->result, i); + const char *name = PQfname(statement->result, i); - if (PQgetisnull(statement->result, tuple, i)) { - if (named_columns) { - LUA_PUSH_ATTRIB_NIL(name); + if (PQgetisnull(statement->result, tuple, i)) { + if (named_columns) { + LUA_PUSH_ATTRIB_NIL(name); } else { LUA_PUSH_ARRAY_NIL(d); } - } else { - const char *value = PQgetvalue(statement->result, tuple, i); - lua_push_type_t lua_push = postgresql_to_lua_push(PQftype(statement->result, i)); + } else { + const char *value = PQgetvalue(statement->result, tuple, i); + lua_push_type_t lua_push = postgresql_to_lua_push(PQftype(statement->result, i)); - /* + /* * data is returned as strings from PSQL * convert them here into Lua types */ @@ -218,7 +271,7 @@ LUA_PUSH_ARRAY_STRING(d, value); } } else if (lua_push == LUA_PUSH_BOOLEAN) { - /* + /* * booleans are returned as a string * either 't' or 'f' */ @@ -232,7 +285,7 @@ } else { luaL_error(L, DBI_ERR_UNKNOWN_PUSH); } - } + } } return 1; @@ -309,7 +362,7 @@ */ new_sql = replace_placeholders(L, '$', sql_query); - snprintf(name, IDLEN, "%017u", ++conn->statement_id); + snprintf(name, IDLEN, "dbd-postgresql-%017u", ++conn->statement_id); result = PQprepare(conn->postgresql, name, new_sql, 0, NULL); @@ -319,19 +372,19 @@ free(new_sql); if (!result) { - lua_pushnil(L); - lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, PQerrorMessage(statement->postgresql)); - return 2; + lua_pushnil(L); + lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, PQerrorMessage(statement->postgresql)); + return 2; } status = PQresultStatus(result); if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) { - const char *err_string = PQresultErrorMessage(result); - PQclear(result); + const char *err_string = PQresultErrorMessage(result); + PQclear(result); - lua_pushnil(L); - lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, err_string); - return 2; + lua_pushnil(L); + lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, err_string); + return 2; } PQclear(result); @@ -351,17 +404,18 @@ int dbd_postgresql_statement(lua_State *L) { static const luaL_Reg statement_methods[] = { - {"affected", statement_affected}, - {"close", statement_close}, - {"execute", statement_execute}, - {"fetch", statement_fetch}, - {"rowcount", statement_rowcount}, - {"rows", statement_rows}, - {NULL, NULL} + {"affected", statement_affected}, + {"close", statement_close}, + {"columns", statement_columns}, + {"execute", statement_execute}, + {"fetch", statement_fetch}, + {"rowcount", statement_rowcount}, + {"rows", statement_rows}, + {NULL, NULL} }; static const luaL_Reg statement_class_methods[] = { - {NULL, NULL} + {NULL, NULL} }; luaL_newmetatable(L, DBD_POSTGRESQL_STATEMENT); diff -r 9b9d85320bc3 -r 8599f34c139b dbd/sqlite3/statement.c --- a/dbd/sqlite3/statement.c Tue Feb 17 00:23:00 2009 +0000 +++ b/dbd/sqlite3/statement.c Fri Apr 17 23:46:12 2009 +0000 @@ -78,6 +78,32 @@ } /* + * column_names = statement:columns() + */ +static int statement_columns(lua_State *L) { + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); + + int i; + int num_columns; + int d = 1; + + if (!statement->stmt) { + luaL_error(L, DBI_ERR_INVALID_STATEMENT); + return 0; + } + + num_columns = sqlite3_column_count(statement->stmt); + lua_newtable(L); + for (i = 0; i < num_columns; i++) { + const char *name = sqlite3_column_name(statement->stmt, i); + + LUA_PUSH_ARRAY_STRING(d, name); + } + + return 1; +} + +/* * success,err = statement:execute(...) */ static int statement_execute(lua_State *L) { @@ -340,6 +366,7 @@ static const luaL_Reg statement_methods[] = { {"affected", statement_affected}, {"close", statement_close}, + {"columns", statement_columns}, {"execute", statement_execute}, {"fetch", statement_fetch}, {"rows", statement_rows},