dreamtang 发表于 2010-07-31 17:04

[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:26

本帖最后由 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 ;
}

sqlnet 发表于 2010-08-02 22:50

我帮你修改下了,不过你的程序问题比较多。

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 ;
}

happer_xc 发表于 2010-08-03 10:55

你在程序中的宿主变量都是指针,如果从数据库中取出的值长度大于指针指向的内存长度导致溢出。

dreamtang 发表于 2010-08-05 09:33

本帖最后由 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:36

本帖最后由 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]
查看完整版本: [ESQL游标]用字符串指针作为where后的匹配项导致数据丢失问题