所以我创建了一个接受 2 个字符串并连接它们的 UDF。
我的 UDF://concat_kv.c
#include <my_global.h>
#include <my_sys.h>
#include <mysql.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
typedef unsigned long ulong;
my_bool concat_kv_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
if(args->arg_count != 2 || args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT) {
strcpy(message, "concat_kv(): Requires 2 string parameters: Key - Value.");
return 1;
}
return 0;
}
char *concat_kv(UDF_INIT *initid, UDF_ARGS *args, char *result, ulong *length, char *is_null, char *error) {
char *key = (char*)calloc(strlen(args->args[0]), sizeof(char));
char *value = (char*)calloc(strlen(args->args[1]), sizeof(char));
char *res = (char *)calloc(strlen(args->args[0]) + strlen(args->args[1]) + 2, sizeof(char));
int len = strlen(args->args[0]) + strlen(args->args[1]) + 2;
key = args->args[0];
value = args->args[1];
strcat(res, key);
strcat(res, " ");
strcat(res, value);
res[len-1] = '\0'; // Terminating character...
return res;
}
void concat_kv_deinit(UDF_INIT *initid) {
}
编译文件为:
gcc $(mysql_config --cflags) -shared concat_kv.c -o concat_kv.so
将 concat_kv.so 文件移动到 /usr/lib/mysql/plugins/。
在 mysql 中创建函数为:
CREATE FUNCTION concat_kv RETURNS STRING SONAME 'concat_kv.so';
然后做:
SELECT concat_kv("Aditya", "Singh") as conc;
预期输出:
| conc |
--------
| "Aditya Singh" |
但是得到了意想不到的输出:
mysql> SELECT concat_kv("Aditya", "Singh") as conc;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| conc
|
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Aditya Singh �T
|+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.01 sec)
我在连接字符串后得到一些不可打印的东西。一些垃圾值附加在字符串之后。
最佳答案
您的 concat_kv 函数应该看起来更像这样:
char *concat_kv(UDF_INIT *initid, UDF_ARGS *args, char *result, ulong *length, char *is_null, char *error) {
char *key = args->args[0];
char *value = args->args[1];
strcpy(result, key);
strcat(result, " ");
strcat(result, value);
*length = strlen(result);
return result;
}
一些说明:
结果参数应该用于结果
应返回长度
长度应该是没有终止空字符,见这里:https://dev.mysql.com/doc/refman/8.0/en/udf-return-values.html
key 和 value 只是从 args 中使用并通过 strcpy/strcat 复制到结果中
演示
动态内存分配
正如评论中已经指出的那样,如果超出预分配缓冲区的大小,则存在缓冲区溢出的危险。
内存泄漏
如果我们要在 concat_kv() 中动态分配内存,我们会引入内存泄漏,因为每次调用用户定义的函数时都会请求内存,并且永远不会再次释放。
解决方案是使用concat_kv_init()和concat_kv_deinit()函数,MySQL在concat_kv()调用前后直接调用这两个函数。
这里引用 MySQL 文档:
MySQL passes a buffer to the xxx() function using the result parameter. This buffer is sufficiently long to hold 255 characters, which can be multibyte characters. The xxx() function can store the result in this buffer if it fits, in which case the return value should be a pointer to the buffer. If the function stores the result in a different buffer, it should return a pointer to that buffer.
If your string function does not use the supplied buffer (for example, if it needs to return a string longer than 255 characters), you must allocate the space for your own buffer with malloc() in your xxx_init() function or your xxx() function and free it in your xxx_deinit() function.
参见 https://dev.mysql.com/doc/refman/8.0/en/udf-return-values.html
动态内存分配示例
所以如果我们不能保证结果的大小大于预分配的缓冲区,我们需要在 concat_kv_init() 中分配内存并在 concat_kv_deinit() 中释放它。
my_bool concat_kv_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
if(args->arg_count != 2 || args->arg_type[0] != STRING_RESULT || args->arg_type[1] != STRING_RESULT) {
strcpy(message, "concat_kv(): Requires 2 string parameters: Key - Value.");
return 1;
}
ulong length = strlen(args->args[0]) + strlen(args->args[1]) + 2;
initid->ptr = (char *)malloc(length);
return 0;
}
char *concat_kv(UDF_INIT *initid, UDF_ARGS *args, char *result, ulong *length, char *is_null, char *error) {
char *key = args->args[0];
char *value = args->args[1];
strcpy(initid->ptr, key);
strcat(initid->ptr, " ");
strcat(initid->ptr, value);
*length = strlen(initid->ptr);
return initid->ptr;
}
void concat_kv_deinit(UDF_INIT *initid) {
free(initid->ptr);
initid->ptr = NULL;
}
关于MySQL UDF 使用附加到返回字符串的垃圾字符进行响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56030546/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)