参考:
环境:
- Windows 10 x64 1803
- MariaDB TX 10.2.14 x64
- MariaDB ODBC Connector 3.0.3 x64
- Visual Studio 2017 Community 15.6.7
安装ODBC驱动并配置数据源:
先安装ODBC驱动。根据自身需求选择32或64位版本。我选择了64位版本。
打开ODBC数据源管理程序,点击右侧的“添加”按钮,添加用户DSN。如图操作。
后面按照默认配置,点击Next即可。
编写ODBC程序:
1 引入头文件:
#include <iostream>
#include <windows.h>
#include <sqlext.h>
2 定义一个检查错误的宏:
#define ODBC_CHECK(x) \
{\
if (!SQL_SUCCEEDED(x))\
{\
std::cout << “SQL error occurred at line “ << LINE << “.“;\
getchar();\
exit(-1);\
}\
}
3 ODBC初始化,为ODBC分配环境句柄
(分配环境句柄:注意,这里使用了新版的ODBC API SQLAllocHandle**,而不是SQLAllocEnv**)
// SQL Handle of ENVironment
SQLHENV env;
ODBC_CHECK(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env)); // SQLAllocEnv
ODBC_CHECK(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0));
4 建立应用程序与ODBC数据源的连接
(分配连接句柄:注意,这里使用了新版的ODBC API SQLAllocHandle**,而不是SQLAllocConnect**)
// SQL Handle of DB Connection
SQLHDBC dbc;
SQLCHAR dbcConfOut[256];
ODBC_CHECK(SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc)); // SQLAllocConnect
ODBC_CHECK(SQLSetConnectAttr(dbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0));
(连接数据源:可以使用SQLConnect**,也可以使用SQLDriverConnect;可以手动指定DSN名字,也可以通过弹出窗口来指定)**
// specify manually
ODBC_CHECK(SQLDriverConnect(dbc, NULL, (SQLCHAR *)“DSN=MariaDB;“, SQL_NTS,
dbcConfOut, sizeof(dbcConfOut), NULL, SQL_DRIVER_COMPLETE)); // SQLConnect
// specify by popup window
//ODBC_CHECK(SQLDriverConnect(dbc, GetDesktopWindow(), NULL, SQL_NTS,
// dbcConfOut, sizeof(dbcConfOut), NULL, SQL_DRIVER_COMPLETE)); // SQLConnect
(显示连接成功的信息)
std::cout << “Connected!“ << std::endl
<< “ConnStrIn = “ << dbcConfOut << std::endl;
SQLCHAR dbmsName[256];
ODBC_CHECK(SQLGetInfo(dbc, SQL_DBMS_NAME, (SQLPOINTER)dbmsName, sizeof(dbmsName), NULL));
SQLCHAR dbmsVer[256];
ODBC_CHECK(SQLGetInfo(dbc, SQL_DBMS_VER, (SQLPOINTER)dbmsVer, sizeof(dbmsVer), NULL));
std::cout << “DBMS Name = “ << dbmsName << std::endl
<< “DBMS Version = “ << dbmsVer << std::endl;
(分配语句句柄:注意,这里使用了新版的ODBC API SQLAllocHandle**,而不是SQLAllocStmt**)
// SQL Handle of STateMenT
SQLHSTMT stmt;
ODBC_CHECK(SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt)); // SQLAllocStmt
5 利用SQLExecDirect语句,实现数据库应用程序对数据库的建立、查询、修改、删除等
(建立一个循环,一直接收并执行用户的SQL**的语句,直到用户退出)**
const int queryLen = 1024;
SQLCHAR query[queryLen];
std::cout << “Please input your SQL query. Type CTRL+Z to quit.“ << std::endl
<< dbmsName << “ >“;
while (fgets((char*)query, queryLen - 1, stdin))
{
if (query[0] == ‘\n‘)
{
std::cout << dbmsName << “ >“;
continue;
}
switch (SQLExecDirect(stmt, query, SQL_NTS))
{
case SQL_SUCCESS_WITH_INFO:
case SQL_SUCCESS:
{
SQLSMALLINT col;
SQLNumResultCols(stmt, &col);
// SELECT
if (col > 0)
{ // 2 methods: SQLGetData() and SQLBindCol()
// SQLGetData() is adopted here
char buf[512];
SQLUSMALLINT colidx;
// print column names
for (colidx = 1; colidx <= col; ++colidx)
{
SQLColAttribute(stmt, colidx, SQL_DESC_NAME,
buf, sizeof(buf), NULL, NULL);
std::cout << buf << “ “;
}
std::cout << std::endl;
// iterate each row
unsigned row = 0; // row counter
while (SQL_SUCCEEDED(SQLFetch(stmt)))
{
++row;
// iterate each column
for (colidx = 1; colidx <= col; ++colidx)
{
SQLLEN indicator;
if (SQL_SUCCEEDED(SQLGetData(stmt, colidx, SQL_C_CHAR,
buf, sizeof(buf), &indicator)))
{
if (indicator == SQL_NULL_DATA) strcpy(buf, “NULL“);
std::cout << buf << “ “;
}
}
std::cout << std::endl;
}
if (row == 1) { std::cout << “1 row in set.“ << std::endl; }
else { std::cout << row << “ rows in set.“ << std::endl; }
}
// CREATE, UPDATE, DELETE, etc.
else
{
SQLLEN row;
ODBC_CHECK(SQLRowCount(stmt, &row));
if (row == 1) { std::cout << “1 row affected.“ << std::endl; }
else { std::cout << row << “ rows affected.“ << std::endl; }
}
break;
}
case SQL_ERROR:
{
std::cout << “Returned SQL_ERROR.“ << std::endl;
break;
}
default:
{
std::cout << “Unknown SQLRETURN.“ << std::endl;
}
}
ODBC_CHECK(SQLFreeStmt(stmt, SQL_CLOSE));
std::cout << dbmsName << “ >“;
}
6 检索查询结果集
7 结束数据库应用程序
// release resources
ODBC_CHECK(SQLFreeHandle(SQL_HANDLE_STMT, stmt));
ODBC_CHECK(SQLDisconnect(dbc));
ODBC_CHECK(SQLFreeHandle(SQL_HANDLE_DBC, dbc));
ODBC_CHECK(SQLFreeHandle(SQL_HANDLE_ENV, env));
return 0;