⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 manual_adding_functions.html

📁 详细介绍了MYSQL的主要功能几一些代码
💻 HTML
📖 第 1 页 / 共 2 页
字号:
{
    strcpy(message,"XXX() requires a string and an integer");
    return 1;
}
</pre>
    <p>作为另一种要求你的函数的参数类型是特定类型的选择,你可以使用初始化函数设置<code>arg_type</code>成员是你想要的类型。这导致<strong>MySQL</strong>为每个<code>xxx()</code>调用强制参数为那些类型,例如,为了指定头 
    2个参数到字符串和整数的强制,在<code>xxx_init()</code>中做这些:</p>
    <pre>args-&gt;arg_type[0] = STRING_RESULT;
args-&gt;arg_type[1] = INT_RESULT;
</pre>
  </dd>
  <dt><code>char **args</code> </dt>
  <dd><code>args-&gt;args</code>将关于你的函数用它调用的参数的一般特性的信息传递到初始化函数。对一个常数参数<code>i</code>,<code>args-&gt;args[i]</code>指向参数值。(见下面关于如何正确存取值的指令) 
    对一个非常数的参数,<code>args-&gt;args[i]</code>是<code>0</code>。一个常数参数只是使用常数的一个表达式,例如<code>3</code>或<code>4*7-2</code>或<code>SI(3.14)</code>。一个非常数参数是引用可能每行不同的值的一个表达式,例如列名字或用非常数参数调用的函数。对主函数的每次调用,<code>args-&gt;args</code>包含对当前正在处理的行所传递的实际参数。函数可以如下地引用一个参数<code>i</code>:<ul>
      <li>一个<code>STRING_RESULT</code>类型的参数由一个字符串指针加一个长度给出,允许处理任意的长度的二进制的数据或数据。字符串内容可由<code>args-&gt;args[i]</code>得到并且字符串长度是<code>args-&gt;lengths[i]</code>。你不应该假设字符串是以空(null)结束的。</li>
      <li>对于一个<code>INT_RESULT</code>类型的参数,你必须强制转换<code>args-&gt;args[i]</code>为一个<code>long 
        long</code>值: <pre>long long int_val;
int_val = *((long long*) args-&gt;args[i]);
</pre>
      </li>
      <li>对一个<code>REAL_RESULT</code>类型的参数,你必须强制转换<code>args-&gt;args[i]</code>为一个<code>double</code>值: 
        <pre>double    real_val;
real_val = *((double*) args-&gt;args[i]);

</pre>
      </li>
    </ul>
  </dd>
  <dt><code>unsigned long *lengths</code> </dt>
  <dd>对初始化函数,<code>lengths</code>数组指出每个参数的最大字符串长度。对于主函数调用,<code>lengths</code>包含为当前正在被处理的行传递的任何字符串参数的实际长度。对<code>INT_RESULT</code>或<code>REAL_RESULT</code>类型的参数,<code>lengths</code>仍然包含参数的最大长度(就象对初始化函数)。 
  </dd>
</dl>

<h3><a NAME="UDF_return_values" HREF="manual_toc.html#UDF_return_values">14.1.3 
返回值和出错处理</a></h3>

<p>如果没有出现错误,初始化函数应该返回<code>0</code>,否则返回<code>1</code>。如果发生一个错误,<code>xxx_init()</code>应该在<code>message</code>参数中存储一条空字符结束的错误消息,消息将被返回给客户。消息缓冲区是<code>MYSQL_ERRMSG_SIZE</code>个字符长,但是你应该试着保持消息不到80个字符以便它适合一幅标准终端屏幕的宽度。</p>

<p>对<code>long long</code>和<code>double</code>函数,主函数<code>xxx()</code>的返回值是函数值。对字符串函数,字符串在<code>result</code>和<code>length</code>参数中被返回。<code>result</code>是至少255个字节长的一个缓冲区,设置这些为返回值的内容和长度。例如:</p>

<pre>memcpy(result, &quot;result string&quot;, 13);
*length = 13;
</pre>

<p>字符串函数返回值也通常指向结果。</p>

<p>为了在主函数中表明一个<code>NULL</code>返回值,设定<code>is_null</code>为<code>1</code>:</p>

<pre>*is_null = 1; 
</pre>

