首页 > 其他分享 >odbc客户端添加错误检查

odbc客户端添加错误检查

时间:2024-01-24 23:01:47浏览次数:49  
标签:res 句柄 odbc 添加 SQLError SQL OK NULL 客户端

在本节中,我将添加一些简单的错误处理函数,并向您展示如何正确释放您创建的句柄资源。为了使您的 ODBC 编程更轻松一些,您可以使用以下函数来检查成功或失败:

static bool SQL_OK(SQLRETURN result){
	if(result==SQL_SUCCESS || result==SQL_SUCCESS_WITH_INFO)
		return(TRUE);
	else
		return(FALSE);
}

SQL_OK() 的典型调用可能如下所示:

if( SQL_OK( SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handle ))
{
	...
}

那么SQL_SUCCESSSQL_SUCCESS_WITH_INFO之间有什么区别?简单的答案是SQL_SUCCESS意味着函数成功;

SQL_SUCCESS_WITH_INFO也意味着函数成功,但有更多信息可用。例如,如果您尝试 REVOKE 用户的权限,但该用户一开始就没有该权

限,您将得到SQL_SUCCESS_WITH_INFO结果。请求已成功完成,但您可能想了解额外的信息。

在 ODBC 2.x 应用程序中,您可以调用 SQLError() 来检索任何扩展返回信息。如果在收到SQL_SUCCESS结果后调用SQLError(),则SQLError()函数将失败。以下是SQLError()函数的函数原型:

SQLRETURN SQLError(
    SQLHENV       envHandle,
    SQLHDBC       conHandle,
    SQLHSTMT      stmtHandle,
    SQLCHAR      *sqlState,
    SQLINTEGER   *nativeError,
    SQLCHAR      *messageText,
    SQLSMALLINT   messageTextLength,
    SQLSMALLINT  *requiredLength 
);

请注意,SQLError()函数可以接受三个不同的句柄,当您调用SQLError()时,您仅提供这三个句柄之一。例如,如果您在语句句柄上收到错误状态,则可以调用SQLError(),如下所示:

SQLError( SQL_NULL_HENV, SQL_NULL_HDBC, stmtHandle, ... );

表2 显示了在给定每种句柄类型的情况下如何调用SQLError()

句柄类型 SQLError() 参数
SQLHENV henvSQL_NULL_HDBCSQL_NULL_HSTMT、...
SQLHDBC SQL_NULL_HENVhdbcSQL_NULL_HSTMT、...
SQLHSTMT SQL_NULL_HENVSQL_NULL_HDBCstmt、...

如果SQLError()函数成功[1],它将返回三条状态信息。

[1]如果您给SQLError()提供了错误的句柄或者没有更多消息可报告给应用程序,则 SQLError() 将失败。

第一个称为SQLSTATEsqlState参数应指向6字节SQLCHAR数组。SQLError()将使用五个字符的代码(和 NULL 终止符)填充sqlState数组。ODBC 使用SQLSTATE作为一种以独立于数据库的格式提供状态信息的方法。SQLSTATE代码由两个字符的类和后跟的三个字符的子类组成。SQLSTATE代码“ 00000 ”表示“成功完成”,相当于SQL_SUCCESS。以类“01”开头的SQLSTATE值是警告。任何其他SQLSTATE类都指示错误。表 3 显示了一些常见的SQLSTATE值。

SQL状态 意义
00000 顺利完成
01004 警告字符串数据,右截断(即,您尝试将 20 个字节选择到 10 字节缓冲区中)
23000 违反完整性约束(例如,您尝试将重复的键值添加到唯一索引中)
42000 语法错误或违反访问规则
HY010 功能顺序错误
42S02 未找到基表(或视图)

SQLError()返回的第二条信息是本机错误号。驱动程序返回本机错误号,您必须先知道应用程序连接到哪种数据库,然后才能理解本机错误号。并非所有驱动程序都会返回本机错误号。

SQLError()返回的最有用的信息是错误消息的文本。SQLError()的最后三个参数用于检索错误消息。messageText 参数指向SQLCHAR数组。该数组的长度应为SQL_MAX_MESSAGE_LENGTH+1 个字节。messageTextLength告诉SQLError()它可以写入*messageText 的字节数。SQLError()将包含消息文本所需的字节数写入requiredLength [2]参数指向的SQLSMALLINT中。

