From 81ec65adbee8fe22d3d257974af18f492ca1bf22 Mon Sep 17 00:00:00 2001 From: blumf Date: Thu, 29 May 2008 18:44:48 +0000 Subject: [PATCH] Changes to comply with test script. Work in progress. --- src/ls_firebird.c | 366 +++++++++++++++++++++++++--------------------- 1 file changed, 203 insertions(+), 163 deletions(-) diff --git a/src/ls_firebird.c b/src/ls_firebird.c index 04eab02..ea016b0 100644 --- a/src/ls_firebird.c +++ b/src/ls_firebird.c @@ -101,13 +101,33 @@ static void free_cur(cur_data* cur) /* ** Check for valid environment. */ -static env_data *getenvironment (lua_State *L) { - env_data *env = (env_data *)luaL_checkudata (L, 1, LUASQL_ENVIRONMENT_FIREBIRD); - luaL_argcheck (L, env != NULL, 1, "environment expected"); - luaL_argcheck (L, !env->closed, 1, "environment is closed"); +static env_data *getenvironment (lua_State *L, int i) { + env_data *env = (env_data *)luaL_checkudata (L, i, LUASQL_ENVIRONMENT_FIREBIRD); + luaL_argcheck (L, env != NULL, i, "environment expected"); + luaL_argcheck (L, !env->closed, i, "environment is closed"); return env; } +/* +** Check for valid connection. +*/ +static conn_data *getconnection (lua_State *L, int i) { + conn_data *conn = (conn_data *)luaL_checkudata (L, i, LUASQL_CONNECTION_FIREBIRD); + luaL_argcheck (L, conn != NULL, i, "connection expected"); + luaL_argcheck (L, !conn->closed, i, "connection is closed"); + return conn; +} + +/* +** Check for valid cursor. +*/ +static cur_data *getcursor (lua_State *L, int i) { + cur_data *cur = (cur_data *)luaL_checkudata (L, i, LUASQL_CURSOR_FIREBIRD); + luaL_argcheck (L, cur != NULL, i, "cursor expected"); + luaL_argcheck (L, !cur->closed, i, "cursor is closed"); + return cur; +} + /* ** Returns the statment type */ @@ -239,7 +259,7 @@ static int count_rows_affected(cur_data* cur) ** row count: number of rows affected by statement if no results */ static int conn_execute (lua_State *L) { - conn_data *conn = (conn_data *)luaL_checkudata(L,1,LUASQL_CONNECTION_FIREBIRD); + conn_data *conn = getconnection(L,1); const char *statement = luaL_checkstring(L, 2); int dialect = (int)luaL_optnumber(L, 3, 3); @@ -402,6 +422,7 @@ static int conn_execute (lua_State *L) { lua_pushnumber(L, count); /* totaly finnished with the cursor */ + isc_dsql_free_statement(conn->env->status_vector, &cur.stmt, DSQL_drop); free(cur.out_sqlda); } @@ -412,7 +433,7 @@ static int conn_execute (lua_State *L) { ** Commits the current transaction */ static int conn_commit(lua_State *L) { - conn_data *conn = (conn_data *)luaL_checkudata(L,1,LUASQL_CONNECTION_FIREBIRD); + conn_data *conn = getconnection(L,1); /* closed? */ if(conn->closed != 0) { @@ -436,7 +457,7 @@ static int conn_commit(lua_State *L) { ** nil and error message otherwise. */ static int conn_rollback(lua_State *L) { - conn_data *conn = (conn_data *)luaL_checkudata(L,1,LUASQL_CONNECTION_FIREBIRD); + conn_data *conn = getconnection(L,1); /* closed? */ if(conn->closed != 0) { @@ -460,11 +481,11 @@ static int conn_rollback(lua_State *L) { ** nil and error message on error. */ static int conn_setautocommit(lua_State *L) { - conn_data *conn = (conn_data *)luaL_checkudata(L,1,LUASQL_CONNECTION_FIREBIRD); + conn_data *conn = getconnection(L,1); /* closed? */ if(conn->closed != 0) { - lua_pushnil(L); + lua_pushboolean(L, 0); lua_pushstring(L, "connection is closed"); return 2; } @@ -474,7 +495,7 @@ static int conn_setautocommit(lua_State *L) { else conn->autocommit = 0; - lua_pushboolean(L, conn->autocommit); + lua_pushboolean(L, 1); return 1; } @@ -486,6 +507,7 @@ static int conn_setautocommit(lua_State *L) { */ static int conn_close (lua_State *L) { conn_data *conn = (conn_data *)luaL_checkudata(L,1,LUASQL_CONNECTION_FIREBIRD); + luaL_argcheck (L, conn != NULL, 1, "connection expected"); /* already closed */ if(conn->closed != 0) { @@ -518,6 +540,97 @@ static int conn_close (lua_State *L) { return 1; } +/* +** Pushes the indexed value onto the lua stack +*/ +static void push_column(lua_State *L, int i, cur_data *cur) { + int varcharlen; + struct tm timevar; + char timestr[256]; + ISC_STATUS blob_stat; + isc_blob_handle blob_handle = NULL; + ISC_QUAD blob_id; + luaL_Buffer b; + char *buffer; + unsigned short actual_seg_len; + + if( (cur->out_sqlda->sqlvar[i].sqlind != NULL) && + (*(cur->out_sqlda->sqlvar[i].sqlind) != 0) ) { + /* a null field? */ + lua_pushnil(L); + } else { + switch(cur->out_sqlda->sqlvar[i].sqltype & ~1) { + case SQL_VARYING: + varcharlen = (int)isc_vax_integer(cur->out_sqlda->sqlvar[i].sqldata, 2); + lua_pushlstring(L, cur->out_sqlda->sqlvar[i].sqldata+2, varcharlen); + break; + case SQL_TEXT: + lua_pushlstring(L, cur->out_sqlda->sqlvar[i].sqldata, cur->out_sqlda->sqlvar[i].sqllen); + break; + case SQL_SHORT: + lua_pushnumber(L, *(short*)(cur->out_sqlda->sqlvar[i].sqldata)); + break; + case SQL_LONG: + lua_pushnumber(L, *(long*)(cur->out_sqlda->sqlvar[i].sqldata)); + break; + case SQL_INT64: + lua_pushnumber(L, (lua_Number)*(ISC_INT64*)(cur->out_sqlda->sqlvar[i].sqldata)); + break; + case SQL_FLOAT: + lua_pushnumber(L, *(float*)(cur->out_sqlda->sqlvar[i].sqldata)); + break; + case SQL_DOUBLE: + lua_pushnumber(L, *(double*)(cur->out_sqlda->sqlvar[i].sqldata)); + break; + case SQL_TYPE_TIME: + isc_decode_sql_time((ISC_TIME*)(cur->out_sqlda->sqlvar[i].sqldata), &timevar); + strftime(timestr, 255, "%X", &timevar); + lua_pushstring(L, timestr); + break; + case SQL_TYPE_DATE: + isc_decode_sql_date((ISC_DATE*)(cur->out_sqlda->sqlvar[i].sqldata), &timevar); + strftime(timestr, 255, "%x", &timevar); + lua_pushstring(L, timestr); + break; + case SQL_TIMESTAMP: + isc_decode_timestamp((ISC_TIMESTAMP*)(cur->out_sqlda->sqlvar[i].sqldata), &timevar); + strftime(timestr, 255, "%x %X", &timevar); + lua_pushstring(L, timestr); + break; + case SQL_BLOB: + /* get the BLOB ID and open it */ + memcpy(&blob_id, cur->out_sqlda->sqlvar[i].sqldata, sizeof(ISC_QUAD)); + isc_open_blob2( cur->env->status_vector, + &cur->conn->db, &cur->conn->transaction, + &blob_handle, &blob_id, 0, NULL ); + /* fetch the blob data */ + luaL_buffinit(L, &b); + buffer = luaL_prepbuffer(&b); + + blob_stat = isc_get_segment( cur->env->status_vector, + &blob_handle, &actual_seg_len, + LUAL_BUFFERSIZE, buffer ); + while(blob_stat == 0 || cur->env->status_vector[1] == isc_segment) { + luaL_addsize(&b, actual_seg_len); + buffer = luaL_prepbuffer(&b); + blob_stat = isc_get_segment( cur->env->status_vector, + &blob_handle, &actual_seg_len, + LUAL_BUFFERSIZE, buffer ); + } + + /* finnished, close the BLOB */ + isc_close_blob(cur->env->status_vector, &blob_handle); + blob_handle = NULL; + + luaL_pushresult(&b); + break; + default: + lua_pushstring(L, ""); + break; + } + } +} + /* ** Returns a row of data from the query ** Lua Returns: @@ -526,17 +639,11 @@ static int conn_close (lua_State *L) { */ static int cur_fetch (lua_State *L) { ISC_STATUS fetch_stat; - struct tm timevar; - char timestr[256]; - int i, varcharlen; - int fetch_mode = 0; - isc_blob_handle blob_handle = NULL; - ISC_QUAD blob_id; - unsigned short actual_seg_len; - ISC_STATUS blob_stat; - char *buffer; - luaL_Buffer b; - cur_data *cur = (cur_data *)luaL_checkudata(L,1,LUASQL_CURSOR_FIREBIRD); + int i; + cur_data *cur = getcursor(L,1); + const char *opts = luaL_optstring (L, 3, "n"); + int num = strchr(opts, 'n') != NULL; + int alpha = strchr(opts, 'a') != NULL; /* closed? */ if(cur->closed != 0) { @@ -545,124 +652,39 @@ static int cur_fetch (lua_State *L) { return 2; } - /* is a table provided? */ - if( lua_gettop(L) > 1 ) { - fetch_mode = 1; - - if(!lua_istable (L, 2)) { - lua_pushnil(L); - lua_pushstring(L, "Need table in paramter 1"); - return 2; - } - } - - /* do we have a fetch mode? */ - if( (lua_gettop(L) > 2) ) { - if((strcmp(lua_tostring(L, 3), "a") == 0) ) - fetch_mode = 2; - lua_settop(L, 2); - } - if ((fetch_stat = isc_dsql_fetch(cur->env->status_vector, &cur->stmt, 1, cur->out_sqlda)) == 0) { - /* loop through the columns */ - for (i = 0; i < cur->out_sqlda->sqld; i++) { - /* push the field index (1-base) onto the stack*/ - if( fetch_mode == 1 ) { - lua_pushnumber(L, i+1); - } + if (lua_istable (L, 2)) { + /* remove the option string */ + lua_settop(L, 2); - if( fetch_mode == 2) { - lua_pushlstring(L, cur->out_sqlda->sqlvar[i].aliasname, cur->out_sqlda->sqlvar[i].aliasname_length); - } + /* loop through the columns */ + for (i = 0; i < cur->out_sqlda->sqld; i++) { + push_column(L, i, cur); - if( (cur->out_sqlda->sqlvar[i].sqlind != NULL) && - (*(cur->out_sqlda->sqlvar[i].sqlind) != 0) ) { - /* a null field? */ - lua_pushnil(L); - } else { - switch(cur->out_sqlda->sqlvar[i].sqltype & ~1) { - case SQL_VARYING: - varcharlen = (int)isc_vax_integer(cur->out_sqlda->sqlvar[i].sqldata, 2); - lua_pushlstring(L, cur->out_sqlda->sqlvar[i].sqldata+2, varcharlen); - break; - case SQL_TEXT: - lua_pushlstring(L, cur->out_sqlda->sqlvar[i].sqldata, cur->out_sqlda->sqlvar[i].sqllen); - break; - case SQL_SHORT: - lua_pushnumber(L, *(short*)(cur->out_sqlda->sqlvar[i].sqldata)); - break; - case SQL_LONG: - lua_pushnumber(L, *(long*)(cur->out_sqlda->sqlvar[i].sqldata)); - break; - case SQL_INT64: - lua_pushnumber(L, (lua_Number)*(ISC_INT64*)(cur->out_sqlda->sqlvar[i].sqldata)); - break; - case SQL_FLOAT: - lua_pushnumber(L, *(float*)(cur->out_sqlda->sqlvar[i].sqldata)); - break; - case SQL_DOUBLE: - lua_pushnumber(L, *(double*)(cur->out_sqlda->sqlvar[i].sqldata)); - break; - case SQL_TYPE_TIME: - isc_decode_sql_time((ISC_TIME*)(cur->out_sqlda->sqlvar[i].sqldata), &timevar); - strftime(timestr, 255, "%X", &timevar); - lua_pushstring(L, timestr); - break; - case SQL_TYPE_DATE: - isc_decode_sql_date((ISC_DATE*)(cur->out_sqlda->sqlvar[i].sqldata), &timevar); - strftime(timestr, 255, "%x", &timevar); - lua_pushstring(L, timestr); - break; - case SQL_TIMESTAMP: - isc_decode_timestamp((ISC_TIMESTAMP*)(cur->out_sqlda->sqlvar[i].sqldata), &timevar); - strftime(timestr, 255, "%x %X", &timevar); - lua_pushstring(L, timestr); - break; - case SQL_BLOB: - /* get the BLOB ID and open it */ - memcpy(&blob_id, cur->out_sqlda->sqlvar[i].sqldata, sizeof(ISC_QUAD)); - isc_open_blob2( cur->env->status_vector, - &cur->conn->db, &cur->conn->transaction, - &blob_handle, &blob_id, 0, NULL ); - /* fetch the blob data */ - luaL_buffinit(L, &b); - buffer = luaL_prepbuffer(&b); - - blob_stat = isc_get_segment( cur->env->status_vector, - &blob_handle, &actual_seg_len, - LUAL_BUFFERSIZE, buffer ); - while(blob_stat == 0 || cur->env->status_vector[1] == isc_segment) { - luaL_addsize(&b, actual_seg_len); - buffer = luaL_prepbuffer(&b); - blob_stat = isc_get_segment( cur->env->status_vector, - &blob_handle, &actual_seg_len, - LUAL_BUFFERSIZE, buffer ); - } - - /* finnished, close the BLOB */ - isc_close_blob(cur->env->status_vector, &blob_handle); - blob_handle = NULL; - - luaL_pushresult(&b); - break; - default: - lua_pushstring(L, ""); - break; + if( num ) { + lua_pushnumber(L, i+1); + lua_pushvalue(L, -2); + lua_settable(L, 2); } + + if( alpha ) { + lua_pushlstring(L, cur->out_sqlda->sqlvar[i].aliasname, cur->out_sqlda->sqlvar[i].aliasname_length); + lua_pushvalue(L, -2); + lua_settable(L, 2); + } + + lua_pop(L, 1); } - /* fill the table */ - if( fetch_mode > 0 ) { - lua_settable(L, 2); - } - } - - /* just returning a table */ - if( fetch_mode > 0 ) + /* returning given table */ return 1; + } else { + for (i = 0; i < cur->out_sqlda->sqld; i++) + push_column(L, i, cur); - /* returning a list of values */ - return cur->out_sqlda->sqld; + /* returning a list of values */ + return cur->out_sqlda->sqld; + } } /* isc_dsql_fetch returns 100 if no more rows remain to be retrieved @@ -670,6 +692,20 @@ static int cur_fetch (lua_State *L) { if (fetch_stat != 100L) return return_db_error(L, cur->env->status_vector); + /* last row has been fetched, close cursor */ + isc_dsql_free_statement(cur->env->status_vector, &cur->stmt, DSQL_drop); + if ( CHECK_DB_ERROR(cur->env->status_vector) ) + return return_db_error(L, cur->env->status_vector); + + /* free the cursor data */ + free_cur(cur); + + cur->closed = 1; + + /* remove cursor from lock count */ + --cur->conn->lock; + + /* return sucsess */ return 0; } @@ -682,7 +718,7 @@ static int cur_fetch (lua_State *L) { static int cur_colnames (lua_State *L) { int i; XSQLVAR *var; - cur_data *cur = (cur_data *)luaL_checkudata(L,1,LUASQL_CURSOR_FIREBIRD); + cur_data *cur = getcursor(L,1); /* closed? */ if(cur->closed != 0) { @@ -711,7 +747,7 @@ static int cur_colnames (lua_State *L) { static int cur_coltypes (lua_State *L) { int i; XSQLVAR *var; - cur_data *cur = (cur_data *)luaL_checkudata(L,1,LUASQL_CURSOR_FIREBIRD); + cur_data *cur = getcursor(L,1); /* closed? */ if(cur->closed != 0) { @@ -724,7 +760,7 @@ static int cur_coltypes (lua_State *L) { for (i=1, var = cur->out_sqlda->sqlvar; i <= cur->out_sqlda->sqld; i++, var++) { lua_pushnumber(L, i); - switch(var->sqltype) { + switch(var->sqltype & ~1) { case SQL_VARYING: case SQL_TEXT: case SQL_TYPE_TIME: @@ -758,11 +794,12 @@ static int cur_coltypes (lua_State *L) { */ static int cur_close (lua_State *L) { cur_data *cur = (cur_data *)luaL_checkudata(L,1,LUASQL_CURSOR_FIREBIRD); + luaL_argcheck (L, cur != NULL, 1, "cursor expected"); - if(cur->closed == 0 ) { + if(cur->closed == 0) { isc_dsql_free_statement(cur->env->status_vector, &cur->stmt, DSQL_drop); - if ( CHECK_DB_ERROR(cur->env->status_vector) ) - return return_db_error(L, cur->env->status_vector); + if ( CHECK_DB_ERROR(cur->env->status_vector) ) + return return_db_error(L, cur->env->status_vector); /* free the cursor data */ free_cur(cur); @@ -813,12 +850,13 @@ static int env_connect (lua_State *L) { int i; static char isc_tpb[] = { isc_tpb_version3, isc_tpb_write }; - conn_data* conn; + conn_data conn; + conn_data* res_conn; - env_data *env = (env_data *) getenvironment (L); + env_data *env = (env_data *) getenvironment (L, 1); const char *sourcename = luaL_checkstring (L, 2); - const char *username = luaL_checkstring (L, 3); - const char *password = luaL_checkstring (L, 4); + const char *username = luaL_optstring (L, 3, ""); + const char *password = luaL_optstring (L, 4, ""); /* check for an open enviroment */ if(env->closed != 0) { @@ -826,18 +864,15 @@ static int env_connect (lua_State *L) { lua_pushstring(L, "Enviroment is closed"); } - conn = (conn_data*)lua_newuserdata(L, sizeof(conn_data)); - luasql_setmeta (L, LUASQL_CONNECTION_FIREBIRD); - - conn->closed = 0; - conn->env = env; - conn->db = 0L; - conn->transaction = 0L; - conn->lock = 0; - conn->autocommit = 0; + conn.closed = 0; + conn.env = env; + conn.db = 0L; + conn.transaction = 0L; + conn.lock = 0; + conn.autocommit = 0; /* Construct a database parameter buffer. */ - dpb = conn->dpb_buffer; + dpb = conn.dpb_buffer; *dpb++ = isc_dpb_version1; *dpb++ = isc_dpb_num_buffers; *dpb++ = 1; @@ -854,26 +889,30 @@ static int env_connect (lua_State *L) { *dpb++ = password[i]; /* the length of the dpb */ - conn->dpb_length = (short)(dpb - conn->dpb_buffer); + conn.dpb_length = (short)(dpb - conn.dpb_buffer); /* do the job */ - isc_attach_database(env->status_vector, (short)strlen(sourcename), (char*)sourcename, &conn->db, - conn->dpb_length, conn->dpb_buffer); + isc_attach_database(env->status_vector, (short)strlen(sourcename), (char*)sourcename, &conn.db, + conn.dpb_length, conn.dpb_buffer); /* an error? */ - if ( CHECK_DB_ERROR(conn->env->status_vector) ) - return return_db_error(L, conn->env->status_vector); + if ( CHECK_DB_ERROR(conn.env->status_vector) ) + return return_db_error(L, conn.env->status_vector); /* open up the transaction handle */ - isc_start_transaction( env->status_vector, &conn->transaction, 1, - &conn->db, (unsigned short)sizeof(isc_tpb), + isc_start_transaction( env->status_vector, &conn.transaction, 1, + &conn.db, (unsigned short)sizeof(isc_tpb), isc_tpb ); /* return NULL on error */ - if ( CHECK_DB_ERROR(conn->env->status_vector) ) - return return_db_error(L, conn->env->status_vector); + if ( CHECK_DB_ERROR(conn.env->status_vector) ) + return return_db_error(L, conn.env->status_vector); + + /* create the lua object and add the connection to the lock */ + res_conn = (conn_data*)lua_newuserdata(L, sizeof(conn_data)); + luasql_setmeta (L, LUASQL_CONNECTION_FIREBIRD); + memcpy(res_conn, &conn, sizeof(conn_data)); - /* add the connection to the lock */ ++env->lock; return 1; @@ -886,8 +925,9 @@ static int env_connect (lua_State *L) { ** nil and error message otherwise. */ static int env_close (lua_State *L) { - env_data *env = (env_data *)luaL_checkudata(L, 1, LUASQL_ENVIRONMENT_FIREBIRD); - + env_data *env = (env_data *)luaL_checkudata (L, 1, LUASQL_ENVIRONMENT_FIREBIRD); + luaL_argcheck (L, env != NULL, 1, "environment expected"); + /* already closed? */ if(env->closed == 1) { lua_pushboolean(L, 0);