WEB开发网
开发学院数据库DB2 db2定长import API问题解决,与大家分享!! 阅读

db2定长import API问题解决,与大家分享!!

 2006-09-18 22:14:47 来源:WEB开发网   
核心提示:原帖子: http://www.chinaunix.net/forum/viewtopic.php?t=62859 在db2里面有import命令,是用来装载文本数据到数据库的,db2定长import API问题解决,与大家分享!!,下面是脚本: import from F:\db2c\PAS-BASS\data\ti

原帖子:
http://www.chinaunix.net/forum/viewtopic.php?t=62859

在db2里面有import命令,是用来装载文本数据到数据库的。下面是脚本:

import from F:\db2c\PAS-BASS\data\ticket\realdata\ OF ASC MODIFIED BY noeofchar  nullindchar=Y timestampformat="YYYYMMDDhhmmss"   METHOD L ( 1 1,2 21,22 36,37 40,41 54,55 55,56 75  INSERT INTO LAW.APTI_FULL_ITEM

现在我们要用db2提供的api,sqluimpr()来实现那个命令。这个函数里面有很多参数,那些参数是用来记录脚本里面的命令参数的,比如文件路径 是char类型,消息文件路径是 char 类型,import的文件类型 sqlchar数据类型等等。

现在我们只关心import api 函数里面有两个参数

struct sqldcol *DataDescriptor
struct sqlchar    *ActionString;


ActionString 是用来存储imnport方式的,就是存储上面脚本的“ INSERT INTO LAW.APTI_FULL_ITEM”

下面给出 sqlchar 结构:

#undef _SQLOLDCHAR 
#ifdef SQLOLDCHAR 
#define _SQLOLDCHAR   unsigned char 
#else 
#define _SQLOLDCHAR   char 
#endif 


SQL_STRUCTURE sqlchar        

    short         length; 
    _SQLOLDCHAR      data[1]; 
}; 

由此看来 sqlchar.short 是用来存储字符串长度的,data[1] 是用来存储字符串的,下面是赋值代码:

struct sqlchar    *ActionString; 
char        String[80]; 

strcpy(String, " INSERT INTO LAW.APTI_FULL_ITEM"); 

ActionString = (struct sqlchar *) 
    malloc (strlen(String) + sizeof(struct sqlchar)); 
ActionString->length = strlen(String); 

strncpy(ActionString->data, String, strlen(String)); 

这句话:
  strncpy(ActionString->data, String, strlen(String));  


明明data是只有一个长度的字符数组,怎么能存储一个长度大于1的字符串string那?
-------------------------------------
实际上是这样的,网上有人回答了:(http://expert.csdn.net/Expert/topic/1754/1754927.xml(标准化越来越近了)?temp=.7425043 )
0。 
 原来(好像很久以前了)c语言中常用的一种惯用法。
他用 char[1]来代替不定长的字符串。比加一个指针在使用上要方便许多。
这种方法通过分配内存时候,多分配几个字节,来解决数组不定长的问题。
好像在 《C++物件模型》 中有介绍。不然的话,就看看介绍 c 惯用法方面的书吧

1。
实际上代码没有错误。
ActionString = (struct sqlchar *) 
    malloc (strlen(String) + sizeof(struct sqlchar)); 
分配了足够的空间(串长+结构大小)

2。
之所以如此写代码,是为了其同用性,不会因为
char        String[80]; 
的大小,去改变
_SQLOLDCHAR      data[1]; 
的大小。

3。
--_SQLOLDCHAR data[1];
这种定义确实和语义不符,但也是一种常用的方法。
在很久很久以前,可以将未知长度的数组定义为:
 DATATYPE array[];
将其定义为“SQLOLDCHAR data[1]”,其实就是说明“data”是一个数组。
应用的时候,数组的实际长度是和分配的内存大小相关的。
--ActionString = (struct sqlchar *)malloc(strlen(String) + sizeof(struct sqlchar)); 
这一句,分配的内存包括了需要拷贝字符串的长度,sqlchar结构的大小(字符串的结束字符“0”也考虑了),就这一段代码来看,并没有问题。

另外,这段代码分配内存用的是“malloc”,而不是C++常用的“new”。这一点需要注意。
-------------------------------------------------------------------------


现在我遇到难题了,本来想按照上面的方法给DataDescriptor赋值的时候发现,结构体变复扎了:
DataDescripto 使用来存储import方式的,使用方法L , P或者 D这三个其中的一种。
L:使用asc文件格式的定长import。(就是文件数据每个字段都是占用定长的,不够长度用空格补起)。
P:使用DEL格式的字段对应import
我们不管P 和D,上面的import脚本就是用的定长格式,脚本里面的语句:
METHOD L ( 1 1,2 21,22 36,37 40,41 54,55 55,56 75 
就说明了,import方法是L ,并且在后面给出了每个字段的在文件的开始位置和结束位置如:第二字段的开始位置是2 结束位置是21。
所以我们要告诉api这下信息。
包含这些信息的参数是:

struct sqldcol *DataDescriptor


db2 api这本书里面是这样说赋值的:

有个变量是DataDescriptor,DataDescriptor 的dcolmeth字段就被赋值成SQL_METH_L,dcolname数组中的第一个元素的dcolnptr指针指向包含sqllocpair结构数组的sqlloctab结构。此数组中的元素的数量必须存储在sqlcol结构的dcolnum字段中。在数组的每个元素必须包含一对整型数值,用来只是在文件中列开始和结束的位置。整型数据中的第一个值是在文件中列开始的字节位置(在第一行中),第二个值是在文件中列结束的字节位置(在同一行中)。第一个字节值可被设置位1(指示在一行数据中的第一个字节),可以设置的最大的字节的位置是由外部文件的第一行数据中所包含的字节数决定。



结构体如下 
SQL_STRUCTURE sqldcoln 

short dcolnlen;  /*dcolnptr字段所指定的数据元数大小*/
char *dcolnptr;  /*一个指向内存中的某个位置的,在这块内存区域中,存放sqldcol结构的dcolmeth字段所指定的数据元数*/
}; 

SQL_STRUCTURE sqldcol 

short dcolmeth; 
short dcolnum; 
struct sqldcoln dcolname[1]; /* actual size must be dcolnum */ 
}; 

