将 SQLDA 从 DB2 转换为 PostgreSQL
Converting SQLDA from DB2 to PostgreSQL
我有以下当前适用于 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 and 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 数据库查询数据可能能够建议?
ecpg 似乎不允许您 pre-define 光标结果所在的位置。最后,我编写了一个函数来从 ecpg 填充的动态 sqlda 中填充所需的结构,而不是 pre-defining 将游标结果放置在我想要的结构中的 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 并填充 originally-used 结构。您只需要一个 window 和两个文本框,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 = @"
}
}";
}
}
我有以下当前适用于 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 and 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 数据库查询数据可能能够建议?
ecpg 似乎不允许您 pre-define 光标结果所在的位置。最后,我编写了一个函数来从 ecpg 填充的动态 sqlda 中填充所需的结构,而不是 pre-defining 将游标结果放置在我想要的结构中的 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 并填充 originally-used 结构。您只需要一个 window 和两个文本框,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 = @"
}
}";
}
}