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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks

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

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类:

2008-05-31 23:50:08

将定制的和复杂的业务逻辑集成到 SQL 语句中

developerWorks



外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163378) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163377) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163376) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163375) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163374) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163373) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163372) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163371) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163370) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163369) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163368) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163367) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163366) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163365) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163364) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163363) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163362) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163361) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163360) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163359) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163358) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163357) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163356) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163355) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163354) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163353) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163352) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163351) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163350) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163349) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163348) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163347) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163346) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163345) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163344) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163343) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163342) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163341) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163340) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163339) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163338) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163337) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163336) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163335) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163334) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163333) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163332) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163331) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163330) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163329) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163328) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~


外部存储过程

通过引用外部程序可以获得超出 SQL PL 范围的强大功能。通过使用一个外部存储过程(即使用 Java 语言或 C# 等编程语言编写的存储过程),可以处理外部数据源,或者执行数据库之外的外部动作。

与外部 UDF 相似,外部存储过程可以定义为以 NOT FENCEDFENCED 模式运行。同样,使用 NOT FENCED 过程的优点是可以提高性能。但是,如果没有适当地编写这种过程,就会出现内存漏洞,这种内存漏洞会覆盖与 DB2 引擎相关联的内存,因此会产生非常恶劣的影响。

清单 25 显示了注册外部存储过程的简化语法图:



                    
>>-CREATE PROCEDURE--procedure-name----------------------------->
 
>--+--------------------------------------------------------+--->
   '-(--+----------------------------------------------+--)-'
        | .-,----------------------------------------. |
        | V .-IN----.                                | |
        '---+-------+--+----------------+--data-type-+-'
            +-OUT---+  '-parameter-name-'
            '-INOUT-'
 
>--*--+-------------------------+--*---------------------------->
      '-SPECIFIC--specific-name-'
 
   .-DYNAMIC RESULT SETS 0--------.     .-MODIFIES SQL DATA-.
>--+------------------------------+--*--+-------------------+--->
   '-DYNAMIC RESULT SETS--integer-'     +-NO SQL------------+
                                        +-CONTAINS SQL------+
                                        '-READS SQL DATA----'
 
      .-NOT DETERMINISTIC-.     .-CALLED ON NULL INPUT-.
>--*--+-------------------+--*--+----------------------+--*----->
      '-DETERMINISTIC-----'
 
   .-OLD SAVEPOINT LEVEL-.
>--+---------------------+--*--LANGUAGE--+-C-----+--*----------->
   '-NEW SAVEPOINT LEVEL-'               +-JAVA--+
                                         +-COBOL-+
                                         +-CLR---+
                                         '-OLE---'
 
>--EXTERNAL--+----------------------+--*------------------------>
             '-NAME--+-'string'---+-'
                     '-identifier-'
 
   .-FENCED------------------------.
>--+-------------------------------+--*------------------------->
   +-FENCED--*--+-THREADSAFE-----+-+
   |            '-NOT THREADSAFE-' |
   |                .-THREADSAFE-. |
   '-NOT FENCED--*--+------------+-'
 
   .-EXTERNAL ACTION----.  .-INHERIT SPECIAL REGISTERS-.
>--+--------------------+--+---------------------------+--*----->
   '-NO EXTERNAL ACTION-'
 
>--PARAMETER STYLE--+-DB2GENERAL---------+--*------------------->
                    +-DB2SQL-------------+
                    +-GENERAL------------+
                    +-GENERAL WITH NULLS-+
                    +-JAVA---------------+
                    '-SQL----------------'

这个语法图中的很多子句在之前的一些小节中已经讨论过。本节着重介绍外部存储过程特有的一些主要部分。

  • LANGUAGE: 表明过程是用什么语言编写的。可用于编写外部过程的语言有 C、Java 语言、COBOL、CLR 和 OLE。
  • EXTERNAL NAME: 指定用户编写的用来实现所定义过程的代码的名称。该字符串的格式取决于所指定的语言。本教程简要地讨论在使用 C、Java 和 CLR 语言时该字符串的格式。
  • EXTERNAL ACTION: 决定过程是否可以执行外部动作。
  • PARAMETER STYLE: 该子句用于指定过程传递参数和返回值的约定。可用的选项有:
    • DB2GENERAL: 使用为 Java 方法定义的参数传递约定。只有在使用 LANGUAGE JAVA 时,才能指定该选项。
    • DB2SQL: 当指定该选项时,可以将提供附加诊断信息的附加参数传递给过程。只有在指定 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。
    • GENERAL: 导致过程接收 CALL 语句中指定的参数,而不使用 SQLDA 结构。只有在指定 LANGUAGE CCOBOLCLR 时,才能指定该选项。
    • GENERAL WITH NULLS: 类似于 GENERAL 选项,但是还将另一个参数传递给过程:该参数是由 null 指示符组成的一个向量,CALL 语句的每个参数对应一个 null 指示符。
    • JAVA: 导致过程使用遵从 Java 语言和 SQLJ 例程规范的参数传递约定。 以单条目数组的形式传递 IN/OUTOUT 参数,以便于返回值。只有当使用 LANGUAGE JAVA 时,才能指定该选项。
    • SQL: 当指定该选项时,CALL 语句中包括提供附加诊断信息的附加参数。只有当使用 LANGUAGE CCOBOLCLROLE 时,才能指定该选项。

要了解关于 CREATE PROCEDURE 语句中这些子句和其他子句的更多信息,请参阅 DB2 文档。





回页首


外部存储过程一个最重要的强制性子句就是 EXTERNAL NAME 子句。该子句控制 DB2 可以在哪里寻找编译后的过程代码。在本节中,您将了解在 C、Java 和 CLR 语言中,该子句的字符串是如何工作的。

指定的字符串是库名和库中的过程,数据库管理器调用它来执行所创建的过程。在执行 CREATE PROCEDURE 语句时,这个库(以及库中的过程)不需要已经存在。但是,当过程被调用时,这个库和库中的过程必须存在,并且能够从数据库服务器上访问到。对于 C 语言,指定的字符串格式如下:

>>-'--+-library_id-------+--+------------+--'------------------>|
      '-absolute_path_id-'  '-!--proc_id-'

下面分别描述它的不同组成部分:

  • library_id: 包含该过程的库的名称。数据库管理器按如下方法寻找库:
    • 在 UNIX 系统上,如果指定的 library_idmyfunc,数据库管理器在 /u/production 目录下运行,当指定 FENCED 时,数据库管理器在 /u/production/sqllib/function/myfunc 中寻找过程库;当指定 NOT FENCED 时,数据库管理器在 /u/production/sqllib/function/unfenced/myproc 中寻找过程库。
    • 在 Windows 操作系统上,数据库管理器在 LIBPATHPATH 环境变量指定的目录路径中寻找过程库。
  • absolute_path_id: 标识包含该过程的文件的完整路径名。
  • ! proc_id: 标识要调用的过程的入口名称。! 是库 ID 与过程 ID 之间的定界符。例如,!proc8 将指示数据库管理器在 absolute_path_id 指定的位置寻找库,并使用那个库中的 proc8 入口。如果这个字符串的格式不对,就会返回错误。

指定的字符串包含可选的 JAR 文件标识符、类标识符和方法标识符,数据库管理器调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,类标识符和方法标识符不需要已经存在。如果指定了一个 jar_id,那么当执行 CREATE PROCEDURE 语句时,它必须已经存在。同样的,当过程被调用时,类标识符和方法标识符必须已经存在,并且可以从数据库服务器上访问到。否则会返回错误。对于 Java 语言,该字符串的格式为:

>>-'--+----------+--class_id--+-.-+--method_id--'--------------><
      '-jar_id :-'            '-!-'

下面分别描述它的不同组成部分:

  • jar_id: JAR 集合在被安装到数据库中时获得的 JAR 标识符。它可以是一个简单的标识符,例如 myJar,也可以是一个模式限定的标识符,例如 mySchema.myJar
  • class_id: Java 对象的类标识符。如果这个类属于一个包,则类标识符部分还必须包括完整的包前缀。例如,如果使用 myPacks.StoredProcs,则 Java 虚拟机将在 .../myPacks/StoredProcs/(对于 Windows,则为 ...\myPacks\StoredProcs\)目录中寻找类。
  • method_id: 被调用的 Java 类中的方法的名称。

指定的字符串表示 .NET 组合件(库或可执行文件)、组合件中的类以及类中的方法,数据库管理器将调用它来执行所创建的过程。当执行 CREATE PROCEDURE 语句时,模块、类和方法不需要已经存在。但是,当过程被调用时,模块、类和方法必须存在,并且可以从数据库服务器上访问到,否则会返回错误。对于 .NET 组合件(库或可执行文件),该字符串格式如下:

>>-'--assembly--:--class_id--!--method_id--'-------------------><

下面分别描述它的不同组成部分:

  • assembly: 类所在的 DLL 或其他文件的标识符。这里必须指定文件扩展名(例如 .dll)。如果没有提供完整的路径名称,那么该文件必须在 DB2 安装路径(例如 C:\sqllib\function)的函数目录中。如果该文件在安装路径下的函数目录中的一个子目录中,那么可以在文件名之前提供这个子目录,而不必指定完整的路径。例如,如果安装目录为 C:\sqllib\function\myprocs\mydotnet.dll,那么只需为组合件指定 myprocs\mydotnet.dll。该参数的大小写敏感性与文件系统相同。
  • class_id: 指定在给定的组合件中,要调用的方法所在的类的名称。如果这个类在一个名称空间中,那么除了类名之外,还需指定完整的名称空间。例如,如果类 EmployeeClass 在名称空间 MyCompany.ProcedureClasses 中,那么必须指定 MyCompany.ProcedureClasses.EmployeeClass。该参数是大小写敏感的。
  • method_id: 指定在给定类中要调用的方法。该参数是大小写敏感的。

现在,您已经回顾了创建外部存储过程的语法,接下来可以看看创建 Java 存储过程的一个例子。





回页首


我们来看一个创建 Java 存储过程的例子。 清单 26 包含该过程的 Java 源代码:



                    
import java.sql.*;
 
public class Simple
{
  public static void SimpleInsert  (String input, String[] outMsg) throws 
  SQLException, Exception
  {
       int errorCode;
  
       try
       {
            // get caller's connection to the database
            Connection con = DriverManager.getConnection("jdbc:default:connection");

            // assumes the following table exists in the database
            // CREATE TABLE db2admin.mydata (col1 CHAR(3))
            String query = "INSERT INTO db2admin.mydata (col1) VALUES (?)";

            PreparedStatement pstmt = con.prepareStatement(query);
            pstmt.setString(1, input);
            pstmt.executeUpdate();
               
            outMsg[0] = "The update was successful.";
       }   
       catch (SQLException sqle)
       {
            errorCode = sqle.getErrorCode();
            throw new SQLException( errorCode + " FAILED" ); 
       }
  }
}

该过程的代码包含在一个名为 SimpleInsert() 的 Java 方法中,而这个 Java 方法又包含在一个名为 Simple 的 Java 类中。(因此存放代码的文件名为 Simple.java)。清单 26 中的代码没有什么特别之处,它是标准的含有 JDBC 方法调用的 Java 代码。该过程有两个参数,都是字符串型的。第一个参数是输入参数,第二个参数是输出参数。注意,输出参数被定义为一个 String 数组。该过程用于注册的 PARAMETER STYLE JAVA 属性要求 OUTINOUT 参数定义为数组。还需注意的是该过程继承调用者到数据库的连接的方式,它使用的连接字符串不同于标准的 JDBC 应用程序。

通过使用安装的系统上的或者 DB2 附带的 JDK,可以像下面这样编译该过程:

javac Simple.java

编译后会生成一个类文件。然后,可以将该文件转移到 sqllib/function 目录(DB2 寻找存储过程可执行文件的默认位置),或者转移到您所选择的其他位置(只要在 CREATE PROCEDURE command 中使用这个定制路径)。对于这个例子,使用前一种目录,将类文件复制到 sqllib/function 目录中。

将类文件放在适当的位置后,便可以使用 CREATE PROCEDURE 语句将该函数注册到 DB2 中,如 清单 27 所示:



                    
CREATE PROCEDURE simple_insert (IN input CHAR(3), OUT outMsg VARCHAR(254))
SPECIFIC simple1
DYNAMIC RESULT SETS 0
DETERMINISTIC
LANGUAGE JAVA
PARAMETER STYLE JAVA
FENCED
THREADSAFE
MODIFIES SQL DATA
EXTERNAL NAME 'Simple!SimpleInsert'

注册函数之后,就可以调用该函数,如 清单 28 所示。注意,问号(?)用于表示输出参数。当从命令行调用存储过程时,都是用问号表示输出参数。



                    
CALL simple_insert('ABC', ?)

Value of output parameters
--------------------------
Parameter Name  : OUTMSG
Parameter Value : The update was successful.

 Return Status = 0



Result from DB2 sample database:

SELECT * FROM db2admin.mydata


COL1

----------------------------
ABC


  1 record(s) selected.

这个非常简单的 Java 存储过程实际上也可以很容易地编写成 SQL 存储过程。但是,看过这个例子之后,就应该清楚,如果使用主机编程语言的所有功能和 API,可以编写出多么复杂的外部存储过程。

阅读(1163327) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~