ODBC介绍与API使用
文章目录
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、ODBC概述
开放式数据库连接 (ODBC) 是一种广泛接受的应用程序编程接口 (API),适用于数据库访问,使用 结构化查询语言 (SQL) 作为其数据库访问语言。ODBC可用于多种常见数据库的连接,其中,主要用于SQL Server。
二、基础知识与官网
本部分主要包括:句柄
,缓冲区
,ODBC中的数据类型
,一致性级别
。
2.1 句柄
句柄
是不透明的 32 位值,用于标识特定项;在 ODBC 中,此项可以是环境、连接、语句或描述符。应用程序调用SQLAllocHandle申请相关类型的句柄。
环境句柄:环境是访问数据的全局上下文;与环境关联的是具有全局性质的信息,如:环境的状态,当前环境级的诊断信息,当前环境中分配的连接句柄,每个环境设置的当前属性。
连接句柄:连接句柄标识每个连接。 连接句柄不仅定义要使用的驱动程序,还定义用于该驱动程序的数据源。包含的信息有:连接的状态,当前连接级别诊断,当前在连接上分配的语句和描述符的句柄,每个连接属性的当前设置。连接到数据源时,主要使用连接句柄 (SQLConnect, SQLDriverConnect 或 SQLBrowseConnect) ,从数据源断开连接 (SQLDisconnect) , (SQLGetInfo) 获取有关驱动程序和数据源的信息, (SQLGetDiagField 和 SQLGetDiagRec) 检索诊断,以及 (SQLEndTran) 执行事务。 在 (SQLSetConnectAttr 和 SQLGetConnectAttr) 设置和获取连接属性时,以及获取 SQL 语句的本机格式 (SQLNativeSql) 时,也使用它们。
语句句柄:语句最容易被视为 SQL 语句,例如 SELECT * FROM Employee。 但是,语句不仅仅是一个 SQL 语句 ,它包含与该 SQL 语句关联的所有信息,例如语句创建的结果集以及语句执行中使用的参数。 语句甚至不需要具有应用程序定义的 SQL 语句。 每个语句由语句句柄标识。 语句与单个连接相关联,并且该连接上可以有多个 语句。 某些驱动程序会限制它们支持的活动语句的数量; SQLGetInfo 中的 SQL_MAX_CONCURRENT_ACTIVITIES 选项指定驱动程序在单个连接上支持的活动语句数。 如果语句具有挂起的结果,其中结果为结果集或受 INSERT、UPDATE 或 DELETE 语句影响的行计数,或者通过多次调用 SQLPutData 发送数据,则会将其定义为活动语句。包含的信息有:语句的状态,当前语句级诊断,绑定到语句的参数和结果集列的应用程序变量的地址,每个语句属性的当前设置。它们在函数中用于将参数和结果集列绑定 (SQLBindParameter 和 SQLBindCol) , 准备并执行 sqlPrepare、 SQLExecute 和 SQLExecDirect) (语句、 (SQLColAttribute 和 SQLDescribeCol) 检索元数据、 (SQLFetch) 提取结果,以及 (SQLGetDiagField 和 SQLGetDiagRec) 检索诊断。 它们还用于目录函数 (SQLColumns、 SQLTables 等) 和许多其他函数。
描述符句柄:描述符是描述 SQL 语句的参数或结果集列的
元数据
集合。描述符可以填充以下四个角色中的任何一个:
(1)应用程序参数描述符 (APD) 。 包含有关绑定到 SQL 语句中参数的应用程序缓冲区的信息,例如其地址、长度和 C 数据类型。
(2)实现参数描述符 (IPD) 。 包含有关 SQL 语句中参数的信息,例如其 SQL 数据类型、长度和可为 null 性。
(3)应用程序行描述符 (ARD) 。 包含有关绑定到结果集中列的应用程序缓冲区的信息,例如其地址、长度和 C 数据类型。
(4)实现 IRD) (行描述符。 包含有关结果集中列的信息,例如其 SQL 数据类型、长度和可为 null 性。
分配语句时,会自动分配四个描述符 (一个填充每个角色) 。 这些描述符称为 自动分配的描述符 ,始终与该语句相关联。 应用程序还可以使用 SQLAllocHandle 分配描述符。 这些描述符称为 显式分配的描述符。 它们在连接上分配,并且可以与该连接上的一个或多个语句相关联,以在这些语句上履行 APD 或 ARD 的角色。
ODBC 中的大多数操作无需应用程序显式使用描述符即可执行。但是,描述符为某些操作提供了便捷的快捷方式。 例如,假设应用程序想要插入两个不同缓冲区集的数据。 若要使用第一组缓冲区,它将重复调用 SQLBindParameter 以将它们绑定到 INSERT 语句中的参数,然后执行语句。 若要使用第二组缓冲区,它将重复此过程。 或者,它可以设置到一个描述符中的第一组缓冲区和另一个描述符中的第二组缓冲区的绑定。 若要在绑定集之间切换,应用程序只需调用 SQLSetStmtAttr 并将正确的描述符与作为 APD 的语句相关联。
2.2 缓冲区
2.2.1 概念
缓冲区是用于在应用程序和驱动程序之间传递数据的所有应用程序内存片段。
数据缓冲区及其包含的数据的长度以字节为单位,而不是字符。 这种区别对于使用 ANSI 字符串的程序并不重要,因为字节和字符的长度相同。
应用程序通过在将字段或属性设置为以下值之一的任何函数调用中设置 length 参数来执行此操作。
- 如果指示字段或属性值的函数参数是指向字符串的指针,则 length 参数是字符串或SQL_NTS的长度。
- 如果指示字段或属性值的函数参数是指向二进制缓冲区的指针,则应用程序会将SQL_LEN_BINARY_ATTR (长度 的结果) 宏置于 length 参数中。 这会在 length 参数中放置一个负值。
- 如果指示字段或属性值的函数参数是指向字符串或二进制字符串以外的值的指针,则 length 参数的值应SQL_IS_POINTER。
- 如果指示字段或属性值的函数参数包含固定长度值,则 长度 参数是SQL_IS_INTEGER、SQL_IS_UINTEGER、SQL_IS_SMALLINT或SQL_ISI_USMALLINT(视情况而定)。
2.2.1 延迟的缓冲区
延迟缓冲区是在函数调用中指定值的某个时间使用的缓冲区。 例如, SQLBindParameter 用于将数据缓冲区与 SQL 语句中的参数相关联或 绑定 。应用程序指定参数的编号,并传递缓冲区的地址、字节长度和类型。 驱动程序保存此信息,但不检查缓冲区的内容。 稍后,当应用程序执行 语句时,驱动程序会检索信息并使用它来检索参数数据并将其发送到数据源。
2.3 ODBC 中的数据类型
ODBC 使用两组数据类型:SQL 数据类型
和 C 数据类型
。 SQL 数据类型用于数据源,C 数据类型用于应用程序中的 C 代码。还有一种我们程序中不会用到的ODBC定义的数据类型。
SQLCHAR:ODBC定义的数据类型
SOL_C_CHAR:C语言的数据类型编码
SQL_CHAR:SQL数据类型编码
2.3.1 ODBC定义的数据类型
如SQLCHAR,SQL开头,后面跟着一系列大写字符,但是没有下划线。这种数据类型定义在sqltypes.h中。这种数据类型可以用来定义变量,ODBC API的变量类型都是这种类型。这样做的好处是ODBC提供了一套自己的变量类型,相当于封装了一层,使用者不用关心底层具体的变量类型实现细节。即使底层的变量类型做了修改,使用者的代码也不用做任何改动。这种数据类型和C语言数据类型的映射如下:
2.3.2 ODBC中的C数据类型
如SQL_C_CHAR,他们并不是真正的数据类型,而是针对上面提到的的ODBC定义的数据类型的编码,所以不能用来定义变量。他们可以用作ODBC API的参数。这种数据类型定义在sqlext.h中,比如:
这种数据类型和ODBC数据类型的映射如下:
2.3.3 ODBC中的SQL数据类型
如SQL_CHAR,第三种是SQL数据类型编码。同第二种一样,他们也不是真正的数据类型,而是提供SQL数据类型和编程语言数据类型的关联,因为也是数字编码,所以也不能用来定义变量。他们可以用作ODBC API的参数。这种数据类型定义在sqlext.h中。这种数据类型和SQL数据类型的映射如下:
2.4 一致性级别
为了帮助应用程序发现驱动程序和数据源功能,提供了两个符合性方面:ODBC 接口和 SQL 语法。详细参见官网说明。
2.5 常用链接
三、ODBC API参考
详细API说明请参见官网手册,此处仅以C语言为例,按字母顺序记录在使用过程中遇到的问题及解决方法。
3.1 常用接口可能遇到的问题及解决(持续新增并补充。。。)
3.1.1 SQLBindParameter & SQLPutData
功能:参数绑定。
注意:任何参数传入错误都可能影响绑定的结果。即使返回绑定成功,也可能影响后续操作。此处以大字段的绑定为例,在注释中说明注意事项。
错误:
(1)可能返回“驱动越界”错误:传入的C类型参数有误:SQL_C_。
(2)返回HY010函数序列错误:API调用的顺序有误。
SQLCHAR b[5000], *b = &b[0]; /* The blob to be sent */
int i; /* Loop counter */
SQLINTEGER len; /* Segment length */
RETCODE rc = SQL_SUCCESS; /* Return code */
SQLPOINTER pToken = NULL; /* Column indicator */
SQLHSTMT hstmt; /* Statement handle */
/*
** Fill the blob buffer with test data.
*/
for ( i = 0; i < 5000; i++ )
b[i] = 'x ';
/*
** Bind the blob, indicating that the length will be provided at untime.
*/
SQLBindParameter(hstmt, /* Statement handle */
1, /* Column number,start from 1 */
SQL_PARAM_INPUT, /* This is an input parameter */
SQL_C_CHAR, /* Parameter is a string */
SQL_LONGVARBINARY, /* Destination type is long varchar */
0, /* No length required */
0, /* No precision required */
(PTR)1, /* Long parameter number 1, 此处可以传入一个地址,如:申请一个句柄lob_hstmt用于大字段的存放,后面将从该句柄取数据,则此处可填:&lob_hstmt */
0, /* No max length required */
&len ); /* Variable blob length,此处的len值需为一个不为0的数,若为0则后续取到的数据长度为0。此处使用的值可能为一个传入的参数,为确保该值不为0,可以使用:len = SQL_LEN_DATA_AT_EXEC( len );提前对值进行处理 */
/*
** This macro definition tells the ODBC when to expect the end of
** data for the blob.
*/
len = SQL_LEN_DATA_AT_EXEC( 5000 ); // 不确定长度可以不用这句
/*
** Execute the insert query.
*/
rc = SQLExecDirect( hstmt,
"insert into longv values ( ? )", SQL_NTS );
/*
** Loop, sending the data in segments of 1000.
*/
while ( rc == SQL_NEED_DATA )
{
/*
** Check for EOD marker.
*/
rc = SQLParamData( hstmt, pToken );
if ( rc == SQL_NEED_DATA )
{
/*
** If more data to send, send it.
*/
if ( pToken == 1 )
{
SQLPutData( hstmt, blob, 1000 );
blob += 1000;
}
}
}
rc = SQLParamData( hstmt, pToken ); // 使用SQLPutData()要注意API调用顺序:1.exec并返回NEED_DATA; 2.SQLParamData并返回NEED_DATA; 3.SQLPutData; 4.SQLParamData并返回SUCCESS; 5.提交。
3.1.2 SQLRowCount
功能:SQLRowCount 返回受 UPDATE、 INSERT 或 DELETE 语句影响的行数。
注意:可能会返回一个错误的影响行数(如一个非常大的值)。在调用该函数前使用SQLSetStmtAttr设置参数属性SQL_ATTR_PARAMSET_SIZE后可获取到正确的影响行数。