当前位置: 代码迷 >> SQL >> LUA C库 Luasql OCI8增多带参数存储过程调用支持
  详细解决方案

LUA C库 Luasql OCI8增多带参数存储过程调用支持

热度:486   发布时间:2016-05-05 13:21:25.0
LUA C库 Luasql OCI8增加带参数存储过程调用支持
     Luasql原始的oci8中对于存储过程只能支持无参数的存储过程的调用,现在我在里边加入一个stmt结构来支持带参数尤其是对cursor输出,的支持,需要做的就是实现一个statement的userdata来完成需要的工作bind_number, bind_string, bind_cursor:
用到的主要数据结构:
typedef union {	int     i;	char   *s;	double  d;	OCIStmt *c; //add by alien} column_value; /*****************author:aliendate:2011-11-27an SQL statement******************/typedef struct {	ub2				type;    /* database type */	OCIBind			*bind;  /* define handle */	int				direction;	column_value	val;} bind_data;typedef struct{	short       closed;	int			conn;	int			numpars;	bind_data	*parvals;	char		*text;		OCIStmt		*stmthp;	OCIError	*errhp; /* !!! */} stmt_data;


在connection metatable中增加prepare方法来返回stmt环境:
/************************************************************author:aliendate:2011-11-27create an SQL statement*************************************************************/static int create_statement (lua_State *L, int o, conn_data *conn, OCIStmt *stmthp, const char *text, int numparam){	env_data *env;	stmt_data *stmt = (stmt_data *)lua_newuserdata(L, sizeof(stmt_data));	luasql_setmeta (L, LUASQL_STATEMENT_OCI8);	/* fill in structure */	stmt->closed = 0;	stmt->numpars = numparam;	stmt->stmthp = stmthp;	stmt->errhp = NULL;	stmt->parvals = NULL;	stmt->text = strdup (text);	lua_pushvalue (L, o);	stmt->conn = luaL_ref (L, LUA_REGISTRYINDEX);	/* error handler */	lua_rawgeti (L, LUA_REGISTRYINDEX, conn->env);	env = lua_touserdata (L, -1);	lua_pop (L, 1);	ASSERT (L, OCIHandleAlloc((dvoid *) env->envhp,		(dvoid **) &(stmt->errhp), (ub4) OCI_HTYPE_ERROR, (size_t) 0,		(dvoid **) 0), conn->errhp);	stmt->parvals = (bind_data *)malloc(sizeof(bind_data)*stmt->numpars);	/* C array indices ranges from 0 to numcols-1 */	return 1;}/************************************************************author:aliendate:2011-11-27prapare an SQL statement*************************************************************/static int conn_prepare(lua_State* L){	env_data *env;	conn_data *conn = getconnection (L);	const char *statement = luaL_checkstring (L, 2);	const int numparam = getparameternum(statement);	OCIStmt *stmthp = NULL;	/* get environment */	lua_rawgeti (L, LUA_REGISTRYINDEX, conn->env);	if (!lua_isuserdata (L, -1))		luaL_error(L,LUASQL_PREFIX"invalid environment in connection!");	env = (env_data *)lua_touserdata (L, -1);	/* statement handle */	ASSERT (L, OCIHandleAlloc ((dvoid *)env->envhp, (dvoid **)&stmthp,		OCI_HTYPE_STMT, (size_t)0, (dvoid **)0), conn->errhp);	ASSERT (L, OCIStmtPrepare (stmthp, conn->errhp, (text *)statement,		(ub4) strlen(statement), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT),		conn->errhp);	return create_statement (L, 1, conn, stmthp, statement, numparam);}


主要实现:
/************************************************************author:aliendate:2011-11-27dispose an SQL statement*************************************************************/static int stmt_close(lua_State* L){	int i, ret;	conn_data *conn;	stmt_data *stmt = (cur_data *)luaL_checkudata (L, 1, LUASQL_STATEMENT_OCI8);	luaL_argcheck (L, stmt != NULL, 1, LUASQL_PREFIX"statement expected");	if (stmt->closed) {		lua_pushboolean (L, 0);		return 1;	}	/* Deallocate buffers. */	for (i = 0; i <= stmt->numpars; i++) {		if( stmt->parvals[i].type == STRING )			free(stmt->parvals[i].val.s);		/*else if( stmt->parvals[i].type == CURSOR ){			lua_rawgeti(L, LUA_REGISTRYINDEX, stmt->parvals[i].val.c);			cur_close(L);		}*/	}	free(stmt->parvals);	free(stmt->text);	/* Nullify structure fields. */	stmt->closed = 1;	if (stmt->stmthp)		OCIHandleFree ((dvoid *)stmt->stmthp, OCI_HTYPE_STMT);	if (stmt->errhp)		OCIHandleFree ((dvoid *)stmt->errhp, OCI_HTYPE_ERROR);	/* Decrement cursor counter on connection object */	lua_rawgeti (L, LUA_REGISTRYINDEX, stmt->conn);	conn = lua_touserdata (L, -1);	conn->cur_counter--;	luaL_unref (L, LUA_REGISTRYINDEX, stmt->conn);	lua_pushboolean (L, 1);	return 1;}/************************************************************author:aliendate:2011-11-27bind integer to an SQL statement*************************************************************/static int stmt_bind_number(lua_State* L){	stmt_data *stmt = getstatement (L);	const int pos = luaL_checknumber(L, 2) - 1;	const int num = luaL_checknumber(L, 3);	const int direction = luaL_checknumber(L, 4);	stmt->parvals[pos].direction = direction;	stmt->parvals[pos].type = NUMBER;	stmt->parvals[pos].val.i = num;	/*ASSERT (L, OCIBindByPos(stmt->stmthp, &stmt->parvals[pos].bind, stmt->errhp, pos, &(stmt->parvals[pos].val.i), sizeof(stmt->parvals[pos].val.i),		SQLT_NUM, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT), stmt->errhp);*/	/*printf("pos: %d statement: %s bind_number: %d\n", pos, stmt->text, stmt->parvals[pos].val.i);	error_proc(stmt->errhp, OCIBindByPos(stmt->stmthp, &(stmt->parvals[pos].bind), stmt->errhp, (ub4)pos, &(num), sizeof(num),		SQLT_NUM, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT));*/	lua_pushboolean (L, 1);	return 1;}/************************************************************author:aliendate:2011-11-27bind string to an SQL statement*************************************************************/static int stmt_bind_string(lua_State* L){	stmt_data *stmt = getstatement (L);	const int pos = luaL_checknumber(L, 2) - 1;	const char* text = luaL_checkstring(L, 3);	const int direction = luaL_checknumber(L, 4);	stmt->parvals[pos].direction = direction;	stmt->parvals[pos].type = STRING;	stmt->parvals[pos].val.s = (char*)calloc(strlen(text)+1, sizeof(char));	strcpy(stmt->parvals[pos].val.s, text);	/*ASSERT (L, OCIBindByPos(stmt->stmthp, &stmt->parvals[pos].bind, stmt->errhp, pos, &(stmt->parvals[pos].val.s), strlen(stmt->parvals[pos].val.s) + 1,		SQLT_NUM, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT), stmt->errhp);*/	/*printf("bind_string>> stmthp: %d\n", stmt->stmthp);	error_proc(stmt->errhp, OCIBindByPos(stmt->stmthp, &(stmt->parvals[pos-1].bind), stmt->errhp, (ub4)pos + 1, &(stmt->parvals[pos].val.s), strlen(stmt->parvals[pos].val.s) + 1,		SQLT_STR, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT));*/	lua_pushboolean (L, 1);	return 1;}/************************************************************author:aliendate:2011-11-27bind an cursor to an SQL statement*************************************************************/static int stmt_bind_cursor(lua_State* L){		env_data *env;	conn_data *conn;	stmt_data *stmt = getstatement (L);	const int pos = luaL_checknumber(L, 2) - 1;	const int direction = luaL_checknumber(L, 3);	stmt->parvals[pos].type = CURSOR;	stmt->parvals[pos].direction = direction;	stmt->parvals[pos].val.c = NULL;		lua_rawgeti (L, LUA_REGISTRYINDEX, stmt->conn);	conn = lua_touserdata (L, -1);	lua_rawgeti (L, LUA_REGISTRYINDEX, conn->env);	env = lua_touserdata (L, -1);	lua_pop(L, 2);	ASSERT(L, OCIHandleAlloc((dvoid*)env->envhp, (dvoid**)&(stmt->parvals[pos].val.c), OCI_HTYPE_STMT, 0, (dvoid**)0), stmt->errhp);		/*ASSERT(L, OCIBindByPos(stmt->stmthp, &stmt->parvals[pos].bind, stmt->errhp, pos, &(stmt->parvals[pos].val.i), sizeof(stmt->parvals[pos].val.i),		SQLT_NUM, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT), stmt->errhp);*/	/*printf("bind_cursor>> stmthp: %d cursor: %d\n", stmt->stmthp, stmt->parvals[pos].val.c);	error_proc(stmt->errhp, OCIBindByPos(stmt->stmthp, &stmt->parvals[pos].bind, stmt->errhp, pos + 1, &(stmt->parvals[pos].val.c), sizeof(stmt->parvals[pos].val.c),		SQLT_RSET, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT));*/	/*error_proc(stmt->errhp, OCIBindByPos(stmt->stmthp, &(stmt->parvals[i].bind), stmt->errhp, i + 1, &(stmt->parvals[i].val.c), sizeof(stmt->parvals[i].val.c),		SQLT_RSET, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT));*/	lua_pushboolean (L, 1);	return 1;}/************************************************************author:aliendate:2011-11-27handle an SQL statement*************************************************************/static int data_handle(lua_State *L, stmt_data* stmt){	int top = lua_gettop(L), i, res = 0;	env_data *env = NULL;	conn_data *conn = NULL;	cur_data *cur = NULL;	OCIStmt* curstmt = NULL;	//debug	//printf("handle>> top: %d\n", top);	for (i =  0; i < stmt->numpars; i++) {		//printf("handle>> %d> io: %d type: %d res: %d\n", i, stmt->parvals[i].direction, stmt->parvals[i].type, res);		if ( OUT == stmt->parvals[i].direction ) {			if ( NUMBER == stmt->parvals[i].type ){				//printf("handle>> number: %u\n", stmt->parvals[i].val.i);				lua_pushnumber( L, stmt->parvals[i].val.i );				res++;			}			if ( STRING == stmt->parvals[i].type ){				//printf("handle>> string: %s\n", stmt->parvals[i].val.s);				lua_pushlstring( L, stmt->parvals[i].val.s, strlen(stmt->parvals[i].val.s) );				res++;			}			if ( CURSOR == stmt->parvals[i].type ){				curstmt = stmt->parvals[i].val.c;				cur = (cur_data *)lua_newuserdata(L, sizeof(cur_data));				luasql_setmeta (L, LUASQL_CURSOR_OCI8);				//printf("handle>> cursor: %d\n", stmt->parvals[i].val.c);				lua_rawgeti (L, LUA_REGISTRYINDEX, stmt->conn);				conn = lua_touserdata (L, -1);				cur->conn = luaL_ref(L, LUA_REGISTRYINDEX);				lua_rawgeti (L, LUA_REGISTRYINDEX, conn->env);				env = lua_touserdata (L, -1);				lua_pop(L, 1);				conn->cur_counter++;				/* fill in structure */				cur->closed = 0;				cur->numcols = 0;				cur->colnames = LUA_NOREF;				cur->coltypes = LUA_NOREF;				cur->curr_tuple = 0;				cur->stmthp = curstmt;				cur->errhp = NULL;				cur->cols = NULL;				cur->text = strdup (stmt->text);				//debug				/*top = lua_gettop(L);				printf("handle>> top: %d\n", top);*/				ASSERT (L, OCIHandleAlloc((dvoid *) env->envhp,					(dvoid **) &(cur->errhp), (ub4) OCI_HTYPE_ERROR, (size_t) 0,					(dvoid **) 0), conn->errhp);				/* get number of columns */				ASSERT (L, OCIAttrGet ((dvoid *)curstmt, (ub4)OCI_HTYPE_STMT,					(dvoid *)&cur->numcols, (ub4 *)0, (ub4)OCI_ATTR_PARAM_COUNT,					cur->errhp), cur->errhp);				//debug				//printf("handle>> numcols: %d\n", cur->numcols );				cur->cols = (column_data *)malloc (sizeof(column_data) * cur->numcols);				/* define output variables */				/* Oracle and Lua column indices ranges from 1 to numcols */				/* C array indices ranges from 0 to numcols-1 */				for (i = 1; i <= cur->numcols; i++) {					int ret = alloc_column_buffer (L, cur, i);					if (ret)						return ret;				}				res++;			}		}		}	return res;	}/************************************************************author:aliendate:2011-11-27execute an SQL statement*************************************************************/static int stmt_execute(lua_State* L){	int i = 0;	env_data *env;	conn_data *conn;	stmt_data *stmt = getstatement (L);	sword status;	ub4 prefetch = 0;	ub4 iters;	ub4 mode;	ub2 type;	/* get environment */	lua_rawgeti(L, LUA_REGISTRYINDEX, stmt->conn);	conn = (conn_data*)lua_touserdata(L, -1);	lua_rawgeti (L, LUA_REGISTRYINDEX, conn->env);	if (!lua_isuserdata (L, -1))		luaL_error(L,LUASQL_PREFIX"invalid environment in connection!");	env = (env_data *)lua_touserdata (L, -1);	lua_pop(L, 2);	//debug	//printf("execute>> text: %s\n", stmt->text);	/* statement handle */	ASSERT (L, OCIAttrSet ((dvoid *)stmt->stmthp, (ub4)OCI_HTYPE_STMT,		(dvoid *)&prefetch, (ub4)0, (ub4)OCI_ATTR_PREFETCH_ROWS,		conn->errhp), conn->errhp);	/* statement type */	ASSERT (L, OCIAttrGet ((dvoid *)stmt->stmthp, (ub4) OCI_HTYPE_STMT,		(dvoid *)&type, (ub4 *)0, (ub4)OCI_ATTR_STMT_TYPE, conn->errhp),		conn->errhp);		if (type == OCI_STMT_SELECT)		iters = 0;	else		iters = 1;	if (conn->auto_commit)		mode = OCI_COMMIT_ON_SUCCESS;	else		mode = OCI_DEFAULT;	// Bind data to SQLStatement	for ( i = 0; i < stmt->numpars; i++)	{		//debug		//printf("execute>> %d %s %d\n", i, stmt->parvals[0].val.s, stmt->numpars);		switch(stmt->parvals[i].type){			case NUMBER:				ASSERT (L, OCIBindByPos(stmt->stmthp, &(stmt->parvals[i].bind), stmt->errhp, i + 1, &(stmt->parvals[i].val.i), sizeof(stmt->parvals[i].val.i),					SQLT_INT, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT), stmt->errhp);				break;			case STRING:				ASSERT (L, OCIBindByPos(stmt->stmthp, &(stmt->parvals[i].bind), stmt->errhp, i + 1, stmt->parvals[i].val.s, strlen(stmt->parvals[i].val.s) + 1,					SQLT_STR, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT), stmt->errhp);				break;			case CURSOR:				ASSERT (L, OCIBindByPos(stmt->stmthp, &(stmt->parvals[i].bind), stmt->errhp, i + 1, &(stmt->parvals[i].val.c), sizeof(stmt->parvals[i].val.c),					SQLT_RSET, NULL, NULL, NULL, 0, NULL, (ub4)OCI_DEFAULT), stmt->errhp);				break;			default:				break;		}		}	status = OCIStmtExecute (conn->svchp, stmt->stmthp, conn->errhp, iters,		(ub4)0, (CONST OCISnapshot *)NULL, (OCISnapshot *)NULL, mode);	//debug	//printf("execute>> type: %d status: %d\n", type, status);		if (status && (status != OCI_NO_DATA)) {		//debug		/*text errbuf[512]; 		sb4 errcode; 		(void)OCIErrorGet((dvoid *)conn->errhp,(ub4)1,NULL,&errcode, 			errbuf,(ub4)sizeof(errbuf),OCI_HTYPE_ERROR); 		printf("错误号:%d\n错误信息:%s\n",errcode,errbuf); */		OCIHandleFree ((dvoid *)stmt->stmthp, OCI_HTYPE_STMT);		return checkerr (L, status, conn->errhp);	}	//get data	if ( OCI_STMT_SELECT == type) {		/* create cursor */		return create_cursor (L, 1, conn, stmt->stmthp, stmt->text);	}	else if ( OCI_STMT_BEGIN == type ){		/* handle the bind data */		return data_handle(L, stmt);	}	else {		/* return number of rows */		int rows_affected;		ASSERT (L, OCIAttrGet ((dvoid *)stmt->stmthp, (ub4)OCI_HTYPE_STMT,			(dvoid *)&rows_affected, (ub4 *)0,			(ub4)OCI_ATTR_ROW_COUNT, conn->errhp), conn->errhp);		OCIHandleFree ((dvoid *)stmt->stmthp, OCI_HTYPE_STMT);		lua_pushnumber (L, rows_affected);		return 1;	}}


LUA接口导出:
#define LUASQL_STATEMENT_OCI8 "Oracle statement"struct luaL_reg connection_methods[] = {		{"close", conn_close},		{"prepare", conn_prepare}, //add		{"execute", conn_execute},		{"commit", conn_commit},		{"rollback", conn_rollback},		{"setautocommit", conn_setautocommit},		{NULL, NULL},	};struct luaL_reg statement_methods[] = {		{"close", stmt_close},		{"bind_number", stmt_bind_number},		{"bind_string", stmt_bind_string},		{"bind_cursor", stmt_bind_cursor},		{"execute", stmt_execute},		{NULL, NULL}	};	//add by alienluasql_createmeta (L, LUASQL_STATEMENT_OCI8, statement_methods);