Add 'columns' method to statement handles to retrieve column names from a result set

Fri, 17 Apr 2009 23:46:12 +0000

author
nrich@ii.net
date
Fri, 17 Apr 2009 23:46:12 +0000
changeset 30
8599f34c139b
parent 29
9b9d85320bc3
child 31
999ef93f0dbc

Add 'columns' method to statement handles to retrieve column names from a result set

dbd/db2/statement.c file | annotate | diff | comparison | revisions
dbd/mysql/statement.c file | annotate | diff | comparison | revisions
dbd/oracle/statement.c file | annotate | diff | comparison | revisions
dbd/postgresql/dbd_postgresql.h file | annotate | diff | comparison | revisions
dbd/postgresql/statement.c file | annotate | diff | comparison | revisions
dbd/sqlite3/statement.c file | annotate | diff | comparison | revisions
--- 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},
--- 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},
--- 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},
--- 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"
--- 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);
--- 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},

mercurial