unixODBC编程(三)查询数据库表中的数据
连接数据库成功后,就可以对数据库进行操作了,我们先看一下怎样从数据库表中查询数据。查询数据在ODBC中也有几个步骤。
1. 分配一个语句句柄,使用SQLAllocHandle()函数,句柄类型为SQL_HANDLE_STMT。
2. 准备语句,使用SQLPrepare()函数。
3. 执行语句,使用SQLExecute()函数。
4. 绑定输出的变量,使用SQLBindCol()函数。
5. 循环取回结果集数据,使用SQLFetch()函数。
下面看看这几个函数的原型和参数。
准备语句函数。
SQLRETURN SQLPrepare(
SQLHSTMT StatementHandle,
SQLCHAR * StatementText,
SQLINTEGER TextLength);
StatementHandle是一个输入参数,语句句柄。
StatementText是一个输入参数,SQL文本字符串。
TextLength是一个输入参数,SQL文本字符串 StatementText 的长度。
执行语句函数。
SQLRETURN SQLExecute(
SQLHSTMT StatementHandle);
StatementHandle是一个输入参数,语句句柄。
绑定输出变量函数。
SQLRETURN SQLBindCol(
SQLHSTMT StatementHandle,
SQLUSMALLINT ColumnNumber,
SQLSMALLINT TargetType,
SQLPOINTER TargetValuePtr,
SQLLEN BufferLength,
SQLLEN * StrLen_or_IndPtr);
StatementHandle是一个输入参数,语句句柄。
ColumnNumber是一个输入参数,要绑定的结果集列的序号。列从 0 开始递增编号,其中列 0 是书签列。如果没有使用书签列,则列号从 1 开始。
TargetType是一个输入参数,是TargetValuePtr 缓冲区的 C 数据类型。
TargetValuePtr是一个输入/输出参数,指向要绑定到列的数据缓冲区的指针。
BufferLength是一个输入参数,TargetValuePtr 缓冲区的长度(以字节为单位)。
StrLen_or_IndPtr是一个输入/输出参数,指向要绑定到列的长度/指示器缓冲区的指针。
取回结果集中数据的函数。
SQLRETURN SQLFetch(
SQLHSTMT StatementHandle);
StatementHandle是一个输入参数,语句句柄。
现在来看一个例子,连接到数据库后,从user_table中查询表名,表空间名和表的状态。SQL语句为select table_name, tablespace_name, status from user_tables。
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "sql.h"
#include "sqlext.h"
#include "sqltypes.h"
SQLHANDLE envh; /* env handle */
SQLHANDLE dbch; /* connect handle */
SQLHANDLE stmth; /* statement handle */
int main(int argc, char *argv[])
{
int conn = 0;
SQLRETURN rc;
SQLLEN rlen1;
SQLLEN rlen2;
SQLLEN rlen3;
char dsn_str[32];
char usrname[32];
char passwd[32];
char table_name[256];
char ts_name[32];
char status[16];
/* 从命令行参数中输入数据源名称,数据库用户名和密码 */
if (argc < 3) {
fprintf(stderr, "usage: %s dsn username password\n", argv[0]);
return (-1);
}
strncpy(dsn_str, argv[1], 32);
dsn_str[31] = '\0';
strncpy(usrname, argv[2], 32);
usrname[31] = '\0';
strncpy(passwd, argv[3], 32);
passwd[31] = '\0';
/* 分配环境句柄 */
rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &envh);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Allocate environment handle error.\n");
return (-1);
}
/* 设置ODBC版本 */
rc = SQLSetEnvAttr(envh, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Set ODBC version error.\n");
goto free_exit;
}
/* 分配连接句柄 */
rc = SQLAllocHandle(SQL_HANDLE_DBC, envh, &dbch);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Allocate DB connection handle error.\n");
goto free_exit;
}
/* 设置连接超时时间 */
rc = SQLSetConnectAttr(dbch, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)10, 0);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Set connection timeout value error.\n");
goto free_exit;
}
/* 连接到数据库 */
rc = SQLConnect(dbch, (SQLCHAR *)dsn_str, SQL_NTS,
(SQLCHAR *)usrname, SQL_NTS, (SQLCHAR *)passwd, SQL_NTS);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Connect to DB error.\n");
goto free_exit;
}
/* 设置连接数据库成功的标志 */
conn = 1;
fprintf(stdout, "connect DB ok ......\n");
/* 分配语句句柄 */
rc = SQLAllocHandle(SQL_HANDLE_STMT, dbch, &stmth);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Allocate statment handle error.\n");
goto free_exit;
}
/* 准备SQL语句文本 */
rc = SQLPrepare(stmth,
(SQLCHAR *)"select table_name, tablespace_name, status from user_tables",
SQL_NTS);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Prepare statment error.\n");
goto free_exit;
}
/* 执行语句 */
rc = SQLExecute(stmth);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Execute statment error.\n");
goto free_exit;
}
/* 绑定第一列的输出变量,类型是C语言的char类型,rlen1是返回的数据长度 */
rc = SQLBindCol(stmth, 1, SQL_C_CHAR, (SQLCHAR *)table_name, 256, &rlen1);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Bind column 1 error.\n");
goto free_exit;
}
/* 绑定第二列输出变量 */
rc = SQLBindCol(stmth, 2, SQL_C_CHAR, (SQLCHAR *)ts_name, 32, &rlen2);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Bind column 2 error.\n");
goto free_exit;
}
/* 绑定第三列输出变量 */
rc = SQLBindCol(stmth, 3, SQL_C_CHAR, (SQLCHAR *)status, 16, &rlen3);
if (rc != SQL_SUCCESS) {
fprintf(stderr, "Bind column 3 error.\n");
goto free_exit;
}
while (1) {
/* 返回结果集数据 */
rc = SQLFetch(stmth);
if (rc == SQL_NO_DATA) {
/* 结果集中没有数据了,退出循环 */
break;
} else if (rc == SQL_ERROR) {
/* 出错,返回 */
fprintf(stderr, "Fetch data error.\n");
goto free_exit;
}
/* 打印返回的变量值 */
fprintf(stdout, "table_name=%s, tablespace_name=%s, status=%s\n",
table_name, ts_name, status);
}
/* 释放语句句柄 */
SQLFreeHandle(SQL_HANDLE_STMT, stmth);
/* 断开数据库连接 */
SQLDisconnect(dbch);
/* 释放连接句柄 */
SQLFreeHandle(SQL_HANDLE_DBC, dbch);
/* 释放环境句柄 */
SQLFreeHandle(SQL_HANDLE_ENV, envh);
return (0);
free_exit:
if (stmth != NULL) {
SQLFreeHandle(SQL_HANDLE_STMT, stmth);
}
if (conn) {
SQLDisconnect(dbch);
}
if (dbch != NULL) {
SQLFreeHandle(SQL_HANDLE_DBC, dbch);
}
if (envh != NULL) {
SQLFreeHandle(SQL_HANDLE_ENV, envh);
}
return (-1);
}
编译程序,需要包含unixODBC的include路径和连接库的路径,比如源文件叫odbc_test.c,编译命令如下。
cc -I$HOME/unixODBC/include -L$HOME/unixODBC/lib -lodbc odbc_test.c