[ESQL游标]用字符串指针作为where后的匹配项导致数据丢失问题
本帖最后由 dreamtang 于 2010-07-31 17:51 编辑代码在SCO unix上,网络没设置好,不能telnet进去。程序所操作的数据库是INFORMIX_SE。
代码大概的逻辑下面应该能说清楚:
void get_str(char *myid, char *mypwd, int *mytype, char *myname)
{
EXEC SQL BEGIN DECLARE SECTION ;
char *getid = NULL ;
char *getpwd = NULL ;
int *gettype = NULL ;
char *getname = NULL ;
EXEC SQL END DECLARE SECTION ;
getid = myid ;
getpwd = mypwd ;
gettype = mytype ;
getname = myname ;
EXEC SQL DECLARE get_info cursor for
select pwd, type, name
into $getpwd, $*gettype, $getname
from operaform
where id = $getid ;
EXEC SQL OPEN get_info ;
EXEC SQL FETCH get_info ;//问题出在这里,当FETCH完之后,“getid”里原有的数据就没了。
EXEC SQL close get_info ;
EXEC SQL free get_info ;
}
int main()
{
char id = "s001" ;
char password ;
int type = 0 ;
char name = "unknowed" ;
EXEC SQL BEGIN DECLARE SECTION ;
char path[] = "/usr/student/informix_database/operaform" ;
EXEC SQL END DECLARE SECTION ;
EXEC SQL DATABASE $path ;
get_str(id, password, &type, name) ;--执行完成后,printf("%s\n", id) 输出基本也是空的,而不是输出"s001"
EXEC SQL CLOSE DATABASE ;
return (0) ;
}
--请问这是什么问题?
--还有,为什么在定义游标的时候,在into后不能使用“:myid”来使用c语言变量?我希望可以在游标里直接把数据存储到函数形参表里的形参中。
--最后,时间紧迫~~DX帮帮忙~ 本帖最后由 dreamtang 于 2010-07-31 17:28 编辑
刚telnet进去把源文件拷贝出来,帖一下代码:
EXEC SQL INCLUDE sqlca.h ;
#include <stdio.h>
#include <string.h>
void get_str_out(char *myid, char *mypwd, int *mytype, char *myname)
{
EXEC SQL BEGIN DECLARE SECTION ;
char *temp_id = NULL ;
char *getid = NULL ;
char *getpwd = NULL ;
int *gettype = NULL ;
char *getname = NULL ;
EXEC SQL END DECLARE SECTION ;
//strcpy(temp_id, myid) ;
getid = myid ;
getpwd = mypwd ;
gettype = mytype ;
getname = myname ;
printf("myid = %s, getid = %s, myidAdd=%d, getidAdd=%d\n", myid, getid, myid, getid) ;
EXEC SQL DECLARE get_str cursor for
select pwd, type, name
into $getpwd, $*gettype, $getname
from operaform
where id = $getid ;
printf("1getid = %s.\n", getid) ; //输出“3getid = s001"
EXEC SQL OPEN get_str ;
printf("2getid = %s.\n", getid) ; //输出“3getid = s001"
if (SQLCODE != 0)
{
printf("Failed to open cursor.\n") ;
return ;
}
EXEC SQL FETCH get_str ;
printf("3getid = %s.\n", getid) ; //输出“3getid = .”
if (SQLCODE == 0)
{
printf("ID = %s, pwd = %s, type = %d, name = %s\n", getid, getpwd, *gettype, getname) ;
EXEC SQL CLOSE get_str ;
printf("4getid = %s.\n", getid) ; //输出“3getid = .”
EXEC SQL FREE get_str ;
printf("5getid = %s.\n", getid) ; //输出“3getid = .”
return ;
}
else if (SQLCODE == 100)
{
printf("No such user.\n") ;
EXEC SQL CLOSE get_str ;
EXEC SQL FREE get_str ;
return ;
}
else
{
printf("Failed to fetch cursor.\n") ;
EXEC SQL CLOSE get_str ;
EXEC SQL FREE get_str ;
}
//strcpy(myid, temp_id) ;
return ;
}
void main()
{
char myid = "s001" ;
char mypwd ;
char myname ;
int mytype ;
$char path[] = "/usr/linkang/informix_database/operaform" ;
EXEC SQL DATABASE $path ;
if (SQLCODE != 0)
{
printf("Failed to open database.\n") ;
return ;
}
printf("1id = %d, pwd = %d,name=%d\n", myid, mypwd, myname) ;
get_str_out(myid, mypwd, &mytype, myname) ;
printf("1ID = %s, PWD = %s, TYPE = %d, NAME = %s\n", myid, mypwd, mytype, myname) ;
EXEC SQL CLOSE DATABASE ;
if (SQLCODE != 0)
{
printf("Failed to close database.\n") ;
return ;
}
return ;
} 我帮你修改下了,不过你的程序问题比较多。
EXEC SQL INCLUDE sqlca.h ;
#include <stdio.h>
#include <string.h>
void get_str_out(char *myid,char *mypwd,long *mytype,char *myname )
{
EXEC SQL BEGIN DECLARE SECTION ;
char temp_id = NULL ;
char getid ;
char getpwd ;
long gettype ;
char getname ;
EXEC SQL END DECLARE SECTION ;
//strcpy(temp_id, myid) ;
strcpy(getid,myid);
printf("myid = %s, getid = %s\n", myid, getid) ;
EXEC SQL DECLARE get_str cursor for
select pwd, type, name
/* into $getpwd, $*gettype, $getname */
into :getpwd, :gettype, :getname
from operaform
where id = :getid ;
printf("1getid = %s.\n", getid) ;
EXEC SQL OPEN get_str ;
printf("2getid = %s.\n", getid) ;
if (SQLCODE)
{
printf("Failed to open cursor.\n") ;
return ;
}
EXEC SQL FETCH get_str ;
printf("3getid = %s %d.\n", getid,gettype) ;
if (SQLCODE == 0)
{
printf("ID = %s, pwd = %s, type = %d, name = %s\n", getid, getpwd, gettype, getname) ;
strcpy(mypwd,getpwd);
*mytype = gettype;
strcpy(myname,getname);
EXEC SQL CLOSE get_str ;
printf("4getid = %s.%d\n", getid,mytype) ;
EXEC SQL FREE get_str ;
printf("5getid = %s.\n", getid) ;
return ;
}
else if (SQLCODE == 100)
{
printf("No such user.\n") ;
EXEC SQL CLOSE get_str ;
EXEC SQL FREE get_str ;
return ;
}
else
{
printf("Failed to fetch cursor.\n") ;
EXEC SQL CLOSE get_str ;
EXEC SQL FREE get_str ;
}
//strcpy(myid, temp_id) ;
return ;
}
void main()
{
char myid = "s001" ;
char mypwd ;
char myname ;
long mytype ;
memset(mypwd,0x00,sizeof(mypwd));
memset(myname,0x00,sizeof(myname));
/* $char path[] = "/usr/linkang/informix_database/operaform" ;*/
EXEC SQL DATABASE test;
if (SQLCODE != 0)
{
printf("Failed to open database.\n") ;
return ;
}
printf("1id = %s, pwd = %s,name=%s\n", myid, mypwd, myname) ;
get_str_out(myid,mypwd,&mytype,myname) ;
printf("1ID = %s, PWD = %s, TYPE = %d, NAME = %s\n", myid, mypwd, mytype, myname) ;
EXEC SQL CLOSE DATABASE ;
if (SQLCODE != 0)
{
printf("Failed to close database.\n") ;
return ;
}
return ;
} 你在程序中的宿主变量都是指针,如果从数据库中取出的值长度大于指针指向的内存长度导致溢出。 本帖最后由 dreamtang 于 2010-08-05 09:47 编辑
回复 3# sqlnet
1.我对你程序的思考:我刚对比了一下修改前后两个源程序,我现在的认知是:你修改后,是将“get_str_out”里传入的字符串指针里的内容拷贝到“函数体里申明的变量char getid”中进行操作。这样从安全的角度上避免了对指针的操作。
2.我的想法是:我在main函数中,将主程序的“指针传入”--“get_str_out”函数中,因为函数里的指针“char *getid”指向的是“char id”,而“ID_LEN + 1” 确保了从数据库获取的字符串长度不会造成id的溢出。这时候我直接操作“char *getid”,通过指针修改原先“char id”里的内容。
SORRY:刚才看了自己的main函数,发现定义的时候定义成“char id”了。这样确实溢出了。不过在我最开始的源码里,我是定义成char id这样的类型。而ID_LEN是数据库表中“id”字段的最大字符串长度。
3.我想你的想法是对的,尽量避免了指针。不过我还是有疑惑,就是你有理解到我程序里希望通过对指针操作,直接修改“原调用函数里的字符串里内容”的意愿了? 本帖最后由 dreamtang 于 2010-08-05 09:47 编辑
回复 4# happer_xc
我定义结构体的时候是蛮小心的,结构体里的每个“数据字符串--如char id”与数据库表中“id”字段相对应,而ID_LEN就是创建数据库时,类型为“char”的字段“id”的最大长度了。
所以我觉得指针所指的可操作空间,应该是大于数据库取出数据的最大长度的。
SORRY:刚才看了自己的main函数,发现定义的时候定义成“char id”了。这样确实溢出了。不过在我最开始的源码里,我是定义成char id这样的类型。而ID_LEN是数据库表中“id”字段的最大字符串长度。
页:
[1]