db2 正则匹配_Db2 中的sql 怎样实现正则表达式的功能

展开全部

尽管62616964757a686964616fe4b893e5b19e31333236396530上面的函数按照预期的方式工作,但还可以改进它以获得更佳的性能。注:函数内部的执行完成得越快,DB2 处理整个 SQL 语句的速度也就越快。

SQL 旨在处理多组行,这意味着通常会针对一个模式匹配多个行。在大多数情况下,模式本身对于整个 SQL 语句都是不变的;即,它不会随行的更改而更改。 清单 5 中的 C 代码展示了对每一行都调用函数 pcre_compile() ,该函数将给定模式转换成内部表示法。

DB2 通过使用所谓的“高速暂存(scratchpad)”提供了在 UDF 调用之间传递信息的机制。此外,您可以标识特定调用“类型”;即它是对该 UDF 的第一次调用、普通调用还是最后一次(最终)调用。使用高速暂存和调用类型,有可能只对模式编译一次,然后将该已编译模式的内部表示法重用于对该 UDF 的所有后续调用。在最后一次调用时,释放在处理期间分配的资源。

如 清单 6所示,对 CREATE FUNCTION 语句进行修改,告诉 DB2 向外部 C 代码提供高速暂存和调用类型:

清单 6. 将高速暂存和调用类型添加到 CREATE FUNCTION 语句

CREATE FUNCTION regex2(pattern VARCHAR(2048), string CLOB(10M))

RETURNS INTEGER

SPECIFIC regexPerf

EXTERNAL NAME 'regexUdf!regexpPerf'

LANGUAGE C

PARAMETER STYLE DB2SQL

DETERMINISTIC

NOT FENCED

RETURNS NULL ON NULL INPUT

NO SQL

NO EXTERNAL ACTION

SCRATCHPAD 50

FINAL CALL

ALLOW PARALLEL;

UDF 入口点看起来很不一样,因为必须改写函数内部的逻辑。参数方面唯一的更改是使用 SQLUDF_TRAIL_ARGS_ALL 代替了 SQLUDF_TRAIL_ARGS ,如 清单 7所示。

清单 7. regex2 的 C UDF 入口点

#include

#include

// data structure mapped on the scratchpad for easier use and access

// to the objects

// the size of the scratchpad defined in the CREATE FUNCTION statement

// must be at least as large as sizeof(scratchPadMapping)

struct scratchPadMapping {

pcre *re;

pcre_extra *extra;

const char *error;

int errOffset;

};

void regexpPerf(

// input parameters

SQLUDF_VARCHAR *pattern, SQLUDF_CLOB *str,

// output

SQLUDF_INTEGER *match,

// null indicators

SQLUDF_NULLIND *pattern_ind, SQLUDF_NULLIND *str_ind,

SQLUDF_NULLIND *match_ind,

SQLUDF_TRAIL_ARGS_ALL) // SQLUDF_SCRAT & SQLUDF_CALLT

{

int rc = 0;

struct scratchPadMapping *scratch = NULL;

// map the buffer of the scratchpad and assume successful return

scratch = (struct scratchPadMapping *)SQLUDF_SCRAT->data;

*match_ind = 0;

switch (SQLUDF_CALLT) {

case SQLUDF_FIRST_CALL:

// initialize data on the scratchpad

scratch->re = NULL;

scratch->extra = NULL;

scratch->error = NULL;

scratch->errOffset = 0;

// compile the pattern (only in the FIRST call

scratch->re = pcre_compile(pattern, 0 /* default options */,

&scratch->error, &scratch->errOffset, NULL);

if (scratch->re == NULL) {

snprintf(SQLUDF_MSGTX, 70, "Regexp compilation failed at "

"offset %d: %s\\n", scratch->errOffset, scratch->error);

strcpy(SQLUDF_STATE, "38900");

rc = -1;

break;

}

// further analyze the pattern (might return NULL)

scratch->extra = pcre_study(scratch->re,

0 /* default options */, &scratch->error);

/* fall through to NORMAL call because DB2 expects a result

already in the FIRST call */

case SQLUDF_NORMAL_CALL:

// match the current string

rc = pcre_exec(scratch->re, scratch->extra, str->data,

str->length, 0, 0 /* default options */, NULL, 0);

switch (rc) {

case PCRE_ERROR_NOMATCH:

*match = 0;

rc = 0;

break;

case PCRE_ERROR_BADOPTION:

snprintf(SQLUDF_MSGTX, 70, "An unrecognized bit was set "

"in the options argument");

strcpy(SQLUDF_STATE, "38901");

rc = -1;

break;

case PCRE_ERROR_NOMEMORY:

snprintf(SQLUDF_MSGTX, 70, "Not enough memory available.");

strcpy(SQLUDF_STATE, "38902");

rc = -1;

break;

default:

if (rc < 0) {

snprintf(SQLUDF_MSGTX, 70, "A regexp match error "

"occured: %d", rc);

strcpy(SQLUDF_STATE, "38903");

rc = -1;

}

else {

*match = 1;

rc = 0;

}

break;

}

break;

}

// cleanup in FINAL call, or if we encountered an error in

// the FIRST call (DB2 will make a FINAL call if we encounter

// an error in any NORMAL call)

if (SQLUDF_CALLT == SQLUDF_FINAL_CALL ||

(SQLUDF_CALLT == SQLUDF_FIRST_CALL && rc < 0)) {

(*pcre_free)(scratch->re);

(*pcre_free)(scratch->extra);

}

return;

}