/* Structure for Pairs of Locations for ASC files */ 
SQL_STRUCTURE sqllocpair 

short begin_loc;  /*在数据文件中的列数据的开始位置*/
short end_loc;   /*在数据文件中的列数据的结束位置*/
}; 

SQL_STRUCTURE sqlloctab 

struct sqllocpair locpair[1]; /*一个指向sqllocpair结构数组的指针,该数组包含个个列的开始位置和结束位置, actual size must be                dcolnum */ 
}; 


DataDescriptor->dcolmeth
        dcolnum
        dcolname[1]->dcolnlen
   char *dcolnptr->(这里强制指向结构)sqllocpair locpair[1]->begin_loc
   end_loc
现在是如何给他们赋值那?

经过我不懈得测试,最后得出,存储列的开始位置和结束位置的数组是这个结构
sqllocpair locpair[1] 

但是他定义的时候只有一个长度,那么就需要我们按照IBM的方法给他赋值了!

[/code]
/*初始化DataDescriptor 结构很复杂注意释放内存*/
     DataDescriptor=(struct sqldcol *) malloc(sizeof(struct sqldcol));
     DataDescriptor->dcolmeth=SQL_METH_L;
     DataDescriptor->dcolnum=colnum;

if ( DataDescriptor==NULL)
       {printf("ERROR while malloc DataDescriptor");   exit(0);}

/*为存放列信息的结构体分配内存,强制转换char *指向 sqlloctab*/
     DataDescriptor->dcolname[0].dcolnptr=(struct sqlloctab *)malloc(colnum*sizeof(struct sqlloctab));
     /*k 分配内存的变量*/

k=0; /*k是存放列数*/
for (i=0;i<k;i++)
 {/*计算出每个列的开始位子和结束位置 X Y
    */
   /*分配DataDescriptor 的成员*/
      ((struct sqlloctab *)((*DataDescriptor).dcolname[0].dcolnptr))->locpair[k].begin_loc=x;
      ((struct sqlloctab *)((*DataDescriptor).dcolname[0].dcolnptr))->locpair[k].end_loc=y;
      (*DataDescriptor).dcolname[0].dcolnlen=strlen((*DataDescriptor).dcolname[0].dcolnptr);

  /*注意,这里用了强制类型转换
  因为char  (*DataDescriptor).dcolname[0].dcolnptr 但是IBM的API里面说他是指向一个内存区域,实际上就是一个结构,所以我们强制把他指向一个结构SQL_STRUCTURE sqlloctab */

/*调用API*/ 
 importl(TName,fullname,msgfile,choose,DataDescriptor);
  }

结束
[/code]

Tags:db 定长 import

编辑录入:coldstar [复制链接] [打 印]
赞助商链接