<p>为了在函数中表明一个错误返回,设定<code>error</code>参数<code>为1</code>: 
</p>

<pre>*error = 1; 
</pre>

<p>如果对任何行<code>xxx()</code>设置<code>*error</code>为<code>1</code>,对当前行函数值是<code>NULL</code>,并且在该语句中处理的后续行,<code>XXX()</code>被调用。(<code>xxx()</code>甚至将不为随后的行被调用。)<strong>注意:</strong>在<strong>MySQL</strong> 
3.22.10以前的版本中,你应该都设置<code>*error</code>和<code>*is_null</code>:</p>

<pre>*error = 1;
*is_null = 1;
</pre>

<h3><a NAME="UDF_compiling" HREF="manual_toc.html#UDF_compiling">14.1.4 
编译并安装用户定义函数</a></h3>

<p>实现UDF的文件必须在服务器运行的主机上被编译并且安装。这个过程下面描述,UDF例子文件包含在<strong>MySQL</strong>源代码分发的<tt>“udf_example.cc”</tt>中,这个文件包含下列函数: 

<ul>
  <li><code>metaphon()</code>返回字符串参数的一个变音位(metaphon)字符串。这有点象一个soundex字符串,但是它更针对英语音调。</li>
  <li><code>myfunc_double()</code>返回在其参数中所有字符的ASCII值的和,除以其参数长度之和。</li>
  <li><code>myfunc_int()</code>返回其参数长度之和。 </li>
  <li><code>lookup()</code>返回对主机名的IP数。</li>
  <li><code>reverse_lookup()</code>返回对一个IP数的主机名。函数可以以一个字符串<code>&quot;xxx.xxx.xxx.xxx&quot;</code>或4位数字被调用。</li>
</ul>

<p>一个可动态装载的文件应该编译为一个共享的对象文件,使用象这样的命令:</p>

<pre>shell&gt; gcc -shared -o udf_example.so myfunc.cc
</pre>

<p>通过运行在你的<strong>MySQL</strong>源代码树的<tt>“sql”</tt>目录下的下列命令,你能很容易地找出对你的系统正确的编译器选项:</p>

<pre>shell&gt; make udf_example.o
</pre>

<p>你应该运行一个类似于<code>make</code>显示的编译命令,除了你应该删除接近行结尾的<code>-c</code>选项并且在行最后增加<code>-o 
udf_example.so</code>。(在一些系统上,你可能需要在命令上保留<code>-c</code>。)</p>

<p>一旦你编译了包含UDF 
的一个共享对象,你必须安装它并且把它告诉<strong>MySQL</strong>。自<tt>“udf_example.cc”</tt>编译一个共享对象产生一个名字类似<tt>“udf_example.so”</tt>的文件(准确的名字可以依平台不同而不同)。拷贝这个文件到被某个<code>ld</code>寻找的目录,例如<tt>“/usr/lib”</tt>。在许多系统上,你能设定<code>LD_LIBRARY</code>或<code>LD_LIBRARY_PATH</code>环境变量,指向有UDF函数文件的目录。<code>dopen</code>手册页告诉你你应该在你的系统上使用哪个变量。你应该在<code>mysql.server</code>或<code>safe_mysqld</code>中设置它并且重启<code>mysqld</code>。</p>

<p>在库被安装以后,用这些命令通知<code>mysqld</code>有关新的函数的信息:</p>

<pre>mysql&gt; CREATE FUNCTION metaphon RETURNS STRING SONAME &quot;udf_example.so&quot;;
mysql&gt; CREATE FUNCTION myfunc_double RETURNS REAL SONAME &quot;udf_example.so&quot;;
mysql&gt; CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME &quot;udf_example.so&quot;;
mysql&gt; CREATE FUNCTION lookup RETURNS STRING SONAME &quot;udf_example.so&quot;;
mysql&gt; CREATE FUNCTION reverse_lookup RETURNS STRING SONAME &quot;udf_example.so&quot;;
</pre>

<p>函数可使用<code>DROP FUNCTION</code>删除:</p>

<pre>mysql&gt; DROP FUNCTION metaphon;
mysql&gt; DROP FUNCTION myfunc_double;
mysql&gt; DROP FUNCTION myfunc_int;
mysql&gt; DROP FUNCTION lookup;
mysql&gt; DROP FUNCTION reverse_lookup;
</pre>

