注册 登录
编程论坛 C++教室

c++连接达梦数据库写入乱码(求能正常读写中文的代码)

AZhengYe 发布于 2023-09-06 17:20, 826 次点击
#include<iostream>
#include<Windows.h>
#include<sql.h>
#include<sqltypes.h>
#include<sqlext.h>
using  namespace std;
#define RC_SUCCESSFUL(rc) ((rc) == SQL_SUCCESS || (rc) == SQL_SUCCESS_WITH_INFO)// #define SQL_SUCCEEDED(rc)  (((rc)&(~1))==0)
#define RC_NOTSUCCESSFUL(rc) (!(RC_SUCCESSFUL(rc)))

SQLHENV henv;/* 环境句柄 */
SQLHDBC hdbc;/* 连接句柄 */
SQLHDBC hstmt;/* 语句句柄 */
SQLRETURN sret; /* 返回代码 */
void getError(SQLHDBC hhandle, SQLSMALLINT TYPE);

int main()
{
    /* 申请一个环境句柄 */
    sret = SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv);
    /* 设置环境句柄的 ODBC 版本 */
    sret = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,
        SQL_IS_INTEGER);
    /* 申请一个连接句柄 */
    sret = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
    sret = SQLConnectW(hdbc, (SQLWCHAR*)L"DM8", SQL_NTS, (SQLWCHAR*)L"TEST", SQL_NTS, (SQLWCHAR*)L"123456", SQL_NTS);
   
    if (RC_NOTSUCCESSFUL(sret)) {
        getError(hdbc, SQL_HANDLE_DBC);
        return 0;
    }
    //申请SQL语句
    SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

    //SQL语句存放
    wchar_t sql[1024];
   
    //书写SQL语句
    //const char* s = "CREATE TABLESPACE \"TEST\" DATAFILE 'TEST.DBF' SIZE 128";
    //const char* s = "insert into TEST.TESTUSER(NAME,SOURCE) values('刘煜成',3);";
    SQLCHAR s1[] = "insert into TEST.TESTUSER(NAME,SOURCE) values('刘煜成',4);";

    //SQL语句存入sql
    swprintf(sql, 1024, L"%hs", s1);

    //执行
    sret = SQLExecDirect(hstmt, sql, sizeof(sql) / 2);

    if (RC_NOTSUCCESSFUL(sret)) {
        getError(hstmt, SQL_HANDLE_STMT);
        return 0;
    }
   
    SQLCHAR s2[] = "select * from TEST.TESTUSER where ID = 2;";
    // SQL语句存入sql
    swprintf(sql, 1024, L"%hs", s2);

    // 执行
    sret = SQLExecDirect(hstmt, sql, sizeof(sql) / 2);

    if (RC_NOTSUCCESSFUL(sret)) {
        getError(hstmt, SQL_HANDLE_STMT);
        return 0;
    }
    SQLCHAR NAME[20], SOURCE[20];
    SQLLEN NAME_LEN, SOURCE_LEN;
   
    SQLGetData(hstmt, 0, SQL_C_CHAR, NAME, 20, &NAME_LEN);
    SQLGetData(hstmt, 1, SQL_C_CHAR, SOURCE, 20, &SOURCE_LEN);

    cout << NAME << endl;
    cout << NAME_LEN << endl;
    cout << SOURCE << endl;
    cout << SOURCE_LEN << endl;


    /* 释放语句句柄 */
    SQLFreeHandle(SQL_HANDLE_DBC, hstmt);
    /* 释放连接句柄 */
    SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
    /* 释放环境句柄 */
    SQLFreeHandle(SQL_HANDLE_ENV, henv);

    return 0;
}

void getError(SQLHDBC hhandle, SQLSMALLINT TYPE)
{
    /* 连接数据源失败! */
    SQLINTEGER   NumRecords = 0;
    SQLGetDiagField(TYPE,
        hhandle,
        0,
        SQL_DIAG_NUMBER,
        &NumRecords,
        SQL_IS_INTEGER,
        NULL);
    printf("Total Number of diagnostic records: %d\n", NumRecords);

    SQLSMALLINT   Counter = 0;
    SQLINTEGER     NativeErr = 0;
    SQLWCHAR      SQLState[6];
    SQLWCHAR      ErrMsg[512];
    SQLSMALLINT  ErrMsgLen = 0;
    for (Counter = 1; Counter <= NumRecords; Counter++)
    {
        SQLGetDiagRec(TYPE,
            hhandle,
            Counter,
            SQLState,
            &NativeErr,
            ErrMsg,
            sizeof(ErrMsg) / 2,
            &ErrMsgLen);
        printf("SQLSTATE : %ls\n", SQLState);
        printf("%ls\n", ErrMsg);
    }
}
4 回复
#2
rjsp2023-09-07 10:03
swprintf(sql, 1024, L"%hs", s1);
你想用它进行编码转换?

sret = SQLExecDirect(hstmt, sql, sizeof(sql) / 2);
函数是想要字符串的长度,还是存储区的长度?
#3
AZhengYe2023-09-07 13:27
回复 2楼 rjsp
swprintf(sql, 1024, L"%hs", s1);
这是把s1放入sql,为什么要把s1放入sql原因如下。

sret = SQLExecDirect(hstmt, sql, sizeof(sql) / 2);
这里SQLExecDirect(hstmt, s1, sizeof(sql) / 2)会报错,需要把s1(SQLCHAR类型)换成sql(wchar_t类型)
#4
rjsp2023-09-07 14:13
我的意思是,你用 swprintf 进行编码转换是 异想天开,char* 转 wchar_t* 得用 MultiByteToWideChar 才行。

说得更直白点:
把 swprintf(sql, 1024, L"%hs", s1); 删除
把 sret = SQLExecDirect(hstmt, sql, sizeof(sql) / 2); 改为 sret = SQLExecDirectA(hstmt, s1, strlen((const char*)s1) );
试试,后面的代码也这么该
#5
AZhengYe2023-09-07 23:06
回复 4楼 rjsp
感谢
1