From b5fdc8788e7bfc61c516896ac740cc9d8c18c70f Mon Sep 17 00:00:00 2001 From: eduquintao Date: Mon, 28 Jul 2003 20:10:12 +0000 Subject: [PATCH] *** empty log message *** --- src/ls_mysql.c | 172 +++++++++++++++++++++++-------------------------- 1 file changed, 79 insertions(+), 93 deletions(-) diff --git a/src/ls_mysql.c b/src/ls_mysql.c index 6ac6431..9f593e8 100644 --- a/src/ls_mysql.c +++ b/src/ls_mysql.c @@ -1,7 +1,7 @@ /* ** LuaSQL, MySQL driver ** Authors: Eduardo Quintao -** $Id: ls_mysql.c,v 1.3 2003/07/23 18:32:38 eduquintao Exp $ +** $Id: ls_mysql.c,v 1.4 2003/07/28 20:10:12 eduquintao Exp $ */ #include @@ -32,24 +32,31 @@ typedef struct { MYSQL *my_conn; } conn_data; - typedef struct { short closed; int conn; /* reference to connection */ int numcols; /* number of columns */ - int numrows; /* number of rows returned or affected */ int colnames, coltypes; /* reference to column information tables */ - int curr_tuple; /* current tuple to be read by fetch */ MYSQL_RES *my_res; } cur_data; - -typedef void (*creator) (lua_State *L, cur_data *cur); - - LUASQL_API int luasql_libopen_mysql (lua_State *L); +/* +** Generates a driver error plus the error message from the database +** The generated error message is preceded by LUASQL_PREFIX string +*/ +static int luasql_failmessage(lua_State *L, const char *err, const char *m) { + lua_pushnil(L); + lua_pushstring(L, LUASQL_PREFIX); + lua_pushstring(L, err); + lua_pushstring(L, m); + lua_concat(L, 3); + return 2; +} + + /* ** Check for valid environment. */ @@ -86,12 +93,12 @@ static cur_data *getcursor (lua_State *L) { /* ** Push the value of #i field of #tuple row. */ -static void pushvalue (lua_State *L, void *row) { +static void pushvalue (lua_State *L, void *row, long int len) { /* Levar em consideracao os tipos mais proximos a lua */ if (row == NULL) lua_pushnil (L); else - lua_pushstring (L, row); + lua_pushlstring (L, row, len); } @@ -102,40 +109,50 @@ static int cur_fetch (lua_State *L) { cur_data *cur = getcursor (L); MYSQL_RES *res = cur->my_res; MYSQL_ROW row; - MYSQL_FIELD *fields; - int tuple = cur->curr_tuple; - fields = mysql_fetch_fields(res); + unsigned long *lengths; - if (tuple >= cur->numrows) { + row = mysql_fetch_row(res); + if (row == NULL) { lua_pushnil(L); /* no more results */ return 1; } + lengths = mysql_fetch_lengths(res); - cur->curr_tuple++; - row = mysql_fetch_row(res); if (lua_istable (L, 2)) { int i; const char *opts = luaL_optstring (L, 3, "n"); if (strchr (opts, 'n') != NULL) /* Copy values to numerical indices */ for (i = 0; i < cur->numcols; i++) { - pushvalue (L, row[i]); + pushvalue (L, row[i], lengths[i]); lua_rawseti (L, 2, i+1); } - if (strchr (opts, 'a') != NULL) + if (strchr (opts, 'a') != NULL) { + /* Check if colnames exists */ + if (cur->colnames == LUA_NOREF) + create_colinfo(L, cur); + lua_rawgeti (L, LUA_REGISTRYINDEX, cur->colnames);/* Push colnames*/ + /* Copy values to alphanumerical indices */ for (i = 0; i < cur->numcols; i++) { - lua_pushstring (L, fields[i].name); - pushvalue (L, row[i]); + lua_rawgeti(L, -1, i+1); /* push the field name */ + + /* Actually push the value */ + lua_pushstring (L, lua_tostring(L, -1) ); + pushvalue (L, row[i], lengths[i]); lua_rawset (L, 2); + + lua_pop(L, 1); /* pop the field name */ } + lua_pop(L, 1); /* Pops colnames table */ + } lua_pushvalue(L, 2); return 1; /* return table */ } else { int i; for (i = 0; i < cur->numcols; i++) - pushvalue (L, row[i]); + pushvalue (L, row[i], lengths[i]); return cur->numcols; /* return #numcols values */ } } @@ -153,7 +170,6 @@ static int cur_close (lua_State *L) { /* Nullify structure fields. */ cur->closed = 1; -/* Checar o my_res antes */ mysql_free_result(cur->my_res); luaL_unref (L, LUA_REGISTRYINDEX, cur->conn); luaL_unref (L, LUA_REGISTRYINDEX, cur->colnames); @@ -185,10 +201,10 @@ static char *getcolumntype (enum enum_field_types type) { return "datetime"; case MYSQL_TYPE_TIME: return "time"; - case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: - return "set"; case MYSQL_TYPE_TIMESTAMP: return "timestamp"; + case MYSQL_TYPE_ENUM: case MYSQL_TYPE_SET: + return "set"; case MYSQL_TYPE_NULL: return "null"; default: @@ -198,42 +214,25 @@ static char *getcolumntype (enum enum_field_types type) { /* -** Creates the list of fields names and pushes it on top of the stack. +** Creates the lists of fields names and fields types. */ -static void create_colnames (lua_State *L, cur_data *cur) { -/* Posso usar o proprio cur->my_res ???? */ - MYSQL_RES *result = cur->my_res; +static void create_colinfo (lua_State *L, cur_data *cur) { MYSQL_FIELD *fields; + char typename[50]; int i; - fields = mysql_fetch_fields(result); - lua_newtable (L); + fields = mysql_fetch_fields(cur->my_res); + lua_newtable (L); /* names */ + lua_newtable (L); /* types */ for (i = 1; i <= cur->numcols; i++) { lua_pushstring (L, fields[i-1].name); - lua_rawseti (L, -2, i); - } -} - - -/* -** Creates the list of fields types and pushes it on top of the stack. -*/ -static void create_coltypes (lua_State *L, cur_data *cur) { - /* conn_data *conn; */ - char typename[100]; - MYSQL_RES *result = cur->my_res; - MYSQL_FIELD *fields; - int i; - fields = mysql_fetch_fields(result); -/* lua_rawgeti (L, LUA_REGISTRYINDEX, cur->conn); - if (!lua_isuserdata (L, -1)) - luaL_error (L, LUASQL_PREFIX"invalid connection"); - conn = (conn_data *)lua_touserdata (L, -1);*/ - lua_newtable (L); - for (i = 1; i <= cur->numcols; i++) { - sprintf (typename, "%.20s (%d)", getcolumntype (fields[i-1].type), fields[i-1].length); + lua_rawseti (L, -3, i); + sprintf (typename, "%.20s(%ld)", getcolumntype (fields[i-1].type), fields[i-1].length); lua_pushstring(L, typename); lua_rawseti (L, -2, i); } + /* Stores the references in the cursor structure */ + cur->coltypes = luaL_ref (L, LUA_REGISTRYINDEX); + cur->colnames = luaL_ref (L, LUA_REGISTRYINDEX); } @@ -242,25 +241,24 @@ static void create_coltypes (lua_State *L, cur_data *cur) { ** If the table isn't built yet, call the creator function and stores ** a reference to it on the cursor structure. */ -static void _pushtable (lua_State *L, cur_data *cur, size_t off, creator func) { +static void _pushtable (lua_State *L, cur_data *cur, size_t off) { int *ref = (int *)((char *)cur + off); - if (*ref != LUA_NOREF) - lua_rawgeti (L, LUA_REGISTRYINDEX, *ref); - else { - func (L, cur); - /* Stores a reference to it on the cursor structure */ - lua_pushvalue (L, -1); - *ref = luaL_ref (L, LUA_REGISTRYINDEX); - } + + /* If colnames or coltypes do not exist, create both. */ + if (*ref == LUA_NOREF) + create_colinfo(L, cur); + + /* Pushes the right table (colnames or coltypes) */ + lua_rawgeti (L, LUA_REGISTRYINDEX, *ref); } -#define pushtable(L,c,m,f) (_pushtable(L,c,offsetof(cur_data,m),f)) +#define pushtable(L,c,m) (_pushtable(L,c,offsetof(cur_data,m))) /* ** Return the list of field names. */ static int cur_getcolnames (lua_State *L) { - pushtable (L, getcursor(L), colnames, create_colnames); + pushtable (L, getcursor(L), colnames); return 1; } @@ -269,16 +267,7 @@ static int cur_getcolnames (lua_State *L) { ** Return the list of field types. */ static int cur_getcoltypes (lua_State *L) { - pushtable (L, getcursor(L), coltypes, create_coltypes); - return 1; -} - - -/* -** Push the number of rows. -*/ -static int cur_numrows (lua_State *L) { - lua_pushnumber (L, getcursor(L)->numrows ); + pushtable (L, getcursor(L), coltypes); return 1; } @@ -286,7 +275,7 @@ static int cur_numrows (lua_State *L) { /* ** Create a new Cursor object and push it on top of the stack. */ -static int create_cursor (lua_State *L, int conn, MYSQL_RES *result, int rows, int cols) { +static int create_cursor (lua_State *L, int conn, MYSQL_RES *result, int cols) { cur_data *cur = (cur_data *)lua_newuserdata(L, sizeof(cur_data)); luasql_setmeta (L, LUASQL_CURSOR_MYSQL); @@ -294,10 +283,8 @@ static int create_cursor (lua_State *L, int conn, MYSQL_RES *result, int rows, i cur->closed = 0; cur->conn = LUA_NOREF; cur->numcols = cols; - cur->numrows = rows; cur->colnames = LUA_NOREF; cur->coltypes = LUA_NOREF; - cur->curr_tuple = 0; cur->my_res = result; lua_pushvalue (L, conn); cur->conn = luaL_ref (L, LUA_REGISTRYINDEX); @@ -318,7 +305,6 @@ static int conn_close (lua_State *L) { /* Nullify structure fields. */ conn->closed = 1; luaL_unref (L, LUA_REGISTRYINDEX, conn->env); -/* Testar o my_conn ?????? */ mysql_close(conn->my_conn); lua_pushnumber(L, 1); return 1; @@ -335,26 +321,26 @@ static int conn_execute (lua_State *L) { const char *statement = luaL_checkstring (L, 2); unsigned long st_len = strlen(statement); if (!mysql_real_query(conn->my_conn, statement, st_len)) { - unsigned int num_rows, num_cols; + unsigned int num_cols; MYSQL_RES *res; - res = mysql_store_result(conn->my_conn); - num_rows = mysql_affected_rows(conn->my_conn); + res = mysql_use_result(conn->my_conn); num_cols = mysql_field_count(conn->my_conn); + if (res) { /* tuples returned */ - return create_cursor (L, 1, res, num_rows, num_cols); + return create_cursor (L, 1, res, num_cols); } - else { /* mysql_store_result() returned nothing; should it have? */ + else { /* mysql_use_result() returned nothing; should it have? */ if(num_cols == 0) { /* no tuples returned */ /* query does not return data (it was not a SELECT) */ - lua_pushnumber(L, num_rows); + lua_pushnumber(L, mysql_affected_rows(conn->my_conn)); return 1; } - else /* mysql_store_result() should have returned data */ - return luasql_faildirect(L, mysql_error(conn->my_conn)); + else /* mysql_use_result() should have returned data */ + return luasql_failmessage(L, "Error retrieving result. MySQL: ", mysql_error(conn->my_conn)); } } else /* error executing query */ - return luasql_faildirect(L, mysql_error(conn->my_conn)); + return luasql_failmessage(L, "Error executing query. MySQL: ", mysql_error(conn->my_conn)); } @@ -426,9 +412,9 @@ static int env_connect (lua_State *L) { const char *username = luaL_optstring(L, 3, NULL); const char *password = luaL_optstring(L, 4, NULL); const char *host = luaL_optstring(L, 5, NULL); - const char *port = luaL_optstring(L, 6, 0); + const int port = luaL_optint(L, 6, 0); - /* Inicializa o ponteiro da conexao e testa se conseguiu */ + /* Try to init the connection object. */ conn = mysql_init(NULL); if (conn == NULL) return luasql_faildirect(L, LUASQL_PREFIX"Error connecting: Out of memory."); @@ -436,10 +422,11 @@ static int env_connect (lua_State *L) { if (!mysql_real_connect(conn, host, username, password, sourcename, port, NULL, 0)) { - mysql_close(conn); - return luasql_faildirect(L, LUASQL_PREFIX"Error connecting to database."); + char error_msg[100]; + strncpy(error_msg, mysql_error(conn), 99); + mysql_close(conn); /* Close conn if connect failed */ + return luasql_failmessage(L, "Error connecting to database. MySQL: ", error_msg); } - /*mysql_error(&conn)); */ return create_connection(L, 1, conn); } @@ -459,7 +446,6 @@ static int env_close (lua_State *L) { } - /* ** Create metatables for each class of object. */ @@ -482,7 +468,6 @@ static void create_metatables (lua_State *L) { {"getcolnames", cur_getcolnames}, {"getcoltypes", cur_getcoltypes}, {"fetch", cur_fetch}, - {"numrows", cur_numrows}, {NULL, NULL}, }; luasql_createmeta (L, LUASQL_ENVIRONMENT_MYSQL, environment_methods); @@ -490,6 +475,7 @@ static void create_metatables (lua_State *L) { luasql_createmeta (L, LUASQL_CURSOR_MYSQL, cursor_methods); } + /* ** Creates an Environment and returns it. */