原代碼地址:https://blog.csdn.net/numbibi/article/details/8446704
根據(jù)自己的理解加上了注釋
程序代碼
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h> //提供了一個(gè)類型jmp_buf jb和兩個(gè)函數(shù)setjmp(jp)尾抑、longjmp(jp,[1~n]); setjmp(jp)用來(lái)保存當(dāng)前的環(huán)境缅叠,未使用longjmp時(shí)
//其返回值總為0。而當(dāng)使用了longjmp后,程序會(huì)直接跳轉(zhuǎn)到setjmp執(zhí)行后,而且其返回值會(huì)改變,常用來(lái)模擬異常處理
#include <sqlcpr.h> // Pro*C產(chǎn)生的與平臺(tái)相關(guān)的SQLLIB函數(shù)的ANSI原形定義
#include <sqlda.h> //使用動(dòng)態(tài)SQL語(yǔ)句時(shí),需準(zhǔn)備DynamicStagingArea對(duì)象(全局對(duì)象SQLSA)和DynamicDescriptionArea對(duì)象(全局對(duì)象SQLDA)
#include <sqlca.h> //系統(tǒng)默認(rèn)事務(wù)對(duì)象
//定義綁定變量和選擇列表項(xiàng)的最大個(gè)數(shù)
#define MAX_ITEMS 40
//定義綁定變量和選擇列表項(xiàng)名稱的最大長(zhǎng)度
#define MAX_VNAME_LEN 30
//定義指示變量名稱的最大長(zhǎng)度
#define MAX_INAME_LEN 30
/*
struct sqlda
{ //SLI=SELECT-List P=占位符 BV=綁定變量 IV=指示變量
long N; //SLI或P的最大個(gè)數(shù)
char * * V; //指向SLI或BV值的地址數(shù)組的指針
long * L; //指向SLI或BV地址的長(zhǎng)度數(shù)組的指針
short * T; //指向SLI或BV值的數(shù)據(jù)類型數(shù)組的指針
short * * I; //指向IV值的地址數(shù)組指針
long F; //SLI或P的實(shí)際個(gè)數(shù)
char * * S; //指向SLI或P名字的地址數(shù)組的指針
short * M; //指向SLI或P名字的最大長(zhǎng)度數(shù)組的指針
short * C; //指向SLI或P名字的當(dāng)前長(zhǎng)度數(shù)據(jù)組的指針
char * * X; //指向IV名字的地址數(shù)組的指針
short * Y; //指向IV名字最大長(zhǎng)度數(shù)組的指針
short * Z; //指向IV名字當(dāng)前長(zhǎng)度數(shù)組的指針
};
P 占位符 SQL語(yǔ)句中不可缺少的類似 :oraName 這樣的東西
BV 綁定變量 用來(lái)減少硬連接赏壹,提高SQL語(yǔ)句的解析效率
IV 指示變量
//這部分注釋來(lái)源于 https://lj-zhu.iteye.com/blog/682465
N 執(zhí)行DESCRIBE前必須執(zhí)行SQLSQLDAAlloc()函數(shù)給N進(jìn)行復(fù)制,設(shè)定描述數(shù)組的維數(shù)衔沼,其決定了描述字
結(jié)構(gòu)成員數(shù)組的最大元素的最大元素個(gè)數(shù)蝌借。在DESCRIBE命令后昔瞧,必須將存儲(chǔ)在F中的變量真實(shí)個(gè)數(shù)賦值
給N。
V 是一個(gè)指向一個(gè)地址數(shù)組的指針菩佑,在該數(shù)組中存儲(chǔ)SELECT-LIST列值或綁定變量的值自晰。當(dāng)使用SQLSQLDAAlloc
函數(shù)之前,系統(tǒng)給V[0]到V[n-]賦值為0.在使用select descriptors時(shí)稍坯,必須在FETCH語(yǔ)句前酬荞,給V指針
數(shù)組分配內(nèi)存空間,應(yīng)為下列語(yǔ)句要用到兩種描述字的具體的值:
EXEC SQL FETCH ... USING 'select descriptors'
對(duì)于bind descriptors,必須在OPEN語(yǔ)句前分配空間
EXEC SQL OPEN ... USING 'bind descriptors'
L 是一個(gè)指向存放SLI或BV變量值長(zhǎng)度數(shù)組的指針瞧哟。對(duì)于select descriotprs,DESCRIBE SELECT LIST語(yǔ)
句設(shè)置數(shù)組中各元素的值混巧,對(duì)不在SLI的對(duì)應(yīng)長(zhǎng)度設(shè)置成該類型的可定義的最大長(zhǎng)度 。在FETCH語(yǔ)句前勤揩,
用NUMVER類型數(shù)據(jù)存儲(chǔ)到C語(yǔ)言char[]類型咧党,
就需要通過(guò)SQLNumberPrecV6()函數(shù)得到NUMBER長(zhǎng)度,然后轉(zhuǎn)換成字符串后的真實(shí)長(zhǎng)度陨亡。
對(duì)于bind descriptors,用戶必須在OPEN語(yǔ)句前傍衡,給數(shù)組成員賦對(duì)應(yīng)V變量成員長(zhǎng)度的值。
因?yàn)镺racle間接的通過(guò)使用存儲(chǔ)在V[i]變量的地址訪問數(shù)據(jù)區(qū)域负蠕,如果不指定L[i]變量蛙埂,就不能得到
V[i]的存儲(chǔ)數(shù)據(jù)的長(zhǎng)度,如果用戶需要更改V[i]指定數(shù)據(jù)區(qū)域的長(zhǎng)度遮糖,只需要簡(jiǎn)單更改L[i]的值即可
T 指向一個(gè)數(shù)組的指針绣的,在這個(gè)數(shù)組中存放著SLI或者BV的數(shù)據(jù)類型。這個(gè)成員決定了Oracle數(shù)據(jù)存儲(chǔ)到
V數(shù)組中時(shí)如何進(jìn)行轉(zhuǎn)換欲账。
對(duì)于select descriptors,DESCRIBE SELECT LIST語(yǔ)句設(shè)置數(shù)據(jù)類型數(shù)組值為Oracle內(nèi)部數(shù)據(jù)了類型(
char,number或dare等)。在進(jìn)行FETCH前,用戶可能需要重新更改此數(shù)組某元素的值斜脂,因?yàn)镺racle內(nèi)部
數(shù)據(jù)類型很難被C語(yǔ)言所采用玷或。通常為了對(duì)SLI對(duì)用的select descriptors數(shù)據(jù)進(jìn)行線束,需要將數(shù)據(jù)
轉(zhuǎn)換成varchar2或STRING類型。T[i]的高位用來(lái)指示其對(duì)應(yīng)的SLI列值的"NULL/NOT NULL"狀態(tài)京景。在使
用OPEN或FETCH語(yǔ)句前较鼓,需要調(diào)用SQLColumnNummCheck()接受T[i]數(shù)據(jù)類型值禽篱,并清空高位NULL/NOT-
NULL狀態(tài)。
對(duì)于bind descriptors馅精,DECRIBE BIND VARIABLES設(shè)置數(shù)據(jù)類型數(shù)組的各元素為0.用戶必須在OPEN命
令前設(shè)置各輸入宿主變量的數(shù)據(jù)類型第队。變量類型值采用Oracle外部數(shù)據(jù)類型描述哮塞。通常,綁定變量值
存儲(chǔ)在字符串?dāng)?shù)組中凳谦,其對(duì)應(yīng)的T[i]就設(shè)置為1(Varchar2)或者5(STRING).
I 這是一個(gè)指向存儲(chǔ)指示變量值數(shù)組的指針忆畅。
對(duì)于select descriptors,在FETCH語(yǔ)句前必須設(shè)置I數(shù)組各元素所指向的地址。
EXEC SQL FETCH ... USING 'select descriptor'
如果第i各SLI對(duì)應(yīng)的列值為空尸执,則I[i]值為-1 否則是個(gè)》=0的證書家凯。
對(duì)于bind descriptors,必須在OPEN語(yǔ)句前設(shè)置I數(shù)組各變量的值如失。
EXEC SQL OPEN ... USING 'bind descriptor'
F 存放通過(guò)DESCRIBE語(yǔ)句得到的SLI或占位符的真實(shí)數(shù)組绊诲,如果經(jīng)過(guò)DECRIBE語(yǔ)句后F小于零標(biāo)識(shí)DECRIBE
語(yǔ)句發(fā)現(xiàn)的SLI數(shù)目或占位符數(shù)目比分配描述符時(shí)指定的最大數(shù)據(jù)數(shù)目N,例如褪贵,如果設(shè)置N=10但
DESCRIBE發(fā)現(xiàn)SLI的數(shù)目時(shí)11個(gè)掂之,那么F將被設(shè)置成-11,這允許用戶根據(jù)此值那么F將被設(shè)置成-11脆丁,這允許用戶根據(jù)此值重新調(diào)用SQLSQLDAAlloc函數(shù)分配大的描述符存儲(chǔ)區(qū)域世舰。
*/
SQLDA *bindDp; //綁定描述區(qū) 用來(lái)設(shè)置類似 select * from table where ID = :userId 中 userId的值以及相關(guān)設(shè)置
SQLDA *selectDp; //選擇描述區(qū) 用來(lái)設(shè)置使用select語(yǔ)句時(shí),從數(shù)據(jù)庫(kù)中FETCH到的值以及相關(guān)設(shè)置
int OracleConnect(); //數(shù)據(jù)庫(kù)連接函數(shù)
int GetConfValue(char *, char *); //取得設(shè)置文件中的數(shù)據(jù),ourVar實(shí)際上是為了保存取得的值
void Trim(char *); //去除字符串兩邊的空格
void AllocDescriptors(int, int, int); //分配空間給選擇描述區(qū)和綁定描述區(qū)
void DeallocDescriptors(); //釋放分配給選擇描述區(qū)和綁定描述區(qū)的空間
void SetBindVariables(); //設(shè)置綁定變量
void PrintQueryResult(); //輸出從數(shù)據(jù)庫(kù)查詢到的值
int main(int argc, char *argv[])
{
//定義用來(lái)存放動(dòng)態(tài)sql語(yǔ)句的宿主變量槽卫、
EXEC SQL BEGIN DECLARE SECTION;
char SqlQuery[100];
EXEC SQL END DECLARE SECTION;
//連接數(shù)據(jù)庫(kù)
OracleConnect();
//分配綁定描述區(qū)與選擇描述區(qū)
AllocDescriptors(MAX_ITEMS, MAX_VNAME_LEN, MAX_INAME_LEN);
for (; ;)
{
printf("請(qǐng)輸入SQL語(yǔ)句(exit退出): \n");
fgets(SqlQuery, 100, stdin);
if ((strncmp(SqlQuery, "exit", 4) == 0) || (strncmp(SqlQuery, "EXIT", 4) == 0))
{
break;
}
//準(zhǔn)備動(dòng)態(tài)sql語(yǔ)句
EXEC SQL PREPARE S FROM :SqlQuery;
if (sqlca.sqlcode != 0)
{
continue;
}
//定義游標(biāo)
EXEC SQL DECLARE C CURSOR FOR S;
if (sqlca.sqlcode != 0)
{
continue;
}
//設(shè)置綁定變量
SetBindVariables();
//打開游標(biāo)
EXEC SQL OPEN C USING DESCRIPTOR bindDp;
printf("open cursor sqlcode : %d\n", sqlca.sqlcode);
printf("list :\n|%s|\n", SqlQuery);
//如果是select語(yǔ)句跟压,那么就要打印結(jié)果集
if ((strncmp(SqlQuery, "select", 6) ==0) || (strncmp(SqlQuery, "SELECT", 6) == 0))
{
printf("Printf Query Result:\n");
PrintQueryResult();
}
printf("return code %d\n", sqlca.sqlcode);
//關(guān)閉游標(biāo) 提交結(jié)果
EXEC SQL CLOSE C;
EXEC SQL COMMIT WORK;
}
//釋放綁定描述符與選擇描述符
printf("DEAllocDescriptors :\n");
DeallocDescriptors();
//提交更改 釋放數(shù)據(jù)庫(kù)連接
printf("EXEC SQL COMMIT WORK RELEASW:\n");
EXEC SQL COMMIT WORK RELEASE;
printf("程序關(guān)閉\n");
return 0;
}
int OracleConnect() //數(shù)據(jù)庫(kù)連接函數(shù)
{
char str[100] = {0};
char port[10] = {0};
char ip[50] = {0};
char threadMax[5] = {0};
EXEC SQL BEGIN DECLARE SECTION;
char oraSid[50] = {0};
char oraUser[50] = {0};
char oraPass[50] = {0};
EXEC SQL END DECLARE SECTION;
if ((GetConfValue("oraSid", oraSid) == 0) || //從配置文件中取得相關(guān)信息
(GetConfValue("oraUser", oraUser) == 0) ||
(GetConfValue("oraPass", oraPass) == 0) ||
(GetConfValue("ip", ip) == 0) ||
(GetConfValue("port", port) == 0))
{
printf("value is not found\n");
return 0;
}
//數(shù)據(jù)庫(kù)連接
EXEC SQL CONNECT :oraUser IDENTIFIED BY :oraPass using :oraSid;
if (sqlca.sqlcode != 0)
{
perror("db connect :");
printf("sqlcode = %d ->%s ->%s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrml, sqlca.sqlerrm.sqlerrmc);
return 0;
}
printf("Connect success\n");
return 1;
}
int GetConfValue(char *type, char *outVar) //從配置文件中獲取信息
{
char *confFile = "conf.txt";
char buf[1024] = {0};
char typeStr[1024] = {0};
int i = 0;
FILE *fp = NULL; //FILE實(shí)際上是一個(gè)結(jié)構(gòu)體
if (!(fp = fopen(confFile, "r"))) //'r'以只讀的方式打開文件,fopen返回一個(gè)指針,也可以進(jìn)行真or假判斷
{
perror("conf.txt open :");
return 0;
}
while (fgets(buf, 1024, fp)) //fgets 讀取fp中的數(shù)據(jù)歼培,每次讀取一行震蒋,讀取size-1個(gè)字符,并在后面補(bǔ)上一個(gè)'\0'丐怯。
{
for (i = 0; i < 1024; i++) //喷好!BUG 1024寫成了2024.翔横。读跷。
{
if (buf[i] == '=')
{
strncpy(typeStr, buf ,i); //復(fù)制 = 前面的i個(gè)字符
Trim(typeStr); //去除字符串兩邊的空格
}
if (strcmp(type, typeStr)==0) //截取到的字符串與輸出的字符串相同,說(shuō)明找到了想要獲取的目標(biāo)
{
strcpy(outVar, buf+i+1); //將 = 后面的字符串復(fù)制到outVar中
outVar[strlen(outVar) -1]='\0';
Trim(outVar);
return 1;
}
}
}
printf("%s not found \n", type);
return 0;
}
void Trim(char *inVar) //自定義函數(shù)禾唁,目的是為了去除字符串兩邊的空格
{
int i = 0;
int j = strlen(inVar) - 1; //strlen一個(gè)指針數(shù)組效览,返回的長(zhǎng)度是不包含'/0'的.因?yàn)閖要作為數(shù)組下標(biāo)无切,所以這里要減去1
while (inVar[i] == ' ')
{
i++;
}
while (inVar[j] == ' ')
{
j--;
}
strncpy(inVar, inVar + i ,j - i + 1); //要把當(dāng)前j指向的字符也放進(jìn)去,所以要加上一個(gè)1
inVar[j - i + 1] = '\0'; //手動(dòng)加上'/0',因?yàn)榇藭r(shí)inVar的元素有j-i+1個(gè)丐枉,而最后一個(gè)元素的下標(biāo)為j-i+1-1,所以j-i+1-1+1=j-i+1上添加一個(gè)'/0'
}
void AllocDescriptors(int size, int maxVnameLen, int maxInameLen) //分配描述區(qū)
{
int i;
//分配綁定描述區(qū)和選擇描述區(qū) size:最大STL或P數(shù)量 即N maxVnameLen:STI或P最大名字長(zhǎng)度 即M maxInameLen:存儲(chǔ)指示變量最大名字長(zhǎng)度 即Y
bindDp = SQLSQLDAAlloc(0, size, maxVnameLen, maxInameLen);
selectDp = SQLSQLDAAlloc(0, size, maxVnameLen, maxInameLen);
//為指示變量哆键,綁定變量分配內(nèi)存
for (i = 0; i < MAX_ITEMS; i++)
{
bindDp->I[i] = (short *)malloc(sizeof(short)); //I 指示變量的地址
selectDp->I[i] = (short *)malloc(sizeof(short));
bindDp->V[i] = (char *)malloc(sizeof(char)); //V STI或P的地址
selectDp->V[i] = (char *)malloc(sizeof(char));
}
}
void DeallocDescriptors()
{
int i = 0;
//釋放指示變量、綁定變量或選擇列表項(xiàng)的內(nèi)存
for (i = 0; i < MAX_ITEMS; i++)
{
if (bindDp->V[i] != (char *)0)
{
printf("FREE bindDp the %d:\n", i);
free(bindDp->V[i]);
bindDp->V[i] = NULL; //釋放數(shù)組空間后瘦锹,手動(dòng)指向NULL是一個(gè)好習(xí)慣
printf("FREE bindDp OVER %d:\n", i);
}
free(bindDp->I[i]);
bindDp->I[i] = NULL;
if (selectDp->V[i] != (char *)0)
{
printf("FREE selectDp the %d:\n", i);
free(selectDp->V[i]);
selectDp->V[i] = NULL;
printf("FREE selectDp OVER %d:\n", i);
}
free(selectDp->I[i]);
selectDp->I[i] = NULL;
}
printf("SQLSQLDAFree:\n");
//釋放綁定描述區(qū)和選擇描述區(qū)
SQLSQLDAFree(0, bindDp);
SQLSQLDAFree(0, selectDp);
}
void SetBindVariables() //進(jìn)項(xiàng)綁定變量的設(shè)置
{
int i = 0;
char bindVar[64] = {0};
//設(shè)置綁定變量的最大個(gè)數(shù)
//bindDp->N = MAX_ITEMS; //多次一舉籍嘹??弯院?前面已經(jīng)將N初始化
//作用辱士,將S語(yǔ)句中的綁定變量放入bindDp中?
EXEC SQL DESCRIBE BIND VARIABLES FOR S INTO bindDp;
printf("BIND VARIABLES sqlcode : %d\n", sqlca.sqlcode);
//DESCRIBE后听绳,將sqlda->F中綁定變量真實(shí)的數(shù)量給sqlda->N
bindDp->N = bindDp->F;
//開始循環(huán)處理綁定變量
for (i = 0; i < bindDp->F; i++)
{
//顯示綁定變量值 這里實(shí)際上顯示的是占位符的名字
printf("請(qǐng)輸入綁定變量 %.*s : ", (int)bindDp->C[i], bindDp->S[i]);
//獲得綁定變量值 fgets會(huì)讀取換行符颂碘,所以要想辦法把換行符去掉,要不然就會(huì)讀取到相鄰的數(shù)據(jù)
fgets(bindVar, 100, stdin);
bindVar[strlen(bindVar) - 1] = '\0';
//也可以使用scanf scanf不會(huì)讀取到換行符
//scanf("%s", bindVar);
//設(shè)置綁定變量的長(zhǎng)度 Oracle通過(guò)V[i]的地址(即字符串的首地址)訪問綁定變量椅挣,所以必須告知其長(zhǎng)度L
bindDp->L[i] = strlen(bindVar);
printf("bindDp->L[%d] = %d\n", i, bindDp->L[i]);
//為綁定變量緩存區(qū)重新分配內(nèi)存头岔,多一位留給'\0' realloc重新分配地址 sqlda->L是指針的指針,sqlda->L[i]訪問外層指針?biāo)赶虻闹羔?
//V[i]保存的實(shí)際上是一個(gè)字符串?dāng)?shù)組鼠证,因?yàn)閏har的長(zhǎng)度為1峡竣,并且char需要一個(gè)'/0'作為終止符,所以寫法如下名惩。 int數(shù)組寫法 sizeof(int)*length
bindDp->V[i] = (char *)realloc(bindDp->V[i], bindDp->L[i] + 1);
//將綁定變量數(shù)據(jù)放入
strcpy(bindDp->V[i], bindVar);
//設(shè)置指示變量澎胡,處理NULL 可能是因?yàn)槿绻斎隢ULL,也會(huì)當(dāng)作字符串娩鹉,所以就用一個(gè)變量指定
if ((strncmp(bindVar, "NULL", 4) == 0) || (strncmp(bindVar, "null", 4) == 0))
{
*bindDp->I[i] = -1; //sqlda->I[i]表示外層指針指向的指針攻谁,*sqlda->I[i]則標(biāo)識(shí)指針指向的指針指向的值
}
else
{
*bindDp->I[i] = 0;
}
//設(shè)置數(shù)據(jù)緩沖區(qū)數(shù)據(jù)類型代碼 char
bindDp->T[i] = 1;
printf("This BindVar is : %s\n", bindDp->V[i]);
}
}
void PrintQueryResult() //輸出select查詢語(yǔ)句獲取到的數(shù)據(jù)庫(kù)數(shù)據(jù)
{
int i = 0; //循環(huán)用
int nullOk;
int precision;
int scale;
char title[30]; //保存列名
//設(shè)置選擇列表項(xiàng)的最大個(gè)數(shù)
//selectDp->N = MAX_ITEMS; //應(yīng)該也是多此一舉
//選擇列表項(xiàng),選擇描述區(qū)
EXEC SQL DESCRIBE SELECT LIST FOR S INTO selectDp;
printf("DESCRIBE SELECT LIST sqlcode is : %d\n", sqlca.sqlcode);
//設(shè)置選擇列表項(xiàng)的實(shí)際個(gè)數(shù)
selectDp->N = selectDp->F;
//循環(huán)處理選擇列表項(xiàng)
for (i = 0; i < selectDp->F; i++)
{
//清除selectDp->T[i]的高位->null T保存對(duì)應(yīng)選擇列表項(xiàng)的數(shù)據(jù)類型 高位則指示其是否能為null
//并根據(jù)數(shù)據(jù)庫(kù)中此項(xiàng)是否能夠?yàn)閚ull設(shè)置nullOk的值 如果允許為空 nullOk=1 否則為0
//0001 0001 1001 0001 左八位為高位弯予、右八位為低位 當(dāng)然戚宦,并不知T的結(jié)構(gòu)是否如此
SQLColumnNullCheck(0, (unsigned short *)&selectDp->T[i], (unsigned short *)&selectDp->T[i], &nullOk);
//根據(jù)內(nèi)部數(shù)據(jù)類型確定外部數(shù)據(jù)類型長(zhǎng)度 很明顯T存儲(chǔ)類型是數(shù)值形式的
switch (selectDp->T[i])
{
case 2:
//number數(shù)據(jù)類型,取得精度與標(biāo)度 -4.75 精度=3锈嫩,標(biāo)度=2
SQLNumberPrecV6(0, (unsigned int *)&selectDp->L[i], &precision, &scale);
//oracle使用number保存所有的數(shù)值類型受楼,但現(xiàn)在要把它放出來(lái),就要有一個(gè)對(duì)應(yīng)的外部數(shù)值類型的長(zhǎng)度保存
if (scale > 0) //scale大于零呼寸,說(shuō)明有小數(shù)位艳汽,那么就要用float保存number
{
selectDp->L[i] = sizeof(float);
}
else //如果沒有小數(shù)位,那么就可以愉快地使用int存了
{
selectDp->L[i] = sizeof(int);
}
break;
case 12:
//data數(shù)據(jù)類型
selectDp->L[i] = 9;
break;
}
//還有第三種數(shù)據(jù)類型 varchar類型 推測(cè)因?yàn)長(zhǎng)[i]中初始保存的數(shù)據(jù)類型長(zhǎng)度就是對(duì)應(yīng)的char[]長(zhǎng)度对雪,所以不用進(jìn)行處理河狐??? -------------含有疑問
//根據(jù)變量長(zhǎng)度馋艺,重新為選擇列表項(xiàng)分配內(nèi)存
if (selectDp->L[i] != 2) //其他類型(其實(shí)本質(zhì)是字符串栅干??) -------------------含有疑問
{
selectDp->V[i] = (char *)realloc(selectDp->V[i], selectDp->L[i]+1);
}
else //number類型
{
selectDp->V[i] = (char *)realloc(selectDp->V[i], selectDp->L[i]);
}
//初始化title
memset(title, ' ', 30); //寫memset(title, '0', 30) 也行捐祠,反正這里只是用來(lái)輸出碱鳞,但是填' '輸出比較好看
//選擇列表項(xiàng)名稱 S保存選擇列表項(xiàng)名字地址的指針 C保存選擇列表項(xiàng)名字地址長(zhǎng)度的指針
strncpy(title, selectDp->S[i], selectDp->C[i]);
//顯示列名
if (selectDp->T[i] == 2) //T保存數(shù)據(jù)類型
{
if (scale > 0)
{
printf("\t%.*s", selectDp->L[i] + 3, title); //指向STI的地址的長(zhǎng)度的數(shù)組 在輸出列名的時(shí)候就設(shè)置好格式
}
else
{
printf("\t%.*s", selectDp->L[i], title);
}
}
else
{
printf("\t%-.*s", selectDp->L[i], title);
}
//根據(jù)oracle內(nèi)部類型確定外部類型
if (selectDp->T[i] == 2)
{
if (scale > 0) //float
{
selectDp->T[i] = 4;
}
else //int
{
selectDp->T[i] = 3;
}
}
else //char
{
selectDp->T[i] = 1;
}
}
printf("\n");
//當(dāng)selectDp中的數(shù)據(jù)處理完畢后,跳出
EXEC SQL whenever not found do break;
//printf("WHEN NOT FOUND sqlcode is : %d\n", sqlca.sqlcode);
//EXEC SQL DECLARE C CURSOR FOR S; //--------------含有疑問
//printf("DECLARE C sqlcode is : %d\n", sqlca.sqlcode);
int n = 0;
//循環(huán)輸出數(shù)據(jù)
for(; ;)
{
//用選擇描述區(qū)提取數(shù)據(jù) ----------含有疑問
//這個(gè)語(yǔ)句有問題
EXEC SQL FETCH C using DESCRIPTOR selectDp;
//開始顯示數(shù)據(jù)
for (i = 0; i < selectDp->F; i++)
{
//處理null值
if (*selectDp->I[i] < 0)
{
printf("\tNull");
}
else
{
if (selectDp->T[i] == 3)
{
printf("\t%d", *(int *)selectDp->V[i]);
}
else if (selectDp->T[i] == 4)
{
printf("\t%8.2f", *(float *)selectDp->V[i]);
}
else //char
{
printf("\t%.*s", selectDp->L[i], selectDp->V[i]);
}
}
}
printf("\n");
//n++;
/*if (n%1000 == 0)
{
char a[10] = {0};
scanf("%s", &a);
if(!strncmp(a, "break", 5))
{
break;
}
}*/
}
}
在定義了一個(gè)sqlda結(jié)構(gòu)體后踱蛀,要使用SQLSQLDAAlloc()函數(shù)為其分配空間窿给。
descriptor_name = SQLSQLDAAlloc (runtime_context, max_vars, max_name, max_ind_name);
//runtime_context //運(yùn)行時(shí)上下文指針
//max_vars //最大SLI或者P數(shù)量 即N
//max_name //SLI或者P最大名字長(zhǎng)度 即M
//max_ind_name /IV最大名字長(zhǎng)度 即Y
宿主變量與指示變量還有綁定變量
EXEC SQL DECLARE BEGIN SECTION;
int oraId = 0; //宿主變量
EXEC SQL DECLARE END SECTION;
//指示器變量是與宿主變量相關(guān)聯(lián)的一類SQL變量,它被用來(lái)監(jiān)督和管理與其相關(guān)聯(lián)的宿主變量率拒,每一個(gè)宿主變量都可以定義一個(gè)指示器變量填大。
//綁定變量 對(duì)于提交的sql語(yǔ)句,有硬解和軟解兩重方式俏橘。第一次提交的sql語(yǔ)句會(huì)采用硬解會(huì)消耗大量的系統(tǒng)資源允华。而如果提交的sql語(yǔ)句
//在數(shù)據(jù)庫(kù)中已有,則為軟解寥掐。針對(duì)查詢同一類數(shù)據(jù)的情況靴寂,就使用了綁定變量,提高效率召耘。