[2]许多API函数需要返回可变长度的信息?不知何故,调用者必须知道为返回信息分配多少空间。此问题的常见解决方案是调用一个函数两次。当您进行第一次调用时,您告诉函数您为可变长度信息分配了 0 个字节。该函数通过设置类似于前面描述的requiredLength参数来告诉您需要多少空间。知道需要多少空间后,分配所需的字节数并再次调用该函数。在SQLError()的情况下,requiredLength参数毫无意义。对于每个诊断,我们不能多次调用SQLError(),因为一旦SQLError()从给定句柄检索诊断,该诊断就会被丢弃。

示例2 client2.c,展示了包含一些错误处理的代码

#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#include <stdio.h>
#include <stdlib.h>
typedef enum {FALSE, TRUE} bool;
static bool SQL_OK(SQLRETURN result){
if(result==SQL_SUCCESS || result==SQL_SUCCESS_WITH_INFO)
	return(TRUE);
else
	return(FALSE);
}

您已经了解过SQL_OK()函数?它只是检查 ODBC 返回的两个成功代码。

static bool printErrors(SQLHENV  	envHandle,
						SQLHDBC  	conHandle,
						SQLHSTMT 	stmtHandle){
	SQLRETURN   result;
	SQLCHAR     sqlState[6];
	SQLINTEGER  nativeError;
	SQLSMALLINT requiredLength;
	SQLCHAR     messageText[SQL_MAX_MESSAGE_LENGTH+1];
	do{
		result = SQLError(envHandle,
						  conHandle,
						  stmtHandle,
						  sqlState,
						  &nativeError,
						  messageText,
						  sizeof(messageText),
						  &requiredLength);
		if(SQL_OK(result)){
			printf("SQLState = %s\n", sqlState);
			printf("Native error = %d\n", nativeError);
			printf("Message text = %s\n", messageText);
		}
	} while(SQL_OK(result));
}

printErrors()函数是新函数。您调用SQLError()直到它返回失败代码。为什么要多次调用SQLError() ?因为每个 ODBC 函数都可能返回多个错误。请记住,每次SQLError()成功返回时,它都会从给定句柄中删除单个诊断。如果您不从句柄中检索所有错误,它们将在您下次使用该句柄时被丢弃。

int main(int argc, char * argv[]){
	SQLRETURN   res;
	SQLHENV     henv;
	SQLHDBC     conn;
	SQLCHAR     fullConnectStr[SQL_MAX_OPTION_STRING_LENGTH];
	SQLSMALLINT requiredLength;
	// 1.申请环境句柄
	res = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
	if(SQL_OK(res)){
		// 2.设置环境属性
		res = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC2, 0);
		if(!SQL_OK(res)){
			printErrors(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT);
			exit(-1);
		}
		// 3.申请连接句柄
		res = SQLAllocHandle(SQL_HANDLE_DBC, henv, &conn);
		if(!SQL_OK(res)){
			printErrors(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT);
			exit(-2);
		}
		res = SQLConnect(conn,  			// connection handle
						argv[1], SQL_NTS,   // data source name
						argv[2], SQL_NTS,   // user name
						argv[3], SQL_NTS);  // password
		if(!SQL_OK(res)){
			printErrors(SQL_NULL_HENV, conn, SQL_NULL_HSTMT);
			exit(-3);
		}
		printf("connection ok...disconnecting\n");
		res = SQLDisconnect(conn);
		if(!SQL_OK(res)){
			printErrors(SQL_NULL_HENV, conn, SQL_NULL_HSTMT);
			exit(-4);
		}
		res = SQLFreeHandle(SQL_HANDLE_DBC, conn);
		if(!SQL_OK(res)){
			printErrors(SQL_NULL_HENV, conn, SQL_NULL_HSTMT);
			exit(-5);
		}
		res = SQLFreeHandle(SQL_HANDLE_ENV, henv);
		if(!SQL_OK(res)){
			printErrors(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT);
			exit(-6);
		}
	}
	exit(0);
}

main()函数中有三个新功能。

首先,您会注意到我在代码中乱七八糟地调用了printErrors()。每当 ODBC 函数返回失败状态时,您都可以调用printErrors() 。当您获得SQL_SUCCESS_WITH_INFO状态时,您也可以调用printErrors(),但在大多数情况下,额外的信息是无用的。

请注意,一旦遇到错误,您就会退出。每次调用exit()都会指定不同的值:如果程序成功,则返回0;在所有其他情况下,您将返回一个唯一的负数。返回值被提供给调用程序(通常是 shell)并用于检查成功或失败。

