似乎 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 = @"
}
}";
}
}