执行SQL语句并处理结果
向数据库发出执行SQL的请求时,需要使用语句句柄,并调用SQLExecDirect或SQLExecute发出查询,服务端执行完成后查询的结果将保存在语句句柄中。
执行查询
直接执行
调用SQLAllocHandle()函数获取句柄,调用SQLExecDirect函数执行查询
HSTMT hstmt = SQL_NULL_HSTMT; //语句句柄
ret = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
if (!SQL_SUCCEEDED(ret))
{
printf("failed to allocate stmt handle");
return;
}
/*执行语句*/
ret = SQLExecDirect(hstmt, (SQLCHAR *) "select * from test", SQL_NTS);
/*获取结果*/
ret = SQLFetch(hstmt);
if (ret == SQL_NO_DATA)
return;
if (ret == SQL_SUCCESS)
{
char buf[40];
SQLLEN ind;
/*获取列数据*/
ret = SQLGetData(hstmt, 1, SQL_C_CHAR, buf, sizeof(buf), &ind);
}
预编译方式执行
调用SQLAllocHandle()函数获取句柄,使用SQLPrepare预编译语句,使用SQLBindParameter绑定参数,最后调用SQLExecute执行查询
/*初始化句柄*/
ret = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
if (!SQL_SUCCEEDED(ret))
{
printf("failed to allocate stmt handle");
exit(1);
}
/*预编译SQL*/
ret = SQLPrepare(hstmt, (SQLCHAR *) "SELECT * FROM testc WHERE c1 = ?", SQL_NTS);
CHECK_STMT_RESULT(ret, "SQLPrepare failed", hstmt);
SQLLEN cbParam1 = SQL_NTS;
/*绑定参数*/
ret = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, /* value type */
SQL_CHAR, /* param type */
20, /* column size */
0, /* dec digits */
"6", /* param value ptr */
0, /* buffer len */
&cbParam1 /* StrLen_or_IndPtr */);
CHECK_STMT_RESULT(ret, "SQLBindParameter failed", hstmt);
/*执行*/
ret = SQLExecute(hstmt);
CHECK_STMT_RESULT(ret, "SQLExecute failed", hstmt);
/*获取结果*/
/*获取结果*/
ret = SQLFetch(hstmt);
if (ret == SQL_NO_DATA)
return;
if (ret == SQL_SUCCESS)
{
char buf[40];
SQLLEN ind;
/*获取列数据*/
ret = SQLGetData(hstmt, 1, SQL_C_CHAR, buf, sizeof(buf), &ind);
}
使用游标获取结果
默认情况下,驱动程序将一次性获取查询的所有结果,当某个查询的结果集很庞大时,一次获取所有结果很不合理,因此ODBC驱动程序提供了一种基于数据库游标的结果集处理方法,只获取少量的行缓存在客户端。通过重新定位游标来获取下一批数据。
游标不能在所有情况下使用。有许多限制会使驱动程序一次性获取整个结果集:
连接不能使用自动提交模式因为后端会在事务结束时关闭游标,因此在自动提交模式下,事务结束后,在从游标获取数据之前,游标已经被关闭。
UseDeclareFetch参数设置为true,默认缓存100行数据,为false时将不会使用游标,直接获取整个结果集。
给定的查询语句必须是单条语句,不能是用分号连接在一起的多个语句。
设置fetch size,且fetch size不能为0.
示例:
int rc;
int i;
/*关闭自动提交*/
rc = SQLSetConnectAttr(conn, SQL_AUTOCOMMIT, (SQLPOINTER) SQL_AUTOCOMMIT_OFF, 0);
CHECK_CONN_RESULT(rc, "SQL_AUTOCOMMIT off failed", conn);
/*执行SQL*/
rc = SQLExecDirect(hstmt, (SQLCHAR *) "SELECT 'foo' || g FROM generate_series(1, 3210) g", SQL_NTS);
CHECK_STMT_RESULT(rc, "SQLExecDirect failed", hstmt);
/*获取结果*/
for (;; i++)
{
char buf[40];
SQLLEN ind;
rc = SQLFetch(hstmt);
if (rc == SQL_NO_DATA)
break;
if (rc != SQL_SUCCESS)
{
char sqlstate[32] = "";
SQLINTEGER nativeerror;
SQLSMALLINT textlen;
SQLGetDiagRec(SQL_HANDLE_STMT, hstmt, 1, sqlstate, &nativeerror,
NULL, 0, &textlen);
/*在读取游标的过程中,如果调用用SQLEndTran提交或回滚了事务,游标将被关闭*/
if (strcmp(sqlstate, "HY010") == 0)
{
printf("SQLFetch failed with HY010 (which probably means that the cursor was closed at commit/rollback)");
break;
}
else
CHECK_STMT_RESULT(rc, "SQLGetDiagRec failed", hstmt);
}
rc = SQLGetData(hstmt, 1, SQL_C_CHAR, buf, sizeof(buf), &ind);
CHECK_STMT_RESULT(rc, "SQLGetData failed", hstmt);
}
执行更新
要更改数据(执行一个insert,update或者delete),可以使用SQLExecDirect函数执行完整的SQL,也可以使用预编译的方式绑定参数后再执行。下面的示例将以预编译的方式执行。
删除
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
rc = SQLPrepare(hstmt, (SQLCHAR *) "delete from tmptable where c2 = ? ", SQL_NTS);
cbParam1 = SQL_NTS;
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, /* value type */
SQL_CHAR, /* param type */
20, /* column size */
0, /* dec digits */
“testvalue”, /* param value ptr */
0, /* buffer len */
&cbParam1 /* StrLen_or_IndPtr */);
CHECK_STMT_RESULT(rc, "SQLBindParameter failed", hstmt);
rc = SQLExecute(hstmt);
CHECK_STMT_RESULT(rc, "SQLExecute failed", hstmt);
更新
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
rc = SQLPrepare(hstmt, (SQLCHAR *) "update tmptable set c1 = c1+1 where c2 = ? ", SQL_NTS);
cbParam1 = SQL_NTS;
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, /* value type */
SQL_CHAR, /* param type */
20, /* column size */
0, /* dec digits */
“testvalue”, /* param value ptr */
0, /* buffer len */
&cbParam1 /* StrLen_or_IndPtr */);
CHECK_STMT_RESULT(rc, "SQLBindParameter failed", hstmt);
rc = SQLExecute(hstmt);
CHECK_STMT_RESULT(rc, "SQLExecute failed", hstmt);
插入
rc = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
rc = SQLPrepare(hstmt, (SQLCHAR *) "INSERT INTO tmptable VALUES (1, ?) ", SQL_NTS);
cbParam1 = SQL_NTS;
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT,
SQL_C_CHAR, /* value type */
SQL_CHAR, /* param type */
20, /* column size */
0, /* dec digits */
“testvalue”, /* param value ptr */
0, /* buffer len */
&cbParam1 /* StrLen_or_IndPtr */);
CHECK_STMT_RESULT(rc, "SQLBindParameter failed", hstmt);
rc = SQLExecute(hstmt);
CHECK_STMT_RESULT(rc, "SQLExecute failed", hstmt);
创建或修改数据库对象
要创建、更改或者删除一个类似表或者视图这样的数据库对象, 可以调用SQLExecDirect() 方法.
例如创建表:
HSTMT hstmt = SQL_NULL_HSTMT; //语句句柄
ret = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);
if (!SQL_SUCCEEDED(ret))
{
printf("failed to allocate stmt handle");
return;
}
ret = SQLExecDirect(hstmt, (SQLCHAR *) "create table test(c1 int,c2 int)", SQL_NTS);