我要解释的关于这个客户端的最后一件事是拆卸代码。要正确清理客户端应用程序,您必须断开连接句柄(使用SQLDisconnect() ),然后使用SQLFreeHandle()释放连接和环境句柄。拆除连接的顺序很重要。在断开连接之前,您将无法释放连接句柄。在所有连接句柄断开并释放之前,您将无法释放环境句柄。

如果要运行此程序,执行如下:

gcc -o client2 client2.c -I /home/postgres/odbc/include -L /home/postgres/odbc/lib -lodbc
./client2 PSQLODBC postgres postgresql@123

现在您知道如何连接到数据库、如何检测错误以及如何正确断开 ODBC 连接。

标签:res,句柄,odbc,添加,SQLError,SQL,OK,NULL,客户端
From: https://www.cnblogs.com/jl1771/p/17986055

相关文章

  • ODBC客户端查询处理
    本节,我将介绍一种新的句柄类型——SQLHSTMT语句句柄。SQLHSTMT的父级是连接句柄。您必须先释放所有子语句句柄,然后才能释放连接句柄。ODBC结果处理模型比其他PostgreSQLAPI更复杂。在libpq、libpq++和libpgeasyAPI中,您向服务器发送查询,然后调用函数来访问结果集中的每个......
  • odbc客户端连接到服务器
    让我们看一个示例代码client1.c。第一个客户端应用程序连接到数据库,然后退出。#include<sql.h>#include<sqlext.h>#include<stdio.h>#include<stdlib.h>intmain(intargc,char*argv[]){ SQLRETURNresult; SQLHENVhenv; SQLHDBChdbc; //1.申请......
  • osg给节点添加材质
      osg给节点添加材质 #include<osg/Material>#include<osg/Geode>#include<osgDB/ReadFile>#include<osgViewer/Viewer>intmain(){//创建一个场景节点osg::ref_ptr<osg::Node>root=newosg::Geode();//创建一个模型节点,这里读取一个模型文......
  • Linux命令:useradd添加用户
    useradd命令的详细使用1.创建一个默认配置的用户$useradduser1创建一个用户,登陆名为user1,『uid』,『group』,『gid』,『shell』,『home_dir』都采用默认值。可以通过$useradd-D来查看配置默认值。uid:用户账户的uid,默认值取决于/etc/login.defs文件中定义的U......
  • 达梦对数据表添加列和删除列优化测试
    背景需求近期项目中碰到一个问题,涉及到应用版本更新,每次更新,就需要对业务系统中上千个表进行增加列或删除列的操作,每个表数据量都比较大,对一个表增加一个列就需要几分钟,导致整个升级需要十几个小时,而同样的在oracle只需要半个小时完成,如果涉及到大版本更新,一次跟新就需要往表添加......
  • 服务器上mysql安装 ,以及客户端Navicat连接
    1.官网下载mysql8.0https://dev.mysql.com/downloads/installer/ 2.安装mysql8.0参考https://blog.csdn.net/weixin_47406082/article/details/131867849?ops_request_misc=&request_id=&biz_id=102&utm_term=mysql%E6%9C%80%E6%96%B0%E7%89%88%E5%AE%89%E8%A3%85%E......
  • centos7环境部署psqlodbc
    1获取unixODBC和psqlodbc源码包打开https://github.com/lurcher/unixODBC/tags,以下载unixODBC-2.3.7.tar.gz为例打开https://www.postgresql.org/ftp/odbc/versions/src/,以下载psqlodbc-09.06.0500.tar.gz为例将下载好的软件包放在/home/postgres2编译安装unixODBC执行如......
  • add 添加一条数据
    //云端函数'usestrict';constdb=uniCloud.database()exports.main=async(event,context)=>{ constcollection=db.collection(event.name) constres=awaitcollection.add(event.data) returnres};//前端js调用add(){ uni.showLoading({ ti......
  • 前端歌谣-第六十五课-express之服务端渲染和客户端渲染
    前言我是歌谣微信公众号关注前端小歌谣一起学习前端知识今天继续给大家讲解服务端渲染和客户端渲染静态资源的讲解案列index.html<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,init......
  • Kettle部署centos7并添加远程图形界面访问
    Kettle部署centos7并添加远程图形界面访问安装运行环境安装远程访问(xmanager)添加中文支持安装运行环境kettle需要java环境才能运行,因此要安装Java,点击我查看部署jdk。安装图形化界面1yumgroupinstall"XWindowSystem" 上传ketle文件,并上传至服务器......