我有以下可用于DB2的代码。
有SQLDA声明......
extern struct sqlca sqlca;
struct{struct sqlda daNM;
struct sqlvar vaNM[6];
} C_NM={"SQLDA ",280,6,6,
492, 8,(char*)&NMTBL.namn, 0,4,"NAMN",
452, 1,(char*)&NMTBL.ssncd, 0,5,"SSNCD",
497, 4,(char*)&NMTBL.ssn, &NMTBL.Fssn ,3,"SSN",
448, 65,(char*)&NMTBL.lna, 0,3,"LNA",
449, 46,(char*)&NMTBL.fna, &NMTBL.Ffna ,3,"FNA",
449, 80,(char*)&NMTBL.nm2ln, &NMTBL.Fnm2ln ,5,"NM2LN"};
struct sqlda *pNM = (struct sqlda*)&C_NM;
然后是光标声明...
EXEC SQL DECLARE C_NM_# CURSOR FOR SELECT NAMN, SSNCD, SSN, LNA, FNA, NM2LN FROM ASL.NMTBL
WHERE NAMN = :Q_namn FOR FETCH ONLY;
最后是一个打开,提取和关闭光标的方法。
void fetch_name_nd(__int64 namn,__int32 commit)
{ /** fetch name with no display **/
struct sqlca ret_sqlca;
Q_namn = namn;
EXEC SQL OPEN C_NM_#;
if (sqlca.sqlcode != 0)
show_error("Error in opening nametable in 'REA_LIB'",1);
memset(&NMTBL,0,sizeof(NMTBL));
EXEC SQL FETCH C_NM_# USING DESCRIPTOR :*pNM;
if (sqlca.sqlcode != 0)
if (sqlca.sqlcode == 100)
show_error("Couldn't find the correct nam# in NMTBL",1);
else show_error("Error in Fetching from the NMTBL",1);
ret_sqlca = sqlca;
EXEC SQL CLOSE C_NM_#;
if (sqlca.sqlcode != 0)
show_error("Error in closing table after reading name",1);
if (commit)
{
EXEC SQL COMMIT;
if (sqlca.sqlcode != 0)
show_error("Error commiting after fetching name from Database",1);
}
sqlca = ret_sqlca; /** copy value from fetch **/
}
在该方法结束时,我可以在结构中使用数据库值,以便在我喜欢的地方使用,NMTBL.lna等。
我通过https://www.postgresql.org/docs/current/static/ecpg.html和https://www.postgresql.org/docs/current/static/ecpg-variables.html阅读,似乎非常类似于DB2。
然而https://www.postgresql.org/docs/9.1/static/ecpg-descriptors.html在我的SQLDA定义和用法方面失去了我。
是否有人使用类似的SQLDA描述符来查询嵌入式SQL C / C ++程序中的数据,以及可能能够提供建议的PostgreSQL数据库?
答案 0 :(得分:0)
看来ecpg不允许您预先定义光标结果的去向。最后,我没有预先定义一个将光标放在我想要的结构中的SQLDA结构,而是编写了一个函数来填充ecpg填充的动态sqlda中所需的结构。
例如,现在我只定义一个sqlda指针
sqlda_t *sqlda_ap;
然后我将光标移到那个
EXEC SQL DECLARE c_ap CURSOR FOR SELECT COL1, COL2 FROM SCHEMA.TABLE WHERE PK=1234;
EXEC SQL OPEN c_ap;
EXEC SQL FETCH c_ap INTO DESCRIPTOR sqlda_ap;
EXEC SQL CLOSE c_ap;
然后我调用我的函数将结果拉出sqlda指针并填充我的结构。
processSqlda_APbuf(sqlda_ap);
这将遍历sqlvar []的每个成员并提取相应的值。
void processSqlda_APbuf(sqlda_t* sqlda)
{
if (sqlda == NULL)
{
printf("can't continue - sqlda is null");
return;
}
for (int i = 0; i < sqlda->sqld; i++)
{
if (memcmp(sqlda->sqlvar[i].sqlname.data, "codes", 5) == 0)
{
memcpy(APbuf.codes, sqlda->sqlvar[i].sqldata, 4);
}
if (memcmp(sqlda->sqlvar[i].sqlname.data, "adrn", 5) == 0)
{
APbuf.adrn = *(long long int*)sqlda->sqlvar[i].sqldata;
APbuf.Fadrn = *sqlda->sqlvar[i].sqlind;
}
if (memcmp(sqlda->sqlvar[i].sqlname.data, "nam", 4) == 0)
{
APbuf.nam[0] = *(long long int*)sqlda->sqlvar[i].sqldata;
APbuf.Fnam[0] = *sqlda->sqlvar[i].sqlind;
}
if (memcmp(sqlda->sqlvar[i].sqlname.data, "aslkey", 6) == 0)
{
memcpy(APbuf.aslkey, sqlda->sqlvar[i].sqldata, 6);
}
}
}
这让我可以像我原来那样访问结构中的值,因此程序的其余部分保持不变。如果碰巧在其他时间拯救别人,那么欢迎您。 :)很可能很多人都没有从DB2的嵌入式sql迁移到PostgreSQL的ecpg嵌入式sql ......但是哦。
更新: 这里有一些代码来获取旧的SQLDA结构(DB2样式)并生成一个函数来读取动态SQLDA并填充最初使用的结构。你只需要一个带有两个文本框的窗口,txtOld和txtNew。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void txtOld_TextChanged(object sender, TextChangedEventArgs e)
{
var old = txtOld.Text;
var n = new StringBuilder();
var structName = "bogus";
foreach (var line in old.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries))
{
var words = line.Split(',');
if (words.Length != 6 && words.Length != 7)
continue;
var dataType = int.Parse(words[0]);
var dataLen = int.Parse(words[1]);
var dest = words[2].Replace("(", "").Replace("char", "").Replace(" ", "").Replace("*", "").Replace(")", "").Replace("&", "");//UGLY!
var nullIndicator = words[3].Replace("&", "").Trim();
var colLen = words[4];
var colName = words[5].ToLower();
if (structName == "bogus")
structName = dest.Split('.')[0];
switch (dataType)
{
case 384://date
case 388://time
case 448://non-null varchar
case 449://nullable varchar
addOpening(n, colLen, colName);
n.AppendLine($" memcpy({dest}, sqlda->sqlvar[i].sqldata, {dataLen});");
if (dataType % 2 == 1)
addNullIndicator(n, nullIndicator);
addClosing(n);
break;
case 452://non-null char
case 453://nullable char
addOpening(n, colLen, colName);
if (dataLen == 1)
n.AppendLine($" {dest} = *sqlda->sqlvar[i].sqldata;");
else
n.AppendLine($" memcpy({dest}, sqlda->sqlvar[i].sqldata, {dataLen});");
if (dataType % 2 == 1)
addNullIndicator(n, nullIndicator);
addClosing(n);
break;
case 480://non-null double
case 481://nullable double
addOpening(n, colLen, colName);
n.AppendLine($" {dest} = *(double*)sqlda->sqlvar[i].sqldata;");
if (dataType % 2 == 1)
addNullIndicator(n, nullIndicator);
addClosing(n);
break;
case 492://non-null bigint
case 493://nullable bigint
addOpening(n, colLen, colName);
n.AppendLine($" {dest} = *(long long int*)sqlda->sqlvar[i].sqldata;");
if (dataType % 2 == 1)
addNullIndicator(n, nullIndicator);
addClosing(n);
break;
case 496://non-null int
case 497://nullable int
addOpening(n, colLen, colName);
n.AppendLine($" {dest} = *(long int*)sqlda->sqlvar[i].sqldata;");
if (dataType % 2 == 1)
addNullIndicator(n, nullIndicator);
addClosing(n);
break;
case 500://non-null short
case 501://nullable short
addOpening(n, colLen, colName);
n.AppendLine($" {dest} = *(short*)sqlda->sqlvar[i].sqldata;");
if (dataType % 2 == 1)
addNullIndicator(n, nullIndicator);
addClosing(n);
break;
default:
throw new ArgumentOutOfRangeException($"what is type {dataType}?!");
}
}
n.Append(funcEnd);
txtNew.Text = funcBegin(structName) + n;
}
private static void addClosing(StringBuilder n)
{
n.AppendLine(" }");
}
private static void addOpening(StringBuilder n, string colLen, string colName)
{
n.AppendLine($" if(memcmp(sqlda->sqlvar[i].sqlname.data, {colName}, {colLen}) == 0)");
n.AppendLine(" {");
}
private static void addNullIndicator(StringBuilder n, string nullIndicator)
{
n.AppendLine($" {nullIndicator} = *sqlda->sqlvar[i].sqlind;");
}
string funcBegin(string structName)
{
return @"
void processSqlda_{{structName}}(sqlda_t* sqlda)
{
if (sqlda == NULL)
{
printf(""can't continue - sqlda is null"");
return;
}
for (int i = 0; i<sqlda->sqld; i++)
{
".Replace("{{structName}}", structName);
}
string funcEnd = @"
}
}";
}
}