ODBC SQLBindCol 绑定 ODBC 浮点类型以返回为 std::string
我正在存储一个数据库记录,其中包含与 SQL 查询一起存储的浮点字段,
create table test_table_3 (a float, b varchar(10));
insert into test_table_3 VALUES (1.4, 'foo');
我想定义一个函数,该函数将记录的值返回为 std::string。
附加程序执行此操作,但返回字符串值为“1.39999”。有没有办法将 ODBC API 设置为返回与插入的值相同的值(“1.4”)。 (这只是因为需要在将输入与输出值匹配的测试中使用代码)
我正在使用 SQLBindCol ODBC 函数,用于将程序中的“TargetType”参数(C 数据类型的标识符)定义为
bind_data[idx].target_type = SQL_C_CHAR;
完整的程序是:
#ifdef _MSC_VER
#include <windows.h>
#endif
#include <sql.h>
#include <sqlext.h>
#include <string>
#include <iostream>
struct bind_column_data_t
{
SQLSMALLINT target_type; //the C data type of the result data
SQLPOINTER target_value_ptr; //pointer to storage for the data
SQLINTEGER buf_len; //maximum length of the buffer being bound for data (including null-termination byte for char)
SQLLEN strlen_or_ind; //number of bytes(excluding the null termination byte for character data) available
//to return in the buffer prior to calling SQLFetch
};
const std::string conn("Driver={SQL Server};Server=localhost;Database=test_db;");
int exec_direct(SQLHSTMT hstmt, const std::string& sql);
int fetch(SQLHSTMT hstmt, const std::string& sql);
/////////////////////////////////////////////////////////////////////////////////////////////////////
//main
/////////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
SQLHENV henv = SQL_NULL_HENV; //environment
SQLHDBC hdbc = SQL_NULL_HDBC; //connection handle
SQLHSTMT hstmt = SQL_NULL_HSTMT; //statement handle
std::string sql1 = "drop table if exists test_table_3;";
std::string sql2 = "create table test_table_3 (a float, b varchar(10));";
std::string sql3 = "insert into test_table_3 VALUES (1.4, 'foo');";
std::string sql4 = "select * from[test_table_3];";
if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv)))
{
}
if (!SQL_SUCCEEDED(SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0)))
{
}
if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc)))
{
}
if (!SQL_SUCCEEDED(SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)TRUE, 0)))
{
}
if (!SQL_SUCCEEDED(SQLDriverConnect(hdbc, NULL, (SQLCHAR*)conn.c_str(), SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE)))
{
return -1;
}
if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt)))
{
}
exec_direct(hstmt, sql1);
exec_direct(hstmt, sql2);
exec_direct(hstmt, sql3);
fetch(hstmt, sql4);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
return 0;
}
int exec_direct(SQLHSTMT hstmt, const std::string& sql)
{
if (!SQL_SUCCEEDED(SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), SQL_NTS)))
{
return -1;
}
return 0;
}
int fetch(SQLHSTMT hstmt, const std::string& sql)
{
SQLSMALLINT nbr_cols;
SQLCHAR* sqlstr = (SQLCHAR*)sql.c_str();
struct bind_column_data_t* bind_data = NULL;
if (!SQL_SUCCEEDED(SQLExecDirect(hstmt, sqlstr, SQL_NTS)))
{
return -1;
}
if (!SQL_SUCCEEDED(SQLNumResultCols(hstmt, &nbr_cols)))
{
}
bind_data = (bind_column_data_t*)malloc(nbr_cols * sizeof(bind_column_data_t));
for (SQLUSMALLINT idx = 0; idx < nbr_cols; idx++)
{
bind_data[idx].target_value_ptr = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//get column names
/////////////////////////////////////////////////////////////////////////////////////////////////////
for (SQLUSMALLINT idx = 0; idx < nbr_cols; idx++)
{
SQLCHAR buf[1024];
SQLSMALLINT sqltype = 0;
SQLSMALLINT scale = 0;
SQLSMALLINT nullable = 0;
SQLSMALLINT len = 0;
SQLULEN sqlsize = 0;
if (!SQL_SUCCEEDED(SQLDescribeCol(
hstmt,
idx + 1,
(SQLCHAR*)buf, //column name
sizeof(buf) / sizeof(SQLCHAR),
&len,
&sqltype,
&sqlsize,
&scale,
&nullable)))
{
}
}
for (SQLUSMALLINT idx = 0; idx < nbr_cols; idx++)
{
bind_data[idx].target_type = SQL_C_CHAR;
bind_data[idx].buf_len = (1024 + 1);
bind_data[idx].target_value_ptr = malloc(sizeof(unsigned char) * bind_data[idx].buf_len);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//SQLBindCol assigns the storage and data type for a column in a result set,
//including:
//a storage buffer that will receive the contents of a column of data
//the length of the storage buffer
//a storage location that will receive the actual length of the column of data
//returned by the fetch operation data type conversion
/////////////////////////////////////////////////////////////////////////////////////////////////////
for (SQLUSMALLINT idx = 0; idx < nbr_cols; idx++)
{
if (!SQL_SUCCEEDED(SQLBindCol(
hstmt,
idx + 1,
bind_data[idx].target_type,
bind_data[idx].target_value_ptr,
bind_data[idx].buf_len,
&(bind_data[idx].strlen_or_ind))))
{
}
}
size_t nbr_rows = 0;
while (SQL_SUCCEEDED(SQLFetch(hstmt)))
{
for (int idx_col = 0; idx_col < nbr_cols; idx_col++)
{
std::string str;
if (bind_data[idx_col].strlen_or_ind != SQL_NULL_DATA)
{
str = (char*)bind_data[idx_col].target_value_ptr;
}
else
{
str = "NULL";
}
std::cout << str << " ";
}
std::cout << "\n";
nbr_rows++;
}
for (SQLUSMALLINT idx_col = 0; idx_col < nbr_cols; idx_col++)
{
if (bind_data[idx_col].target_value_ptr != NULL)
{
free(bind_data[idx_col].target_value_ptr);
}
}
if (bind_data != NULL)
{
free(bind_data);
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return 0;
}
输出是:
1.3999999999999999 foo
I am storing a database record with a float field stored with the SQL queries
create table test_table_3 (a float, b varchar(10));
insert into test_table_3 VALUES (1.4, 'foo');
I want to define a function that returns the values of the records as std::string.
The attached program does that, but the return value as string is "1.39999". Would there be a way to set the ODBC API to return the same value as inserted ("1.4"). (This is just because the code needs to be used in a test that matches input with output values)
I am using SQLBindCol ODBC function to define the "TargetType" parameter (identifier of the C data type) in the program as
bind_data[idx].target_type = SQL_C_CHAR;
Complete program is:
#ifdef _MSC_VER
#include <windows.h>
#endif
#include <sql.h>
#include <sqlext.h>
#include <string>
#include <iostream>
struct bind_column_data_t
{
SQLSMALLINT target_type; //the C data type of the result data
SQLPOINTER target_value_ptr; //pointer to storage for the data
SQLINTEGER buf_len; //maximum length of the buffer being bound for data (including null-termination byte for char)
SQLLEN strlen_or_ind; //number of bytes(excluding the null termination byte for character data) available
//to return in the buffer prior to calling SQLFetch
};
const std::string conn("Driver={SQL Server};Server=localhost;Database=test_db;");
int exec_direct(SQLHSTMT hstmt, const std::string& sql);
int fetch(SQLHSTMT hstmt, const std::string& sql);
/////////////////////////////////////////////////////////////////////////////////////////////////////
//main
/////////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
SQLHENV henv = SQL_NULL_HENV; //environment
SQLHDBC hdbc = SQL_NULL_HDBC; //connection handle
SQLHSTMT hstmt = SQL_NULL_HSTMT; //statement handle
std::string sql1 = "drop table if exists test_table_3;";
std::string sql2 = "create table test_table_3 (a float, b varchar(10));";
std::string sql3 = "insert into test_table_3 VALUES (1.4, 'foo');";
std::string sql4 = "select * from[test_table_3];";
if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv)))
{
}
if (!SQL_SUCCEEDED(SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0)))
{
}
if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc)))
{
}
if (!SQL_SUCCEEDED(SQLSetConnectAttr(hdbc, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)TRUE, 0)))
{
}
if (!SQL_SUCCEEDED(SQLDriverConnect(hdbc, NULL, (SQLCHAR*)conn.c_str(), SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE)))
{
return -1;
}
if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt)))
{
}
exec_direct(hstmt, sql1);
exec_direct(hstmt, sql2);
exec_direct(hstmt, sql3);
fetch(hstmt, sql4);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return 0;
return 0;
}
int exec_direct(SQLHSTMT hstmt, const std::string& sql)
{
if (!SQL_SUCCEEDED(SQLExecDirect(hstmt, (SQLCHAR*)sql.c_str(), SQL_NTS)))
{
return -1;
}
return 0;
}
int fetch(SQLHSTMT hstmt, const std::string& sql)
{
SQLSMALLINT nbr_cols;
SQLCHAR* sqlstr = (SQLCHAR*)sql.c_str();
struct bind_column_data_t* bind_data = NULL;
if (!SQL_SUCCEEDED(SQLExecDirect(hstmt, sqlstr, SQL_NTS)))
{
return -1;
}
if (!SQL_SUCCEEDED(SQLNumResultCols(hstmt, &nbr_cols)))
{
}
bind_data = (bind_column_data_t*)malloc(nbr_cols * sizeof(bind_column_data_t));
for (SQLUSMALLINT idx = 0; idx < nbr_cols; idx++)
{
bind_data[idx].target_value_ptr = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//get column names
/////////////////////////////////////////////////////////////////////////////////////////////////////
for (SQLUSMALLINT idx = 0; idx < nbr_cols; idx++)
{
SQLCHAR buf[1024];
SQLSMALLINT sqltype = 0;
SQLSMALLINT scale = 0;
SQLSMALLINT nullable = 0;
SQLSMALLINT len = 0;
SQLULEN sqlsize = 0;
if (!SQL_SUCCEEDED(SQLDescribeCol(
hstmt,
idx + 1,
(SQLCHAR*)buf, //column name
sizeof(buf) / sizeof(SQLCHAR),
&len,
&sqltype,
&sqlsize,
&scale,
&nullable)))
{
}
}
for (SQLUSMALLINT idx = 0; idx < nbr_cols; idx++)
{
bind_data[idx].target_type = SQL_C_CHAR;
bind_data[idx].buf_len = (1024 + 1);
bind_data[idx].target_value_ptr = malloc(sizeof(unsigned char) * bind_data[idx].buf_len);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
//SQLBindCol assigns the storage and data type for a column in a result set,
//including:
//a storage buffer that will receive the contents of a column of data
//the length of the storage buffer
//a storage location that will receive the actual length of the column of data
//returned by the fetch operation data type conversion
/////////////////////////////////////////////////////////////////////////////////////////////////////
for (SQLUSMALLINT idx = 0; idx < nbr_cols; idx++)
{
if (!SQL_SUCCEEDED(SQLBindCol(
hstmt,
idx + 1,
bind_data[idx].target_type,
bind_data[idx].target_value_ptr,
bind_data[idx].buf_len,
&(bind_data[idx].strlen_or_ind))))
{
}
}
size_t nbr_rows = 0;
while (SQL_SUCCEEDED(SQLFetch(hstmt)))
{
for (int idx_col = 0; idx_col < nbr_cols; idx_col++)
{
std::string str;
if (bind_data[idx_col].strlen_or_ind != SQL_NULL_DATA)
{
str = (char*)bind_data[idx_col].target_value_ptr;
}
else
{
str = "NULL";
}
std::cout << str << " ";
}
std::cout << "\n";
nbr_rows++;
}
for (SQLUSMALLINT idx_col = 0; idx_col < nbr_cols; idx_col++)
{
if (bind_data[idx_col].target_value_ptr != NULL)
{
free(bind_data[idx_col].target_value_ptr);
}
}
if (bind_data != NULL)
{
free(bind_data);
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return 0;
}
Output is :
1.3999999999999999 foo
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
因为这是针对 MS SQL Server 的,所以可以使用 STR 函数,长度为3个字符,精度为1,精确匹配字符串“1.4”
输出
Because this is for MS SQL Server, it's possible to use the STR function with a length of 3 characters and precision of 1, to match exactly the string "1.4"
Output