<p><code>CREATE FUNCTION</code>和<code>DROP FUNCTION</code>语句在<code>mysql</code>数据库中更新系统表<code>func</code>。函数名、类型和共享库名被保存在该表中。你必须有对<code>mysql</code>的<strong>insert</strong>和<strong>delete</strong>权限以创建和抛弃函数。</p>

<p>你不应该使用<code>CREATE FUNCTION</code>增加一个已经被创建的函数。如果你需要重新安装函数,你应该用<code>DROP 
FUNCTION</code>删除它,然后用<code>CREATE FUNCTION</code>重新安装它。你将需要这样做,例如,如果你重新编译你的函数的一个新版本,以便<code>mysqld</code>获得新版本,否则服务器将继续使用旧版本。</p>

<p>活跃函数在每次服务器启动时再次装载,除非你使用<code>--skip-grant-tables</code>选项启动<code>mysqld</code>。在这种情况下,UDF初始化被跳过并且UDF不可用。(活跃函数是一个用<code>CREATE 
FUNCTION</code>装载并且没有用<code>DROP FUNCTION</code>删除的函数。) </p>

<p><a NAME="IDX677"></a> <a NAME="IDX678"></a> <a NAME="IDX679"></a> </p>

<h2><a NAME="Adding_native_function" HREF="manual_toc.html#Adding_native_function">14.2 
增加一个新的原生函数</a></h2>

<p>增加一个新的原生函数的过程在下面描述。注意,你不能往一个二进制分发中加入新函数,因为该过程涉及修改<strong>MySQL</strong>源代码。你必须从源代码分发自行编译<strong>MySQL</strong>。也要注意,如果你迁移到<strong>MySQL</strong>的其他版本(例如,当一个新版本被释放时),你将需要用新版本重复该过程。</p>

<p>为了加入一个新的原生<strong>MySQL</strong>函数,遵循这些步骤: 

<ol>
  <li>在<tt>“lex.h”</tt>加入1行,它在<code>sql_functions[]</code>数组中定义函数名。 
  </li>
  <li>在<tt>“sql_yacc.yy”</tt>加入2行。一行指出示<code>yacc</code>应该定义的预处理器符号(这应该加在文件的开始),然后定义函数参数并且将一个具有这些参数“项目”加到<code>simple_expr</code>语法分析规则中。有一个例子,检查在<tt>“sql_yacc.yy 
    </tt>所有的<code>SOUNDEX</code>出现看看它使怎样做的。</li>
  <li>在<tt>“item_func.h”</tt>中,声明一个继承<code>Item_num_func</code>或<code>Item_str_func</code>的类,取决于你的函数是返回一个数字或是一个字符串。</li>
  <li>在<tt>“item_func.cc”</tt>,增加下列声明之一,取决于你是正在定义一个数字或是字符串函数: 
    <pre>double   Item_func_newname::val()
longlong Item_func_newname::val_int()
String  *Item_func_newname::Str(String *str)
</pre>
  </li>
  <li>你也可能应该定义下列函数:<pre>void Item_func_newname::fix_length_and_dec()
</pre>
    <p>这个函数至少应该基于给定的参数计算<code>max_length</code>,<code>max_length</code>是函数可以返回的字符的最大数目。如果主函数不能返回一个<code>NULL</code>值,这个函数也应该设置<code>maybe_null 
    = 0</code>。函数可以通过检查参数的<code>maybe_null</code>变量以便检查函数参数的任何一个是否能返回<code>NULL</code>。</p>
  </li>
</ol>

<p>所有函数必须是线程安全的(thread-safed)。 </p>

<p>对字符串函数,已知有一些额外的考虑: 

<ul>
  <li><code>String *str</code>参数提供一个可以用来保存结果的字符串缓冲区。 
  </li>
  <li>函数应该返回保存结果的字符串。</li>
  <li>所有的当前字符串函数试图避免分配任何内存,除非绝对必要!</li>
</ul>

<hr>

<p><a HREF="manual_Introduction.html">第一章</a>, <a HREF="manual_Maintenance.html">前一章</a>, 
<a HREF="manual_Adding_procedures.html">下一章</a>, <a HREF="manual_Concept_Index.html">最后一章</a>,<a HREF="manual_toc.html">目录</a>. </p>
</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -