免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5992 | 回复: 6
打印 上一主题 下一主题

[问题求助] DB2自定义TRIM函数 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-10-27 13:24 |只看该作者 |倒序浏览
最近因项目的需要,须在DB2中自建一个自定义的TRIM函数,功能是去掉字符串前后的空字符,如空格,TAB之类的东西.

版上有许多这方面的讨论以及代码,我COPY了Jamesqiao所写的用来测试:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <sys/stat.h>
  5. #include <sys/types.h>
  6. #include <sqludf.h>


  7. //Macro for iendity the blanks
  8. #define isSpaces(ch) (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\b' || ch == '\f' || ch == '\n')

  9. char *TrimChr(char *pszSource)
  10. {
  11.         //pointer of the first char of string
  12.         char *pszHead = pszSource;
  13.         //pointer of the last non-blank char
  14.         char *pszLast = &pszSource[strlen(pszSource)-1];
  15.         //search the location of the last non-blank char
  16.         while (isSpaces(*pszLast))
  17.                 --pszLast;
  18.         *(++pszLast) = '\0';
  19.         //search the first non-blank char for left shift the string
  20.         for ( ; (*pszHead != '\0') && (pszHead != pszLast); ++pszHead)
  21.         {
  22.                 if (! isSpaces(*pszHead))
  23.                 {
  24.                         strcpy(pszSource, pszHead);
  25.                         break;
  26.                 }
  27.         }

  28.         return pszSource;
  29. }

  30. int main(int argc,char *argv[])
  31. {
  32.         printf("\"");
  33.         printf(argv[1]);
  34.         printf("\"\n");
  35.         printf("\"");
  36.         printf(TrimChr(argv[1]));
  37.         printf("\"\n");
  38. }
复制代码
代码可以编译成功并在LINUX环境下运行的.


但是我想用它变成DB2的一个自定义函数时,老是出问题:
  1. values TrimChr('   aaaa    ');

  2. [IBM][CLI Driver][DB2/LINUX] SQL0444N  Routine "TRIMCHR" (specific name "SQL080529112348600") is implemented with code in library or path ".../sqllib/function/TrimChr", function "TrimChr" which cannot be accessed.  Reason code: "5".  SQLSTATE=42724
复制代码
自定义函数是如此写的:
  1. CREATE FUNCTION TrimChr (VARCHAR(400))
  2.                            RETURNS VARCHAR(400)   
  3.                            EXTERNAL NAME '/home/db2inst1/sqllib/function/TrimChr!TrimChr'
  4.                            LANGUAGE C  
  5.                            NULL CALL  
  6.                            PARAMETER STYLE DB2SQL  
  7.                            NO SQL  
  8.                            DETERMINISTIC  
  9.                            NO EXTERNAL ACTION
  10.                            NOT FENCED;

  11. GRANT EXECUTE ON FUNCTION TRIMCHR(VARCHAR(400)) TO PUBLIC;
复制代码
请问是什么原因?是编译的问题?还是C函数的问题(与指针有关?)?

论坛徽章:
0
2 [报告]
发表于 2010-10-27 14:04 |只看该作者
Reason code 5 :
There was insufficient memory to load the library containing
The function or one or more symbols could not be resolved.
Contact the routine creator or your database administrator to
Make sure that the library was correctly linked. All required
Libraries to resolve referenced symbols such as external
Functions must be available. If a lack of memory is determined
Then the system configuration may need to be changed to make more
Memory available to DB2.

论坛徽章:
1
2015年辞旧岁徽章
日期:2015-03-03 16:54:15
3 [报告]
发表于 2010-10-27 14:25 |只看该作者
专业人士面对陌生领域一般都是先从 hello world 开始吧。
这个唤作“单元测试”

论坛徽章:
0
4 [报告]
发表于 2010-10-27 18:16 |只看该作者
我查了一下网上的资料,发现人家是这样写的:
  1. #include <pcre.h>
  2. #include <sqludf.h>

  3. void regexpSimple(
  4.     // input parameters
  5.     SQLUDF_VARCHAR *pattern,      SQLUDF_CLOB *str,
  6.     // output
  7.     SQLUDF_INTEGER *match,
  8.     // null indicators
  9.     SQLUDF_NULLIND *pattern_ind,  SQLUDF_NULLIND *str_ind,
  10.     SQLUDF_NULLIND *match_ind,
  11.     SQLUDF_TRAIL_ARGS)
  12. {
  13.     pcre *re = NULL;
  14.     const char *error = NULL;
  15.     int errOffset = 0;
  16.     int rc = 0;

  17.     // we assume successful return
  18.     *match_ind = 0;

  19.     // compile the pattern to its internal representation
  20.     re = pcre_compile(pattern, 0 /* default options */, &error,
  21.         &errOffset, NULL);
  22.     if (re == NULL) {
  23.         snprintf(SQLUDF_MSGTX, 70, "Regexp compilation failed at "
  24.             "offset %d: %s\n", errOffset, error);
  25.         strcpy(SQLUDF_STATE, "38900");
  26.         (*pcre_free)(re);
  27.         return;
  28.     }

  29.     // match the string againts the pattern
  30.     rc = pcre_exec(re, NULL, str->data, str->length, 0,
  31.             0 /* default options */, NULL, 0);
  32.     switch (rc) {
  33.       case PCRE_ERROR_NOMATCH:
  34.         *match = 0;
  35.         break;
  36.       case PCRE_ERROR_BADOPTION:
  37.         snprintf(SQLUDF_MSGTX, 70, "An unrecognized bit was set in the "
  38.             "options argument");
  39.         strcpy(SQLUDF_STATE, "38901");
  40.         break;
  41.       case PCRE_ERROR_NOMEMORY:
  42.         snprintf(SQLUDF_MSGTX, 70, "Not enough memory available.");
  43.         strcpy(SQLUDF_STATE, "38902");
  44.         break;
  45.       default:
  46.         if (rc < 0) {
  47.             snprintf(SQLUDF_MSGTX, 70, "A regexp match error "
  48.                 "occured: %d", rc);
  49.             strcpy(SQLUDF_STATE, "38903");
  50.         }
  51.         else {
  52.             *match = 1;
  53.         }
  54.         break;
  55.     }

  56.     // cleanup
  57.     (*pcre_free)(re);
  58.     return;
  59. }
