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