为了进一步改进该函数的性能,我添加了对函数 pcre_study() 的调用,该函数是由模式匹配引擎提供的。该函数进一步分析了该模式,并将额外的信息存储在独立的结构中。然后,在实际的匹配期间使用这些额外的信息来加快处理速度。通过使用一个非常简单的模式和大约 4000 行的表,我获得了 5% 的执行时间的改善。当然,模式越复杂,差异将越显著。

我先前提到该实现假定模式在处理期间不会随行的不同而更改。当然,如果模式确实更改了,您可以进行少量的改写以再次编译一个模式。要这样做,有必要跟踪当前(已编译的)模式并在每次调用中将它与所提供的模式进行比较。也可以在高速暂存中维护当前模式。但必须将它复制到独立的缓冲区,并且不能通过指针模式直接引用它,因为这个指针或它所引用的数据可能会更改或变为无效。至于相应的代码更改,就当作练习留给读者了。

返回匹配子串

大多数模式匹配引擎提供了一种方法,返回与指定模式或其一部分相匹配的子串。如果想在 SQL 中使用这种能力,则必须使用不同的方法来实现匹配函数。给定的字符串可能包含不止一个匹配的子串。例如,当解析类似“abc = 123;”或“def = 'some text';”这样的字符串时,用户可能会希望检索由等号分隔的两个子串。您可以使用模式“\\w+\\s*=\\s*(\\d+|'[\\w\\s] *');”来表示适用于该字符串的语法规则。Perl 兼容的正则表达式允许您捕获等号两边的子串。最后,必须将要捕获的子串用括号括起来。我已经用该方式编写了第二个子串,但第一个子串不是这样编写的。用于该用途的最终模式是这样的:

(\\w+)\\s*=\\s*(\\d+|'[\\w\\s]*');

当把这个模式应用于字符串“abc= 123;”或“def = 'some text';”时,“abc”或“def”分别与“(\\w+)”匹配,空格和等号是通过“\\s*=\\s*”查找的,并用另外的“(\\d+|'[\ \w\\s*]')”涵盖了余下的子串。在“(\\d+|'[\\w\\s*]')”中,第一个选项与任何至少由一个数字“\\d+”组成的数匹配,而第二个选项解析任何由字母和空格组成的由单引号括起的字符串“'[\\w\\s]*'”。

在 DB2 中做到这一点的需求可以描述成:为一次 UDF 调用返回多个结果。换句话说,就是返回针对模式进行匹配的单个字符串的多个子串。DB2 的表函数是完成这一任务的完美工具。

实现表 UDF

和以前一样,必须在数据库中创建该函数。 清单 8中的下列语句正是用于这一任务的:

清单 8. 注册名为 regex3 的表 UDF

CREATE FUNCTION regex3(pattern VARCHAR(2048), string CLOB(10M))

RETURNS TABLE ( position INTEGER, substring VARCHAR(2048) )

SPECIFIC regexSubstr

EXTERNAL NAME 'regexUdf!regexpSubstr'

LANGUAGE C

PARAMETER STYLE DB2SQL

DETERMINISTIC

NOT FENCED

RETURNS NULL ON NULL INPUT

NO SQL

NO EXTERNAL ACTION

SCRATCHPAD 50

NO FINAL CALL

DISALLOW PARALLEL;

实现该函数的实际逻辑的 C 代码与 清单 7中的代码非常相似,但根据表函数所必须满足的特殊需求对它进行了改编,如 清单 9所示

你还是看一下这个网站

http://news.weixiuwang.com/server/2006-6/2006E6Y2;1057E89818855_1.htm

本回答被网友采纳

已赞过

已踩过<

你对这个回答的评价是?

评论

收起

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值