Chinaunix首页 | 论坛 | 博客
  • 博客访问: 91094402
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094403
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094404
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094405
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094406
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094407
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094408
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094399
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094410
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094411
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094412
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094413
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094414
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094415
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094416
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094417
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094418
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094419
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094420
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094421
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094422
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094423
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094414
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094425
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094426
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094427
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094428
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094429
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094430
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094431
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094432
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094433
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094434
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094435
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094436
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094437
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094438
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094429
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094440
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094441
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094442
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094443
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094444
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094445
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094446
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094447
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094448
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094449
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094450
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094451
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094452
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks

DB2 9 应用开发(733 考试)认证指南,第 5 部分: CLI/ODBC 编程(5)-sdccf-ChinaUnix博客
  • 博客访问: 91094453
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:33:13

developerWorks



诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261638) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261637) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261636) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261635) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261634) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261633) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261632) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261631) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261630) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261629) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261628) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261627) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261626) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261625) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261624) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261623) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261622) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261621) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261620) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261619) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261618) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261617) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261616) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261615) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261614) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261613) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261612) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261611) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261610) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261609) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261608) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261607) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261606) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261605) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261604) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261603) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261602) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261601) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261600) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261599) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261598) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261597) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261596) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261595) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261594) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261593) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261592) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261591) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261590) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261589) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261588) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


诊断和错误处理

每当调用 CLI/ODBC 函数时,都会将一个特殊的值,即所谓的返回码,返回给调用的应用程序,以表明函数是否按预期执行。如果由于某种原因函数没有成功执行,那么生成的返回码的值将指示函数失败的原因。CLI/ODBC 函数可能返回的返回码如表 2 所示:



返回码 意义
SQL_SUCCESS CLI/ODBC 函数成功完成
SQL_SUCCESS_WITH_INFO CLI/ODBC 函数成功完成,但是遇到一个警告或非致命错误
SQL_NO_DATA or SQL_NO_DATA_FOUND CLI/ODBC 函数成功完成,但是未找到相关的数据
SQL_INVALID_HANDLE 由于指定了无效的环境句柄、连接句柄、语句句柄或描述符句柄,CLI/ODBC 函数失败。只有在指定的句柄还没有分配空间,或者类型不对的情况下(例如,当期望的是一个环境句柄时,提供的却是一个连接句柄),才会返回该返回码
SQL_NEED_DATA 由于函数没有找到期望在执行时使用的数据,CLI/ODBC 函数失败。当返回该返回码时,通常是因为参数或列已经被绑定为实时数据的(SQL_DATA_AT_EXEC)参数/列
SQL_STILL_EXECUTING 异步启动的 CLI/ODBC 函数仍然在执行
SQL_ERROR CLI/ODBC 函数失败

错误处理是应用程序中重要的一部分,CLI/ODBC 应用程序也不例外。CLI/ODBC 应用程序至少应该通过检查返回码来确认 CLI/ODBC 函数是否成功执行。当一个函数未能按预期执行时,应该通知用户出现了错误或警告,并尽可能向用户提供有助于他们快速发现并修复问题的诊断信息。





回页首


虽然返回码可以告诉应用程序是否遇到错误或警告,但是它不能为应用程序提供关于是什么导致错误或警告出现的具体信息。由于在解决一个问题时,通常还需要关于一个错误或警告的更多信息,因此 DB2 (以及其他关系数据库产品)使用一组错误消息码,即所谓的 SQLSTATE 来提供警告和错误的补充诊断信息。SQLSTATE 是由字母和数字组成的一个字符串,长度为 5 个字符(字节),格式为 ccsss,其中 cc 表示错误消息的类型,sss 表示错误消息的子类。类型为 01 的 SQLSTATE 对应于一个警告;类型为 HY 的 SQLSTATE 对应于由 DB2 CLI 生成的错误;类型为 IM 的 SQLSTATE 对应于由 ODBC Driver Manager 生成的错误。(由于不同的数据库服务器通常有不同的诊断消息码,因此 SQLSTATE 遵从 X/Open CLI 标准规范中列出的标准。SQLSTATE 值的标准化使得应用程序开发人员对于不同关系数据库产品可以按一致的方法处理错误和警告。)

与返回码不同,SQLSTATE 通常被当作指导信息,而且不需要通过驱动程序来返回它们。因此,虽然驱动程序应该总是返回正确的 SQLSTATE 以指示它们所能检测的错误或警告,但是应用程序不应总是指望它。因为 SQLSTATE 并不是一定会返回,因此大多数应用程序只是将 SQLSTATE 与相应的诊断消息和可用的本地错误代码一起返回给用户。





回页首


那么,当 CLI/ODBC 函数未能正确执行时,如何获取 SQLSTATE 值、诊断消息和本地错误代码呢?这些信息可以通过调用 SQLGetDiagRec() 函数、SQLGetDiagField() 函数或同时调用这两个函数获得。这两个函数接受环境句柄、连接句柄、语句句柄或描述符句柄作为输入,然后返回关于最近使用指定句柄执行的 CLI/ODBC 函数的诊断信息。如果生成了多个诊断记录,那么应用程序必须重复地调用这两个函数中的一个函数或同时调用这两个函数,直到获得所有可用的诊断信息。(通过调用 SQLGetDiagField() 函数,并指定记录号 0 —— header 记录号 —— 和 SQL_DIAG_NUMBER 选项,可以确定可用的诊断信息的总数。)

诊断信息以诊断记录的形式存储在内容中。应用程序可以通过调用 SQLGetDiagRec() 函数直接获得 SQLSTATE 值、诊断消息和本地错误代码。但是,不能使用该函数从诊断 header 记录中检索信息。应用程序必须使用 SQLGetDiagField() 函数来检索诊断 header 记录中存储的信息。SQLGetDiagField() 函数还可以用于获取单个诊断记录字段的值。(例如,SQLGetDiagField() 函数可用于获得关于受 select、insert、update 或 delete 操作影响的行数的信息。)





回页首


前面已经介绍了,当出现错误或警告时,如何使用返回码进行检测,以及如何使用诊断记录提供反馈。 接下来,让我们看一看 CLI/ODBC 应用程序中通常是如何进行错误处理和检索诊断信息的。下面这个 CLI/ODBC 应用程序是用 C 语言编写的,它展示了当出现错误或者需要更多关于与一个 SELECT SQL 语句相关联的处理的信息时,如何使用 SQLGetDiagRec()SQLGetDiagField() 函数显示诊断信息。



                     
#include 
#include 
#include 

int main()
{
    // Declare The Local Memory Variables
    SQLHANDLE    EnvHandle = 0;
    SQLHANDLE    ConHandle = 0;
    SQLHANDLE    StmtHandle = 0;
    SQLCHAR      ConString[512];
    SQLRETURN    RetCode = SQL_SUCCESS;

    SQLSMALLINT  Counter = 0;
    SQLINTEGER   NumRecords = 0;
    SQLINTEGER   NativeErr = 0;
    SQLCHAR      SQLState[6];
    SQLCHAR      ErrMsg[255];
    SQLSMALLINT  ErrMsgLen = 0;
    SQLCHAR      SQLStmt[255];

    // Allocate An Environment Handle
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
        &EnvHandle);

    // Set The ODBC 应用程序 Version To 3.x
    if (EnvHandle != 0)
        SQLSetEnvAttr(EnvHandle, SQL_ATTR_ODBC_VERSION, 
            (SQLPOINTER) SQL_OV_ODBC3, SQL_IS_UINTEGER);

    // Allocate A Connection Handle
    if (EnvHandle != 0)
        SQLAllocHandle(SQL_HANDLE_DBC, EnvHandle,
            &ConHandle);

    // Build A Valid Connection String
    sprintf((char *) ConString, "driver={IBM DB2 ODBC DRIVER};");
    strcat((char *) ConString, "dbalias=sample;uid=db2admin;pwd=ibmdb2");

    // Connect To The Appropriate Data Source
    if (ConHandle != 0)
        RetCode = SQLDriverConnect(ConHandle, NULL, (SQLCHAR *) ConString,
                      SQL_NTS, NULL, 0, NULL, 
                      SQL_DRIVER_NOPROMPT);

    // If Unable To Establish A Data Source Connection,
    // Obtain Any Diagnostic Information Available
    if (RetCode != SQL_SUCCESS)
    {
        // Find Out How Many Diagnostic Records Are 
        // Available
        SQLGetDiagField(SQL_HANDLE_DBC, ConHandle, 0,
            SQL_DIAG_NUMBER, &NumRecords, SQL_IS_INTEGER,
            NULL);

        // Retrieve And Display The Diagnostic Information
        // Produced 
        for (Counter = 1; Counter <= NumRecords; Counter++)
        {
            // Retrieve The Information Stored In Each
            // Diagnostic Record Generated 
            SQLGetDiagRec(SQL_HANDLE_DBC, ConHandle, Counter,
                SQLState, &NativeErr, ErrMsg, sizeof(ErrMsg),
                &ErrMsgLen);

            // Display The Information Retrieved
            printf("SQLSTATE : %s\n", SQLState);
            printf("%s\n", ErrMsg);

            // Prepare To Exit
            goto EXIT;            
        }
    }

    // Allocate An SQL Statement Handle
    if (ConHandle != 0)
        SQLAllocHandle(SQL_HANDLE_STMT, ConHandle,
           &StmtHandle);

    // Set The Appropriate Statement Attributes
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_DEFERRED_PREPARE, 
        (SQLPOINTER) SQL_DEFERRED_PREPARE_OFF, 0);
    SQLSetStmtAttr(StmtHandle, SQL_ATTR_CURSOR_TYPE, 
        (SQLPOINTER) SQL_CURSOR_STATIC, 0);

    // Define A SELECT SQL Statement
    strcpy((char *) SQLStmt, "SELECT deptno, deptname FROM ");
    strcat((char *) SQLStmt, "department");

    // Prepare The SQL Statement
    if (SQLPrepare(StmtHandle, (SQLCHAR *) SQLStmt, SQL_NTS) == SQL_SUCCESS)
        {
            // Obtain The Estimated Number Of Rows That Will Be
            // Returned By The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords, 
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
            printf("Estimated number of records that will be returned : %d\n", 
                NumRecords);
     
            // Execute The SELECT SQL Statement
            SQLExecute(StmtHandle);

            // Obtain The Actual Number Of Rows Returned By 
            // The SELECT Statement
            RetCode = SQLGetDiagField(SQL_HANDLE_STMT, StmtHandle, 0, 
                          SQL_DIAG_CURSOR_ROW_COUNT, &NumRecords,
                          SQL_IS_INTEGER, NULL);

            // Display The Information Retrieved
            if (RetCode == SQL_SUCCESS)
                printf("Actual number of records returned : %d\n",
                    NumRecords);
	}

EXIT:

    // Free The SQL Statement Handle
    if (StmtHandle != 0)
        SQLFreeHandle(SQL_HANDLE_STMT, StmtHandle);

    // Free The Connection Handle
    if (ConHandle != 0)
        SQLFreeHandle(SQL_HANDLE_DBC, ConHandle);

    // Free The Environment Handle
    if (EnvHandle != 0)
        SQLFreeHandle(SQL_HANDLE_ENV, EnvHandle);

    // Return Control To The Operating System
    return(0);
}
	
阅读(261587) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~