转义字符插入数据库

时间:2014-12-24 18:31:09

标签: mysql c database

我使用下面的代码将任意二进制数据插入到mysql数据库MEDIUMBLOB中。我将相同的数据写入同一程序的文件中。然后我从DB内容创建一个文件:

select data from table where tag=95 order by date, time into outfile "dbout";

然后我将直接写入文件的输出与dbout中的输出进行比较。在dbout文件中的某些字节之前有转义(0x5c,' \')字符(例如在0x00之前)。这会使数据库的输出变得混乱。我的理解是,通过使用MEDIUMBLOB和准备好的语句,我可以避免这个问题。最初我使用mysql_real_escape_string与常规INSERT,并遇到问题。似乎没有什么能解决这个问题。

void
insertdb(int16_t *data, size_t size, size_t nmemb)
{
    int16_t *fwbuf; // I have also tried this as char *fwbuf
    unsigned long i;
    struct tm *info;
    time_t rawtime;
    char dbuf[12];
    char tbuf[12];

    if(fwinitialized==0){
        fwbuf = malloc(CHUNK_SZ);
        fwinitialized = 1;
    }

    if(fwindex + (nmemb*size) + 1 >= CHUNK_SZ || do_exit == 1){
        MYSQL_STMT *stmt = mysql_stmt_init(con);
        MYSQL_BIND param[1];

        time(&rawtime);
        info = localtime(&rawtime);
        snprintf(dbuf, 16, "%d-%02d-%02d", 1900+info->tm_year, 1+info->tm_mon, info->tm_mday);
        snprintf(tbuf, 16, "%02d:%02d:%02d", info->tm_hour, info->tm_min, info->tm_sec);

        char *tmp = "INSERT INTO %s (date, time, tag, data) VALUES ('%s', '%s', %d, ?)";
        int len = strlen(tmp)+strlen(db_mon_table)+strlen(dbuf)+strlen(tbuf)+MAX_TAG_LEN+1;
        char *sql = (char *) malloc(len);
        int sqllen = snprintf(sql, len, tmp, db_mon_table, dbuf, tbuf, tag);

        if(mysql_stmt_prepare(stmt, sql, strlen(sql)) != 0){
            printf("Unable to create session: mysql_stmt_prepare()\n");
            exit(1);
        }

        memset(param, 0, sizeof(param));
        param[0].buffer_type = MYSQL_TYPE_MEDIUM_BLOB;
        param[0].buffer = fwbuf;
        param[0].is_unsigned = 0;
        param[0].is_null = 0;
        param[0].length = &fwindex;

        if(mysql_stmt_bind_param(stmt, param) != 0){
            printf("Unable to create session: mysql_stmt_bind_param()\n");
            exit(1);
        }

        if(mysql_stmt_execute(stmt) != 0){
            printf("Unabel to execute session: mysql_stmt_execute()\n");
            exit(1);
        }

        printf("closing\n");
        mysql_stmt_close(stmt);

        free(sql);
        fwindex = 0;

    } else {
        memcpy((void *) fwbuf+fwindex, (void *) data, nmemb*size);
        fwindex += (nmemb*size);
    }
}

那么,为什么数据库中的转义字符?我在程序中和从msyql创建文件时尝试了几种hex / unhex的组合。这似乎也无济于事。不将任意二进制数据插入数据库是一种常见的解决方案吗?

P.S。 - 是否可以像这样打开,插入和关闭准备好的语句,或者是准备好的语句,通常用于在关闭之前循环和插入一堆数据?

PPS - 也许这对问题很重要:当我尝试像这样使用UNHEX时:

select unhex(data) from table where tag=95 order by date, time into outfile "dbout";

输出非常短(少于十几个字节,由于某种原因被截断)。

1 个答案:

答案 0 :(得分:1)

由于MEDIUMBLOB可以包含任何字符(甚至是ASCII NUL),MySQL通常会转义输出,因此您可以判断字段何时结束。您可以使用ESCAPED BY控制此操作。文档是here。以下是摘录。根据下面的最后一段(我以粗体显示),您可以完全禁用转义。由于最后一句话的原因,我从未尝试过。

  

FIELDS ESCAPED BY控制如何编写特殊字符。如果FIELDS ESCAPED BY字符不为空,则在必要时使用它以避免歧义作为输出后面字符之前的前缀:

     
      
  • FIELDS ESCAPED BY字符

  •   
  • FIELDS [OPTIONALLY] ENCLOSED BY字符

  •   
  • FIELDS TERMINATED BYLINES TERMINATED BY值的第一个字符

  •   
  • ASCII NUL(零值字节;转义字符后面实际写的是ASCII "0",而不是零值字节)

  •   
     

必须转义FIELDS TERMINATED BYENCLOSED BYESCAPED BYLINES TERMINATED BY个字符,以便您可以可靠地读取该文件。转义ASCII NUL,以便使用某些寻呼机更容易查看。

     

生成的文件不必符合SQL语法,因此不需要转义任何其他内容。

     

如果FIELDS ESCAPED BY字符为空,则不转义字符,NULL输出为NULL,而不是\N可能是指定空的转义字符不是一个好主意,特别是如果数据中的字段值包含刚刚给出的列表中的任何字符。

更好的策略(如果输出文件中只需要一个blob)是SELECT INTO ... DUMPFILE,记录在同一页面上,如下所示:

  

如果使用INTO DUMPFILE而不是INTO OUTFILE,MySQL只会在文件中写入一行,不会有任何列或行终止,也不会执行任何转义处理。如果要将BLOB值存储在文件中,这非常有用。