复制代码
输入与输出都是放在参数里,返回用VOID.调用如下:
  1. SELECT str
  2. FROM   strTable
  3. WHERE regex1('\w* = (\d|0x00);', str) = 1
复制代码
创建DB2函数的DDL如下:
  1. CREATE FUNCTION regex1(pattern VARCHAR(2048), string CLOB(10M))
  2.     RETURNS INTEGER
  3.     SPECIFIC regexSimple
  4.     EXTERNAL NAME 'regexUdf!regexpSimple'
  5.     LANGUAGE C
  6.     PARAMETER STYLE DB2SQL
  7.     DETERMINISTIC
  8.     NOT FENCED
  9.     RETURNS NULL ON NULL INPUT
  10.     NO SQL
  11.     NO EXTERNAL ACTION
  12.     ALLOW PARALLEL;
复制代码

论坛徽章:
0
5 [报告]
发表于 2010-10-27 18:18 |只看该作者
所以, 原来的TrimChr函数需要改成两个参数,一个是输入,一个是输出.

不过我改了一下,编译时一直有问题,请问有无高人帮改一下.

论坛徽章:
0
6 [报告]
发表于 2010-10-27 21:51 |只看该作者
问题解决了.

C代码如下:
  1. #include        <string.h>
  2. #include        <memory.h>
  3. #include        <sqludf.h>

  4. #define        ISSPACE(x) ((x)==' '||(x)=='\r'||(x)=='\n'||(x)=='\f'||(x)=='\b'||(x)=='\t')

  5. void TrimChr( char *String, char *TrimedString )
  6. {
  7.         char        *Tail, *Head;

  8.         for ( Tail = String + strlen( String ) - 1; Tail >= String; Tail -- )
  9.                 if ( !ISSPACE( *Tail ) )
  10.                         break;
  11.         Tail[1] = 0;
  12.         for ( Head = String; Head <= Tail; Head ++ )
  13.                 if ( !ISSPACE( *Head ) )
  14.                         break;
  15.         if ( Head != String )
  16.                 memcpy( String, Head, ( Tail - Head + 2 ) * sizeof( char ) );
  17.         
  18.         strcpy(TrimedString, String);
  19.         return;
  20. }
复制代码
这段代码是借鉴FH的这个贴子的:
http://bbs.chinaunix.net/viewthread.php?tid=277036

编译命令如下:
  1. cc -c -o TrimChr.o -I ~/sqllib/include TrimChr.c -D_REENTRANT
  2. cc -o TrimChr -shared -fpic TrimChr.o
复制代码
请用db2inst1用户编译,编译成功后,将可执行文件COPY到 ~/sqllib/function/下,即/home/db2inst1/sqllib/function/下.
  1. cp TrimChr ~/sqllib/function/
复制代码
最后到数据库中创建自定义函数:
  1. --DROP FUNCTION TrimChr;

  2. CREATE FUNCTION TrimChr (VARCHAR(400))
  3.                            RETURNS VARCHAR(400)  
  4.                            EXTERNAL NAME '/home/db2inst1/sqllib/function/TrimChr!TrimChr'
  5.                            LANGUAGE C  
  6.                            NULL CALL  
  7.                            PARAMETER STYLE DB2SQL  
  8.                            NO SQL  
  9.                            DETERMINISTIC  
  10.                            NO EXTERNAL ACTION
  11.                            NOT FENCED;

  12. GRANT EXECUTE ON FUNCTION TRIMCHR(VARCHAR(400)) TO PUBLIC;
复制代码
然后就可以直接使用此函数了:
  1. values TrimChr('                 aaa          bbb                          ');
复制代码
本人不懂C,主要是不断的查资料,不断的做实验而成功的.

在此还要请假一个问题:
定义宏使用了如下语句:
  1. #define        ISSPACE(x) ((x)==' '||(x)=='\r'||(x)=='\n'||(x)=='\f'||(x)=='\b'||(x)=='\t')
复制代码
能否用ASCII码代替"\t","\f"这些?因为我想将宏改成所有ASCII码在0~32之间的值.

论坛徽章:
0
7 [报告]
发表于 2010-10-28 19:32 |只看该作者
本帖最后由 nees 于 2010-10-28 19:36 编辑

笨办法:
  1. #define        ISSPACE(x) ((x)==0x00 ||(x)==0x01 ||(x)==0x02 ||(x)==0x03 ||(x)==0x04 ||(x)==0x05 ||(x)==0x06 ||(x)==0x07 ||(x)==0x08 ||(x)==0x09 ||(x)==0x0A ||(x)==0x0B ||(x)==0x0C ||(x)==0x0D ||(x)==0x0E ||(x)==0x0F ||(x)==0x10 ||(x)==0x11 ||(x)==0x12 ||(x)==0x13 ||(x)==0x14 ||(x)==0x15 ||(x)==0x16 ||(x)==0x17 ||(x)==0x18 ||(x)==0x19 ||(x)==0x1A ||(x)==0x1B ||(x)==0x1C ||(x)==0x1D ||(x)==0x1E ||(x)==0x1F ||(x)==0x20 )
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP