1. 程式人生 > >Proc *C/C++入門之動態SQL

Proc *C/C++入門之動態SQL

基本概念

在有些情況下, 在編碼時 SQL 語句還不能完整地寫出來, 而是在程式執行時才能
構造出來,這種在程式執行臨時生成的 SQL 語句叫動態 SQL 語句. 利用動態 SQL 來
編寫 Pro*C 程式的方法叫動態 SQL 技術!

  • 目的:加強應用程式的功能和靈活
  • 靜態SQL —- 在編寫應用程式時,使用EXEC SQL關鍵字直接嵌入的SQL語句;在proc編譯應用程式生成c語言的時,都已經確定
  • 動態SQL —- 在執行應用程式時,由使用者動態輸入的SQL語句。

在下列情況之一不知道時, 使用動態 SQL 技術:

  1. SQL 語句的文字.
  2. 宿主變數的個數。
  3. 宿主變數的資料型別
  4. 引用的資料庫物件, 如列, 索引, 序列, 表, 使用者名稱和檢視.

Oracle 中動態 SQL 可用以下兩種方法實現:一個是 Oracle 自己的方法, 一個是 ANSI 的方法. 一般建議使用 Oracle 的方法,
但對於較複雜的應用, 可以使用 ANSI 的方法, 因為這樣可以使自己的程式簡化。

動態SQL1

  • 語法:
    EXEC SQL EXECUTE IMMEDIATE :host_string

host_string 字串

  • 限制
    • 不能執行select語言,僅適用於非select語句
    • 在sqlplus上執行的命令,都可以拿過來來執行
    • 語句中不包含輸入宿主變數–一個宿主指標變數指向一塊記憶體空間(存有使用者輸入的SQL語句)
    • 常用於僅執行一次的動態語句
    • 對重複執行多次的動態SQL語句,降低執行效率

nt main01()
{
    int     ret = 0;    
    int     i = 0;
    char    choosechar;

    memset(mySql, 0, sizeof(mySql));
    pSql = NULL;

    EXEC SQL WHENEVER SQLERROR DO sqlerr02();
    connet();
    pSql = mySql;
    //迴圈處理sql語言
    for(;;)
    {
        printf
("\nplease enter sql(not select ): "); gets(mySql); //scanf("%s", mySql); --空格截斷 printf("mysql:%s\n", mySql); printf("任意鍵繼續....\n"); getchar(); EXEC SQL EXECUTE IMMEDIATE :pSql; EXEC SQL COMMIT; printf("繼續執行嗎?\n"); scanf("%c", &choosechar); fflush(stdin); if (choosechar=='n' || choosechar=='N') { break; } } EXEC SQL COMMIT WORK RELEASE; printf("return ok...\n"); return ret ; }

動態SQL2

  • 使用PREPARE命令準備SQL語句

EXEC SQL PREPARE statement_name FROM :host_string;

statement_name: 識別符號,
host_string:含SQL語句的字串

  • 使用EXECUTE命令執行SQL語句
    EXEC SQL EXECUTE statement_name [USING :host_variable]

  • 如果SQL語句要通過宿主變數賦值,輸入SQL語句時要用佔位符

  • 僅適用於非select語句
  • 可包含虛擬輸入宿主變數和指示器變數,其個數和型別在預編譯時已知
int main02()
{
    int     ret = 0;    
    int     i = 0;
    char    choosechar;

    memset(mySql, 0, sizeof(mySql));
    pSql = NULL;

    EXEC SQL WHENEVER SQLERROR DO sqlerr02();
    connet();

    pSql = mySql;
    //迴圈處理sql語言
    for(;;)
    {
        printf("\n請輸入要更新部門編號 ");
        scanf("%d", &deptno);

        printf("\n請輸入要新loc值 ");
        scanf("%s", loc);

        //準備動態sql
        EXEC SQL PREPARE my_pre_sql FROM 'update dept set loc = :a where deptno = :b';
        //執行動態sql
        EXEC SQL EXECUTE my_pre_sql USING :loc, :deptno;

        EXEC SQL COMMIT;

        printf("\n 按任意鍵繼續? ");
        getchar();
        printf("\n退出鍵入n, 其他繼續? ");
        scanf("%c", &choosechar);
        fflush(stdin);

        if (choosechar=='n' || choosechar=='N')
        {
            break;
        }
    }

    EXEC SQL COMMIT WORK RELEASE;
    printf("return ok...\n");

    return ret ;
}

動態SQL3

  • 使用PREPARE命令準備SQL語句

EXEC SQL PREPARE statement_name FROM :host_string;

statement_name: 識別符號,
host_string:含SQL語句的字串

  • 使用DECLARE命令定義遊標,可以結合遊標一塊使用
 EXEC SQL DECLARE cursor_name CURSOR FOR statement_name; 
 EXEC SQL OPEN cursor_name [using host_variable_list]
 EXEC SQL FETCH cursor_name INTO host_variable_list
 EXEC SQL CLOSE cursor_name 
  • 查詢部門號大於10的所有部門資訊
  • 動態sql3 處理選擇列表項(select查詢出來的結果列數固定) 和 輸入宿主變數個數一定
  • 本質:
    • 輸入宿主變數個數固定 查詢條件固定
    • 輸出宿主變數個數固定 返回結果固定

//可以結合遊標一塊使用

int main()
{
    int     ret = 0;    
    int     i = 0;
    char    choosechar;

    memset(mySql, 0, sizeof(mySql));
    pSql = NULL;

    EXEC SQL WHENEVER SQLERROR DO sqlerr02();
    connet();
    //EXEC SQL WHENEVER NOT FOUND DO nodata();

    //迴圈處理sql語言
    for(;;)
    {
        printf("\n請輸入部門編號 ");
        scanf("%d", &deptno);

        //準備動態sql
        EXEC SQL PREPARE my_pre_sql3 FROM 'select deptno, dname, loc from dept where deptno > :a';

        //定義遊標
        EXEC SQL DECLARE c1 CURSOR FOR my_pre_sql3;

        //開啟遊標
        EXEC SQL OPEN c1 USING :deptno;

        //提取資料
        EXEC SQL WHENEVER NOT FOUND DO break;

        for (;;)
        {
            EXEC SQL FETCH c1 INTO :deptno, :dname,:loc:loc_ind;
            printf("%d\t %s\t %s \n", deptno, dname, loc); 

        }
        EXEC SQL CLOSE c1;


        EXEC SQL COMMIT;

        printf("\n 按任意鍵繼續? ");
        getchar();
        printf("\n鍵入 n 退出, 其他繼續? ");
        scanf("%c", &choosechar);
        fflush(stdin);

        if (choosechar=='n' || choosechar=='N')
        {
            break;
        }
    }

    EXEC SQL COMMIT WORK RELEASE;
    printf("return ok...\n");

    return ret ;
}   

動態SQL4

  • 既適用於SELECT語句,也適用於非SELECT語句、
  • 工程中主要使用該模式
  • 與前面的方法相比有兩個突出的不同點:

    • 不但包含選擇表項或虛擬輸入宿主變數,而且它們的個數或資料型別在編譯時還不知道
    • 在其它方法中,ORACLE和C之間的資料型別轉換是自動實現的。而在方法4中,由於動態語句中的宿主變數個數和型別在編譯時還不知道,因此不能實現自動轉換,必須由程式來控制資料型別之間的轉換
  • 主要資訊:

    • 選擇表項和實輸入宿主變數的個數
    • 每一個選擇表項和實輸入宿主變數的成年高度
    • 每一個選擇表項和實輸入宿主變數的資料型別
    • 每一個輸出宿主變數和實輸入宿主變數的記憶體單元地址

ANSI模式


/* 包含C標頭檔案 */  
#include <stdio.h>  
#include <string.h>  

/* 包含SQLCA標頭檔案 */  
#include "sqlca.h"  

/* 定義繫結變數值和選擇列表項值的最大長度 */  
#define MAX_VAR_LEN     30 

/* 定義選擇列表項名的最大長度 */  
#define MAX_NAME_LEN    31  


/* 定義宿主變數 */  
exec sql begin declare section; 
    char    *usrname = "scott";
    char    *passwd = "tiger";
    char    *serverid = "orcl"; 
    char sql_stat[100];  
    char current_date[20];  
exec sql end declare section;  

void sql_error();  
void connet();
void process_input();  
void process_output();  

int main()  
{  
    /* 安裝錯誤處理控制代碼 */  
    exec sql whenever sqlerror do sql_error();  

    /* 連線到資料庫 */  
    connet();  

    /* 分配輸入描述區和輸出描述區 */  
    exec sql allocate descriptor 'input_descriptor';  
    exec sql allocate descriptor 'output_descriptor';  

    for( ; ; )  
    {  
        printf("\n請輸入動態SQL語句(EXIT:退出):\n");  
        gets(sql_stat);  

        /* EXIT(exit)->退出 */  
        if(0 == strncmp(sql_stat , "EXIT" , 4) || 0 == strncmp(sql_stat , "exit" , 4))  
            break;  

        /* 準備動態SQL語句 */  
        exec sql prepare s from :sql_stat;  

        /* 定義遊標 */  
        exec sql declare c cursor for s;  

        /* 處理繫結變數 */  
        process_input();  

        /* 開啟遊標 
         * select語句:處理查詢結果 
         * 其他SQL語句:執行 
        */  
        exec sql open c using descriptor 'input_descriptor';  
        if(0 == strncmp(sql_stat , "SELECT" , 6) , 0 == strncmp(sql_stat , "select" , 6))  
        {  
            process_output();
        }  
        /* 關閉遊標 */  
        exec sql close c;  
    }  

    /* 釋放輸入描述區和輸出描述區 */  
    exec sql deallocate descriptor 'input_descriptor';  
    exec sql deallocate descriptor 'output_descriptor';  

    /* 提交事務,斷開連線 */  
    exec sql commit work release;  
    puts("謝謝使用ANSI動態SQL!\n");  

    return 0;  
}  

void sql_error()  
{  
    /* 顯示SQL錯誤 */  
    printf("%.*s\n" , sqlca.sqlerrm.sqlerrml , sqlca.sqlerrm.sqlerrmc);  
    exit(0);
}  

void process_input()  
{  
    int i;  

    /* 定義宿主變數 */  
    exec sql begin declare section;  
        int input_count;  
        int input_type ;  
        int input_len;  
        char input_buffer[MAX_VAR_LEN];  
        char name[MAX_NAME_LEN];  
        int occurs;  
    exec sql end declare section;  

    /* 繫結變數->輸入描述區 */  
    exec sql describe input s using descriptor 'input_descriptor';  

    /* 取得繫結變數個數 */  
    exec sql get descriptor 'input_descriptor' :input_count = count;  

    /* 迴圈處理繫結變數名 */  
    for(i = 0 ; i != input_count ; ++i)  
    {  
        occurs = i + 1;  

        /* 取得繫結變數名 */  
        exec sql get descriptor 'input_descriptor' value :occurs :name = name;  
        printf("請輸入%s的值:" , name);  
        gets(input_buffer);  

        /* 以NULL結尾 */  
        input_len = strlen(input_buffer);  
        input_buffer[input_len] = '\0';  

        /* 設定繫結變數型別、長度和值 */  
        input_type = 1;  
        exec sql set descriptor 'input_descriptor' value :occurs   
            type = :input_type , length = :input_len , data = :input_buffer;  
    }  
}  

void process_output()  
{  
    int i;  

    // 定義宿主變數  
    EXEC SQL BEGIN DECLARE SECTION ;  

        int output_count;  
        int output_type;  
        int output_len;  
        char output_buffer[MAX_VAR_LEN];
        short  output_indicator;  
        char name[MAX_NAME_LEN];  
        int occurs;  
    EXEC SQL END DECLARE SECTION ;  


    // 選擇列表項, 輸出描述區 
    exec sql describe output s using descriptor 'output_descriptor';  

    //取得選擇列表項個數  
    exec sql get descriptor 'output_descriptor' :output_count = count;  


    //迴圈處理選擇列表項 

    output_type = 12;  //note //設定型別為變長字串
    //output_type = 1;  //note
    for(i = 0 ; i != output_count ; ++i)  
    {  
        occurs = i + 1;  

        output_len = MAX_VAR_LEN;  

      //printf("22222222222222:%d \n", i);
        // 設定選擇列表項的型別和長度 
        exec sql set descriptor 'output_descriptor' value :occurs   
            type = :output_type , length = :output_len;  

        //取得選擇列表項的名稱並輸出 
        exec sql get descriptor 'output_descriptor' value :occurs :name = name;  

        //顯示選擇列表項名稱
        printf("\t%s" , name);  
    }  
    printf("\n");  

    // 提取資料完畢->退出迴圈  
    exec sql whenever not found do break;  

    // 迴圈處理選擇列表項資料  
    for( ; ; )  
    {  
        // 行資料->輸出描述區  
        exec sql fetch c into descriptor 'output_descriptor';  

        // 迴圈處理每列資料  
        for(i = 0 ; i < output_count ; ++i)  
        {  
            occurs = i +1;  

            // 取得列資料和指示變數值  
            exec sql get descriptor 'output_descriptor' VALUE :occurs  
                :output_buffer = DATA , :output_indicator = INDICATOR;  

            //輸出列資料   
            if(-1 == output_indicator)  
               printf("\t%s", "   ");         
            else  
               printf("\t%s" , output_buffer);        
        }  

        printf("\n"); 
    }  

}


void connet()
{
    int ret = 0;
    //連線資料庫
    EXEC SQL CONNECT:usrname IDENTIFIED BY:passwd USING:serverid ;
    if (sqlca.sqlcode != 0)
    {
        ret = sqlca.sqlcode;
        printf("sqlca.sqlcode: err:%d \n", sqlca.sqlcode);
        return ;
    }
    else
    {
        printf("connect ok...\n");
    }
}

ORACLE模式

  • 關於SQLDA
    為了儲存執行動態SQL語句所需要的資訊,系統提供一個稱之為SQL描述區的程式資料結構。把ORACLE所需要的全部有關選擇表項或虛擬輸入宿主變數的資訊,除了值和名字外,都儲存在SQLDA中

  • SQLDA中所包含的資訊主要通過以下三種方法寫入:

    • sqlald()函式:在分配描述區和緩衝區的同時,還把SLI或P的名字在緩衝區中的地址和長度寫入SQLDA中
    • 應用程式:通過程式把SLI或BV值的緩衝區地址、長度既資料型別寫入SQLDA
    • DESCRIBE語句:檢查每一個選擇表項,確定它的名字、資料型別、約束、長度、定標和精度,然後把這方面的資訊儲存在選擇SQLDA和輸出緩衝區中,以供使用者使用

  • 說明的方式有如下三種:

    • 直接把商標中所示的程式碼編寫到程式中
    • 用INCLUDE語句:EXEC SQL INCLUDE sqlda;
    • 使用指標:EXEC SQL INCLUDE sqlda; sqlda *bind_dp;sqlda *select_dp;bind_dp=sqlald(…);select_dp=sqlald(…);
  • sqlald(max_vars,max_name,max_ind_name)為SQLDA分配控制元件,並分配相應的緩衝區,並把緩衝區的地址等填入SQLDA中


/* 包含C標頭檔案 */  
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <setjmp.h>  
#include <sqlcpr.h>  

/* 包含SQLDA和SQLCA結構 */  
#include <sqlda.h>  
#include <sqlca.h>  

/* 定義繫結變數和選擇列表項的最大個數 */  
#define MAX_ITEMS       40  

/* 定義繫結變數和選擇列表項名稱的最大長度 */  
#define MAX_VNAME_LEN   30  

/* 定義指示變數名稱的最大長度 */  
#define MAX_INAME_LEN   30  

void connect();  
void sql_error();  
void alloc_descriptors(int , int , int);  
void dealloc_descriptors();  
void set_bind_variables();  
void process_select_list();  

/* 定義繫結描述區和選擇描述區 */  
SQLDA* bind_dp;  
SQLDA* select_dp;  

/* 定義輸入宿主變數:存放動態SQL語句 */  
char sql_stat[100];   
char current_date[20];     

int main()  
{  
    /* 安裝錯誤處理控制代碼 */  
    exec sql whenever sqlerror do sql_error();  

    /* 連線到資料庫 */  
    connect2();  

    /* 分配繫結描述區和選擇描述區 */  
    alloc_descriptors(MAX_ITEMS , MAX_VNAME_LEN , MAX_INAME_LEN);  

    for( ; ; )  
    {  
        printf("請輸入動態SQL語句(exit:退出):");  
        gets(sql_stat);  

        /* EXIT(exit):退出 */  
        if(0 == strncmp(sql_stat , "exit" , 4) || 0 == strncmp(sql_stat , "EXIT" , 4))  
            break;  

        /* 準備動態SQL語句 */  
        exec sql prepare s from :sql_stat;  

        /* 定義遊標 */  
        exec sql declare c cursor for s;  

        /* 出錯,繼續下一迴圈 */  
        if(0 != sqlca.sqlcode)  
            continue;  

        /* 設定繫結變數 */  
        set_bind_variables();  

        /* 
         * 開啟遊標 
         * select語句:生成結果集 
         * 其他SQL語句:執行語句 
         */  
        exec sql open c using descriptor bind_dp;  

        /* 
         * select語句 
         */  
        if(0 == strncmp(sql_stat , "select" , 6) || 0 == strncmp(sql_stat , "SELECT" , 6)) 
        {  
            process_select_list();   
        }  
        /* 關閉遊標 */  
        exec sql close c;  
    }  

    /* 釋放選擇描述區和選擇描述區 */  
    dealloc_descriptors();  

    /* 提交事務,斷開連線 */  
    exec sql commit work release;  
    puts("謝謝使用Oracle動態SQL方法四!\n");  

    return 0;  
}  


void connect2()  
{  
    /* 定義宿主變數 */  
    char username[20] , password[20] , server[20];  

    /* 輸入使用者名稱、口令和網路服務名 */  
    printf("輸入使用者名稱:");  
    gets(username);  

    printf("輸入口令:");  
    gets(password);  

    printf("輸入網路服務名:");  
    gets(server);  

    /* 連線到資料庫 */  
    EXEC SQL CONNECT :username identified by :password using :server;  
}  

void sql_error()  
{  
    /* 顯示SQL錯誤資訊 */  
    printf("%.*s\n" , sqlca.sqlerrm.sqlerrml , sqlca.sqlerrm.sqlerrmc);  
}  

void alloc_descriptors(int size , int max_vname_len , int max_iname_len)  
{  

    int i;  

    /* 分配繫結描述區和選擇描述區 */  
    bind_dp = SQLSQLDAAlloc(0 , size , MAX_VNAME_LEN , MAX_INAME_LEN);  
    select_dp = SQLSQLDAAlloc(0 , size , MAX_VNAME_LEN , MAX_INAME_LEN);  


    /* 為指示變數、繫結變數和選擇列表項分配記憶體 */  
    for(i = 0 ; i != MAX_ITEMS ; ++i)  
    {  
        bind_dp->I[i] = (short*)malloc(sizeof(short));  
        select_dp->I[i] = (short*)malloc(sizeof(short));  

        bind_dp->V[i] = (char*)malloc(1);  
        select_dp->V[i] = (char*)malloc(1);  
    }  
}  

void dealloc_descriptors()  
{  
    int i;  

    /* 釋放指示變數、繫結變數和選擇列表項佔用的記憶體 */  
    for(i = 0 ; i != MAX_ITEMS ; ++i)  
    {  
        if(bind_dp->V[i] != (char*)0)  
            free(bind_dp->V[i]);  
        free(bind_dp->I[i]);  

        if(select_dp->V[i] != (char*)0)  
            free(select_dp->V[i]);  
        free(select_dp->I[i]);  
    }  

    /* 釋放繫結描述區和選擇描述區 */  
    SQLSQLDAFree(0 , bind_dp);  
    SQLSQLDAFree(0 , select_dp);  
}  

void set_bind_variables()  
{  
    int i;  
    char bind_var[64];  

    /* 設定繫結變數最大個數 */  
    bind_dp->N = MAX_ITEMS;  

    /* 繫結變數名稱: 繫結描述區 */  
    exec sql describe bind variables for s into bind_dp;  

    /* 設定繫結變數實際個數 */  
    bind_dp->N = bind_dp->F;  

    /* 迴圈處理繫結變數 */  
    for(i = 0 ; i != bind_dp->F ; ++i)  
    {  
        /* 顯示繫結變數名 */  
        printf("請輸入繫結變數%.*s的值:" , (int)bind_dp->C[i] , bind_dp->S[i]);  

        /* 輸入繫結變數的值 */  
        gets(bind_var);  

        /* 設定繫結變數的長度成員 */  
        bind_dp->L[i] = strlen(bind_var);  

        /* 為繫結變數資料緩衝區重新分配記憶體(多一位,留給'\0') */  
        bind_dp->V[i] = (char*)realloc(bind_dp->V[i] , bind_dp->L[i] + 1);  

        /* 繫結變數資料: 資料緩衝區 */  
        strcpy(bind_dp->V[i] , bind_var);  

        /* 設定指示變數,處理NULL */  
        if(0 == strncmp(bind_var , "NULL" , 4) || 0 == strncmp(bind_var , "null" , 4))  
            *bind_dp->I[i] = -1;  
        else  
            *bind_dp->I[i] = 0;  

        /* 設定資料緩衝區資料型別程式碼->char */  
        bind_dp->T[i] = 1;  
    }  
}  

void process_select_list()  
{  
    int i , null_ok , precision , scale;  
    char title[MAX_VNAME_LEN];  

    /* 設定選擇列表項的最大個數 */  
    select_dp->N = MAX_ITEMS;  

    /* 選擇列表項: 選擇描述區 */  
    exec sql describe select list for s into select_dp;  

    /* 設定選擇列表項的實際個數 */  
    select_dp->N = select_dp->F;  

    /* 迴圈處理選擇列表項 */  
    for(i = 0 ; i != select_dp->F ; ++i)  
    {  
        /* 清除select_dp->T[i]的高位->null */  
        SQLColumnNullCheck(0 , (unsigned short*)&select_dp->T[i]  
            , (unsigned short*)&select_dp->T[i] , &null_ok);  

        /* 根據內部資料型別確定外部型別資料長度(顯示長度) */  
        switch(select_dp->T[i])  
        {  
        case 2:  
            /* number型別,取得精度與標度 */  
            //SQLNumberPrecV6(0 , (unsigned short*)&select_dp->T[i] , &precision , &scale); 
            SQLNumberPrecV6(0 , (unsigned long *)&select_dp->L[i] , &precision , &scale);  //wangbaoming modify 201409

            if(scale > 0)  
                /* 實數: 顯示長度:float  */  
                select_dp->L[i] = sizeof(float);  
            else  
                /* 整數: 顯示長度 int */  
                select_dp->L[i] = sizeof(int);  
            break;  
        case 12:  
            /* DATA資料型別(DD-MON-YY) */  
            select_dp->L[i] = 9;  
            break;  
        }  

        /* 根據變數長度,重新為選擇列表項資料緩衝區分配記憶體 */  
        if(2 != select_dp->T[i])  
            /* 其他型別 */  
            select_dp->V[i] = (char*)realloc(select_dp->V[i] , select_dp->L[i] + 1);  
        else  
            /* number型別 */  
            select_dp->V[i] = (char*)realloc(select_dp->V[i] , select_dp->L[i]);  

        /* 初始化title */  
        memset(title , ' ' , MAX_VNAME_LEN);  

        /* 選擇列表項名稱: title */  
        strncpy(title , select_dp->S[i] , select_dp->C[i]);  

        /* 顯示列名 */  
        if(2 == select_dp->T[i])  
            if(scale > 0)  
                printf("\t%.*s" , select_dp->L[i] + 3, title);  
            else  
                printf("\t%.*s" , select_dp->L[i] , title);  
        else  
            printf("\t%-.*s" , select_dp->L[i] , title);  

        /* 根據Oracle內部型別確定外部資料型別(顯示型別) */  
        if( 2 == select_dp->T[i])  
        {  
            /* number 型別*/  
            if(scale > 0)  
                /* float */  
                select_dp->T[i] = 4;  
            else  
                /* int */  
                select_dp->T[i] = 3;  
        }  
        else  
            /* char */  
            select_dp->T[i] = 1;  
    }  

    printf("\n");  

    /* 提取資料完畢->結束迴圈 */  
    exec sql whenever not found do break;  

    /* 迴圈處理選擇列表資料 */  
    for( ; ; )  
    {  
        /* 資料->選擇描述區 */  
        exec sql fetch c using descriptor select_dp;  

        /* 顯示資料 */  
        for( i = 0 ; i != select_dp->F ; ++i)  
        {  
            if(*select_dp->I[i] < 0){  
                /* 處理NULL */  
                printf("\tNULL");  
            }else{  
                if(3 == select_dp->T[i]){  
                    /* int */  
                    printf("\t%d" , *(int*)select_dp->V[i]);  
                }else if(4 == select_dp->T[i]){  
                    /* float */  
                    printf("\t%8.2f" , *(float*)select_dp->V[i]);  
                }else{  
                    /* char */  
                    printf("\t%.*s" , select_dp->L[i] , select_dp->V[i]);  
                }  
                }  
        }  
        printf("\n");  
    }  
}