-1

私のCプログラムでは、次の形式の入力を受け取っています

     "name,age,salary|Richard,35,10000"

ここで、この入力から挿入クエリと更新クエリを組み立てたいと思います。

この目的のためにstrtok_randを使用しています。strtok

しかし、私の問題は、挿入または更新中に、「Richard」のような varchar データ型を二重引用符で囲む必要があることです。

入力には固定パターンはなく、任意の順序にすることができます。

  • 毎回すべての列のデータ型を確認する必要がありますか?

  • より良いアプローチはありますか?

私が使用しているデータベースは Informix です。私は ESQL/C を使用しています。これは SQL 拡張機能が埋め込まれた古い C です。

4

1 に答える 1

1

これに対処する最善の方法は、ホスト変数を使用することです。つまり、値を引用符で囲む必要はありません。Informixは、文字列を他のタイプに変換するのに非常に優れています。問題が発生する唯一のタイプは、BLOB(BYTE、TEXT、BLOB、CLOB)です。

このコードはコンパイルされただけです。実行されていません。さまざまなreturnステートメントは、最後を除いてエラーリターンです。プリペアドステートメントを解放せずに戻ることが正しいかどうかを議論することができます。そうではないことは容易に議論の余地があります。このモンスターから構築されたいくつかのルーチンがあるはずです。

#include "sqlca.h"
#include "sqlda.h"
#include "sqltypes.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>

extern int insert_record(char *line, const char *tabname);

int insert_record(char *line, const char *tabname)
{
    /* Analyze line */
    char *pipe = strchr(line, '|');
    char *comma = line;
    int c_count = 0;
    int v_count = 0;
    while ((comma = strchr(comma, ',')) != 0 && comma < pipe)
        c_count++;
    comma = pipe;
    while ((comma = strchr(comma, ',')) != 0)
        v_count++;
    if (v_count != c_count)
        return(-1);
    char *names[c_count];
    char *value[c_count];
    char *np = line;
    char *vp = pipe+1;
    for (int i = 0; i < c_count; i++)
    {
        names[i] = np;
        value[i] = vp;
        char *sep = strchr(np, ',');
        assert(sep != 0);
        if (sep > pipe)
            sep = pipe;
        *sep = '\0';
        np = sep + 1;
        sep = strchr(vp, ',');
        if (sep != 0)
        {
            *sep = '\0';
            vp = sep + 1;
        }
    }

    /* Create SQL statement with placeholders */
    /* names[i] contains column name for entry i; value[i] contains the value */
    $ char buffer[4096];
    char *sql = buffer;
    int len = sizeof(buffer) - 1;
    int num = snprintf(sql, len, "insert into %s", tabname);
    if (num <= 0 || num >= len)
        return(-2);
    if (num <= 0 || num >= len)
        return(-2);
    sql += num;
    len -= num;
    pad = "(";
    for (int i = 0; i < c_count; i++)
    {
        num = snprintf(sql, len, "%s%s", pad, "?");
        if (num <= 0 || num >= len)
            return(-2);
        sql += num;
        len -= num;
    }
    num = snprintf(sql, len, ")");
    if (num <= 0 || num >= len)
        return(-2);

    $ PREPARE p_insert FROM :buffer;
    if (sqlca.sqlcode != 0)
        return(sqlca.sqlcode);

    /* Create sqlda to describe strings */
    ifx_sqlda_t data;
    ifx_sqlvar_t columns[c_count];
    $ struct sqlda *udesc = &data;
    data.sqld = c_count;
    data.sqlvar = columns;
    data.desc_name[0] = '\0';
    data.desc_occ = 0;
    data.reserved = 0;
    data.desc_next = 0;
    for (int i = 0; i < c_count; i++)
    {
        columns[i].sqltype       = SQLVCHAR;
        columns[i].sqllen        = strlen(value[i]);
        columns[i].sqldata       = value[i];
        columns[i].sqlind        = 0;
        columns[i].sqlname       = names[i];
        columns[i].sqlformat     = 0;
        columns[i].sqlitype      = 0;
        columns[i].sqlilen       = 0;
        columns[i].sqlidata      = 0;
        columns[i].sqlxid        = 0;
        columns[i].sqltypename   = 0;
        columns[i].sqltypelen    = 0;
        columns[i].sqlownerlen   = 0;
        columns[i].sqlsourcetype = 0;
        columns[i].sqlownername  = 0;
        columns[i].sqlsourceid   = 0;
        columns[i].sqlilongdata  = 0;
        columns[i].sqlflags      = 0;
        columns[i].sqlreserved   = 0;
    }

    /* Execute the SQL and clean up */
    $ EXECUTE p_insert USING DESCRIPTOR udesc;
    if (sqlca.sqlcode != 0)
        return(sqlca.sqlcode);
    $ FREE p_insert;
    if (sqlca.sqlcode != 0)
        return(sqlca.sqlcode);
    return(0);
}
于 2012-12-22T23:36:21.640 に答える