将SQLDA从DB2转换为PostgreSQL

时间:2018-02-15 19:55:22

标签: postgresql postgresql-10 ecpg

我有以下可用于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.htmlhttps://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数据库?

1 个答案:

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