如题:如何用pro*C实现unix操作系统下的Oracle数据库表的导出环境,Hp_Unix
Oracle9i  +  Pro*C 编译环境
gcc编译环境需要实现的功能是
以参数形式输入数据库名,用户名,密码,数据库中的表名,要保存的文件的路径及文件名。
将此表中的所有数据导出到指定的文本文件中。导出的文件的格式要求是:
每一个记录做成一行。末尾为换行符。
char 和vchar型的数据按照左对齐,右侧没有达到数据库字段规定之长度的,用空格补齐
number型的数据右对齐,左侧没有达到数据库字段规定之长度的,用空格补齐例子如下:数据类型 位数 数据                     文本文件中存储的数据    
number         4        10       ————〉            △△10
char          9         abcde                          abcde△△△△  望各位给出完整的代码,如果可以给出注释就更好了:
谢谢各位高手了。分不够可以再加!我这里找到一个C++builder的例子,可是不会自己修改过来,
代码如下

解决方案 »

  1.   

    //-------------------------------------------------------------------------
    //加入必要的头文件
    #include<vcl.h> #include<windows.h> #include<stdio.h> #include<stdlib.h> #include<string.h>
    #include<time.h> #include<math.h> #include<fcntl.h> #include<io.h> #include<sys\stat.h>
    //说明DLL的输出函数
    extern "C" _declspec(dllexport) int _stdcall ConnectDB(const char *Username,
                                    const char *Password, const char *Dbname);
    extern "C" _declspec(dllexport) int _stdcall ImportTxtfile(TList *LengthArray,
                                    String *FieldArray, const char *TableName,
                                    const char *FileName);
    extern "C" _declspec(dllexport) int _stdcall ExportTxtfile(const char *Sql,
                                    const char *FileName); 
    #pragma hdrstop
    //----------------------------------------------------------------------------
    #define MAX_ITEMS 20        //定义最大字段数
    #define MAX_VNAME_LEN 30  //定义选择表项最大长度
    #define MAX_INAME_LEN 30  //定义指示器变量名字的最大长度
     
    EXEC SQL INCLUDE sqlca;    //说明SQL通讯区
    EXEC SQL INCLUDE oraca;    //说明ORACLE通讯区
    EXEC SQL INCLUDE sqlda;    //说明SQL语句描述结构/*SQLDA结构体请查相关资料*///如果在PROC中用到ORACA,还要在程序头加上 EXEC ORACLE OPTION (ORACA = YES);
    EXEC ORACLE OPTION (ORACA = YES);
    ///*RELEASE_CURSOR=YES 使PROC 在执行完后释放与嵌入SQL有关资源*/
    EXEC ORACLE OPTION (RELEASE_CURSOR = YES);
     
    //说明ORACLE外部函数
    extern "C" _declspec(dllimport) void _stdcall sqlclu(SQLDA*);  ////释放空间使用函数free()释放由函数malloc()所分配的内存,使用函数sqlclu()释放为查询描述区以及绑定描述区所分配的空间
    extern "C" _declspec(dllimport) void _stdcall sqlnul(short*, short*, int*);//将NUMBER的值重置为FLOAT或INT。T[i]的高位存储着第i个查询列表项的NULL\NOTNULL状态信息。在执行OPEN或FETCH命令前必须清除该位,这可以通过调用函数sqlnul()来完成。
    extern "C" _declspec(dllimport) void _stdcall sqlprc(int*, int*, int*);//对于查询描述区来说,DESCRIBESELECT LIST命令会将长度数组设置为每个查询列表项的最大长度。各种数据类型的长度是各不相同的。对于CHAR或VARCHAR2类型的查询列表项来说, DESCRIBE SELECT LIST将L[i]设置为查询列表项的最大长度;而对于NUMBER类型的查询列表项来说,分别被保存到了,通过调用函数sqlpre()可以从L[i] 中读取到精度和标度值。函数sqlpre()的语法如下:sqlpre(long*length,int*precision,int*scale);该函数的原型在sqlcpr.h文件中。参数说明如下:·length:指向存储NUMBER值长度的长整数变量的指针。对于变量L来说,长度被存储到L[i]中,而精度和标度分别存储在该变量的低字节和高字节中。·precision:指向整数变量的指针,NUMBER值的精度返回到该变量中。·scale: 指向整数变量的指针,NUMBER值的标度返回到该变量中。该函数只能用于非线程应用。而如果要在线程应用中完成同样功能,则需要使用函数sqlprct()。另外,也可以使用SQLLIB的新函数SQLNumberProV6(),该函数既可用于线程应用又可用于非线程应用。
    extern "C" _declspec(dllimport) struct SQLDA * _stdcall sqlald(int, unsigned int, unsigned int);//在定SQLDA结构后,为了使用查询描述区和绑定描述区,我们还必须使用函数sqlald()为它们分配内存。当分配描述区时,函数sqlald()会将V[0]到V[N-1]设置为0。该函数语法如下:
     
    SQLDA *SelectUnit;  //定义选择项描述
    SQLDA *BindUnit;  //定义输入项空间
    //定义变量,以存放连接数据库的参数
    EXEC SQL BEGIN DECLARE SECTION;
        char User[20];//用户名
        char Pwd[20];//密码
        char DB[20];//数据库服务名
    EXEC SQL END DECLARE SECTION;
     
    bool bConnect = false;//是否连接标志
    #pragma hdrstop
     
    #pragma argsused
    //C++ Builder DLL的主函数
    BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fwdreason, LPVOID lpvReserved)
    {
            return 1;
    }
     
    /*---------------------------------------------------------------------------
        连接数据库
    ---------------------------------------------------------------------------*/
    int _stdcall ConnectDB(const char *Username, const char *Password,
                                       const char *Dbname)
    {
      strcpy(User, Username);
      strcpy(Pwd, Password);
      strcpy(DB, Dbname);
     
      EXEC SQL CONNECT :User IDENTIFIED BY :Pwd USING :DB;
     
      if (sqlca.sqlcode < 0)
        return -1;
     
      bConnect = true;
      return 0;
    }
      

  2.   

    /*---------------------------------------------------------------------------
    导出文本函数
    因为不确定SELECT语句的表及字段,所以我使用动态语句(ORACLE DYNAMIC SQL)的
    //第四种方式。动态SQL方法四是在不确定SQL语句的选择项与输入项,
    且不知个数与数据类型的情况下使用的一种复杂程序设计技术。
    ---------------------------------------------------------------------------*/
    int _stdcall ExportTxtfile(const char *Sql/*SQL选择语句*/, const char FileName/*导出目标文本文件名*/)
    {
      int null_ok, precision, scale;
     
      int handle;
     
      if ((handle = open(FileName, O_CREAT|O_TEXT|O_APPEND|O_RDWR, S_IREAD|S_IWRITE)) == -1)
      {
        //文件打开出错
        return -1;
      }
    //定义变量,以存放SQL语句
      EXEC SQL BEGIN DECLARE SECTION;
        char sqlstr[256];
      EXEC SQL END DECLARE SECTION;
     
      //检查是否连接数据库
      if (bConnect == false) return -2;
     
      strcpy(sqlstr/*.arr*/, Sql);
      //  sqlstr.len = strlen(sql);
     
      //给描述区分配空间  
      if ((SelectUnit = sqlald(MAX_ITEMS, MAX_VNAME_LEN, MAX_INAME_LEN)) == (SQLDA *)NULL)
      {
        //空间分配失败
        return -3;
      }
     
      if ((BindUnit = sqlald(MAX_ITEMS, MAX_VNAME_LEN, MAX_INAME_LEN)) == (SQLDA *)NULL)
      {
        //空间分配失败
        return -3;
      }
      //给查询返回值存储区分配空间
      SelectUnit->N = MAX_ITEMS;
      for (int i=0; i < MAX_ITEMS; i++)
      {
        BindUnit->I[i] = (short *)malloc(sizeof(short *));
        BindUnit->V[i] = (char *)malloc(MAX_VNAME_LEN);
      }
      for (int i=0; i < MAX_ITEMS; i++)
      {
        SelectUnit->I[i] = (short *)malloc(sizeof(short *));
        SelectUnit->V[i] = (char *)malloc(MAX_VNAME_LEN);
      }
     
      EXEC SQL WHENEVER SQLERROR GOTO sqlerr;//DO sql_error("导出出错");
    //设置SQL语句
      EXEC SQL PREPARE SQLSA FROM :sqlstr;
      EXEC SQL DECLARE Cursorbase CURSOR FOR SQLSA;
     
      //输入描述处理
      BindUnit->N = MAX_ITEMS;
      EXEC SQL DESCRIBE BIND VARIABLES for SQLSA INTO BindUnit;
     
      if (BindUnit->F < 0)
      {
        return -4;
        //输入项过多
      }
      BindUnit->N = BindUnit->F;
      //打开光标
      EXEC SQL OPEN Cursorbase USING DESCRIPTOR BindUnit;
     
      //选择项处理
      EXEC SQL DESCRIBE SELECT LIST for SQLSA INTO SelectUnit;
     
      if (SelectUnit->F < 0)
      {
        return -4;
        //选择表项过多
      }
      SelectUnit->N = SelectUnit->F;
    //因为所有格式,类型都是不确定的,所以要得到正确的返回值就要处理格式
      for (int i=0; i < SelectUnit->F; i++)
      {
        sqlnul(&(SelectUnit->T[i]), &(SelectUnit->T[i]), &null_ok);
        switch (SelectUnit->T[i])
        {
         case 1://CHAR
              break;
         case 2://NUMBER
              sqlprc(&(SelectUnit->L[i]), &precision, &scale);
              if (precision == 0)
                precision = 40;
              SelectUnit->L[i] = precision + 2;
              break;
            case 8://LONG
                 SelectUnit->L[i] = 240;
                 break;
            case 11://ROWID
                 SelectUnit->L[i] = 18;
                 break;
            case 12://DATE
                 SelectUnit->L[i] = 9;
                 break;
            case 23://RAW
                 break;
            case 24://LONGRAW
                 SelectUnit->L[i] = 240;
                 break;
         }
     
         SelectUnit->V[i] = (char *)realloc(SelectUnit->V[i], SelectUnit->L[i]+1);
     
         SelectUnit->T[i] = 1;//把所有类型转换为字符型
      }
     
      EXEC SQL WHENEVER NOT FOUND goto EndFor;
     
      for (;;)
      {
        EXEC SQL FETCH Cursorbase USING DESCRIPTOR SelectUnit;
     
        //输出各字段
        for (int i=0; i < SelectUnit->F; i++)
        {
          char buffer[256];
     
          if (i != SelectUnit->F-1)
            sprintf(buffer, "%s", SelectUnit->V[i]);
          else sprintf(buffer, "%s\r\n", SelectUnit->V[i]);
     
          int length = strlen(buffer);
     
          if (write(handle, buffer, length) != length)
          {
            return -5;
            //写文件失败 exit(1);
          }
        }
     
      }
     
    EndFor:
     
      close(handle);
     
      for (int i=0; i < MAX_ITEMS; i++)
      {
        if (SelectUnit->V[i] != (char *)NULL)
          free(SelectUnit->V[i]);
     
        free(SelectUnit->I[i]);
      }
     
      for (int j=0; j < MAX_ITEMS; j++)
      {
        if (BindUnit->V[j] != (char *)NULL)
          free(BindUnit->V[j]);
     
        free(BindUnit->I[j]);
      }
     
      sqlclu(SelectUnit);
      sqlclu(BindUnit);
     
      EXEC SQL CLOSE Cursorbase;
     
      return 0;
     
    sqlerr:
      return -6;
    }