第27章:扩展MySQL

27.1. MySQL内部控件

    本章包含许多在你处理MySQL代码时需要了解的你事情。如果你想投入到MySQL的开发中,或想要接触到最新的中间版本的代码,或者就是想了解开发的进度,请参阅2.8.3节,“从开发源代码树安装”的说明。如果你对MySQL的内部插件感兴趣,你也可以订阅我们的内部插件邮件列表。这个列表的流量相对低一些。欲知如何订阅的详情,请参阅1.7.1.1节,“MySQL邮件列表”。在MySQL AB 的所有开发人员都在内部插件列表里, 此外,我们帮助那些正在处理MySQL代码的人。请随意使用这个邮件列表来问代码有关的问题,也可用它来发送你想奉献给MySQL项目的 补丁!

27.1.1. MySQL线程

    MySQL服务器创建如下线程:

  • TCP/IP 连接线程处理所有连接请求,并为每一个连接创建一个新的专用线程来处理认证和SQL查询处理。

  • Windows NT 平台上有一个名为管道处理程序(pipe handler)的线程,它和名为管道连接请求(pipe connect requests)的TCP/IP连接线程做同样的工作。

  • 信号线程处理所有的信号,这个线程通常也处理报警和调用process_alarm() 函数来强制使得空闲时间太长的连接超时。

  • mysqld是与DUSE_ALARM_THREAD线程一起编译的,这个专用线程是处理 创建的警报的。这个线程用在一些sigwait()函数有问题的系统上,或者用在你想在应用程序中使用thr_alarm()代码而不带专用信号处理线程之时。

  • 若想使用flush_time=val选项,会创建一个专用线程以给定的时间间隔刷新所有表格。

  • 每个连接都有它自己的线程。

  • 每个被使用INSERT DELAYED 的不同表格都会有自己的线程。

  • 若使用了master-host, 则会创建一个从属的复制线程从主线程读取并实施更新。

mysqladmin processlist 仅显示连接,INSERT DELAYED, 及复制线程

27.1.2. MySQL测试套件

     包含在Unix源码和二进制分发版中的测试系统可以让用户和开发人员对MySQL代码施行回归测试。这些测试可以在Unix上进行,目前它们还不能在原生的Windows环境下进行。

      当前的测试案例套件不能在MySQL中测试所有东西,但是它能发现SQL处理代码,OS/library文件中大多数明显的缺陷,并且在测试复件方面也是非常彻底的。我们的终极目标是对100%的代码进行测试。我们欢迎大家给我们的测试套件添加内容。你可能会特别想贡献出那些检查你系统里功能性危机的测试,因为这将确保未来所有发行版的MySQL会与你的应用程序一起更好地运行。

27.1.2.1. 运行MySQL测试套件

    测试系统包括一个测试语言解释器(mysqltest),一个运行所有测试的外壳脚本(mysql-test-run),用专用语言编写的测试案例,以及它们的预期结果。在系统上编译好之后,在源代码的root下键入make test 或mysql-test/mysql-test-run。如果安装了一个二进制分发版, cd 到安装root (如 /usr/local/mysql), 然后键入 scripts/mysql-test-run。所有测试应该都通过,假使有没通过的,若是一个MySQL里的缺陷,你可以试着找找是因为什么,并且报告这个问题。请参阅27.1.2.3节,“在MySQL测试套件里报告缺陷”

如果你想要运行测试套件的机器上已经运行了一个 mysqld ,只要它不占用9306 和 9307端口,就不用停掉它。如果占用了其中的一个,以可以编辑mysql-test-run把主端口和(或)从端口号改为其它可用的。.

可使用下面指令运行单个测试案例 mysql-test/mysql-test-run test_name.

若一个测试未通过,你可以用--force选项来检查运行着的mysql-test-run看是否是别的测试未通过

27.1.2.2. 扩展MySQL测试套件

你可以用mysqltest 语言编写你自己的测试案例。不幸地是,我们还没有写完相关方面完整地文档。但是,你可以查看我们现有的测试案例,并将它们作为范例。下面几点将有助于你入手:

  • 测试位于 mysql-test/t/*.test

  • 测试案例包括终止声明,测试案例类似于mysql命令行客户端的输入。 默认的声明是一个被发送到MySQL服务器的查询,除非这个声明被识别为内部命令(如 sleep)。

  • 所有产生结果的查询,例如SELECT, SHOW, EXPLAIN等,必须在 @/path/to/result/file之前。那个文件必须包含期望的结果。生成结果文件的一个简单办法是在mysql-test目录运行mysqltest -r < t/test-case-name.test ,然后编辑生成的结果文件,如果需要,可将它们调整到想要的输出端。在那种情况下,要小心避免添加或删除任何不可见的字符,确保只改变文本和(或)删除行。如果插入一行,要确保插入的区域被一个硬标识隔开,且在行尾有一个硬标识。你可能会想要使用od -c来确保你的文本编辑器在编辑 步骤中没有搞乱任何东西。当你发现一个缺陷而不得不编辑mysqltest -r的输出时,我们真希望你不要编辑它。

  • 为和我们的设置一致,你应该把你的结果文件放在mysql-test/r 目录,并取名为test_name.result。如果测试产生不止一个结果,你应该使用诸如 test_name.a.result,test_name.b.result等这样的名字。

  • 如果声明返回一个错误,你可以在声明的前一行使用--error error-number来详细说明它。错误号可能是由“,”分开的可能错误号的列表。

  • 如果你正编写一个重复的测试案例,你应该在测试文件的第一行写:source include/master-slave.inc;。用connection master; 和 connection slave;来切换主案例和从案例。如果你需要对一个替换的连接做点什么,对于主连接,用connection master1;,对于从连接,用connection slave1;。

  • 如果需要在一个循环里做点什么,可以用些这样的内容:

    let $1=1000;
    while ($1)
    {
     # do your queries here
     dec $1;
    }
    
  • 在查询之间休眠,使用sleep命令。此命令支持几分之几秒,所以,例如你想要休眠1.3秒,你可以使用sleep 1.3; 命令

  • 对你的测试案例要运行带附加选项的从案例,以命令行方式把它们放在mysql-test/t/test_name-slave.opt。对于主案例,把它们放在mysql-test/t/test_name-master.opt。

  • 如果对测试套件有问题,和想要献出一个测试案例,发送邮件信息到MySQL 内部插件 邮件列表。请参阅1.7.1.1节,“MySQL邮件列表”。 虽然这个列表不接受附件,你可以把相关文件通过ftp上传到:ftp://ftp.mysql.com/pub/mysql/upload/

27.1.2.3. 在MySQL测试套件中报告缺陷

如果你的MySQL的版本没有通过测试套件,你可以采取如下措施:

  • 在尽可能多地找到出错之时的错误之前,不要发送缺陷报告。查找之时,请使用mysqlbug脚本比便我们能获取你的系统和MySQL版本信息,参阅1.7.1.3节 ,“如何报告缺陷或问题

  • 确保包含了mysql-test-run的输出,以及  mysql-test/r目录下所有.reject文件的内容。

  • 如果测试套件里的测试未通过,用如下命令检查一下看它自己运行时是否通过测试:

    cd mysql-test
    mysql-test-run --local test-name
    

    如果未能通过,你应该用 --with-debug 配置MySQL并使用--debug选项来运行mysql-test-run。如果这样也未能通过,请把追踪文件var/tmp/master.trace 上传到 ftp://ftp.mysql.com/pub/mysql/upload/ 以便我们能检查它。请记得也要包含你系统的完整描述,mysqld 二进制文件的版本,以及你是如何编译它的。

  • 也试着带--force选项运行一下mysql-test-run ,看是否还有别的测试未通过。

  • 如果你是自己编译的MySQL,查看我们的手册看看如何在你的平台上编译MySQL,最好用一个在http://dev.mysql.com/downloads/上我们已经为你编译好的二进制版本。我们所有标准的二进制版本都能通过测试套件的测试!

  • 如果错误是Result length mismatch 或 Result content mismatch ,这意味测试的输出于期望的输出不匹配,这可能是在MySQL或你的mysqld 版本里的缺陷在某些环境下产生稍有不同的结果。

    未通过的测试结果放在和结果文件同主名但扩展名为.reject的文件里。如果测试案例未通过,你应该对两个文件做diff操作。如果你不能发现它们是如何不同,用od -c 命令检查它们,也检查一下文件长度。

  • 如果测试完全未通过,你应该检查mysql-test/var/log目录下的日志文件以获得有关错误的一些提示。

  • 如果你是为调试而编译MySQL,试一下带--gdb和(或)--debug参数运行mysql-test-run 。请参阅E.1.2节,“创建跟踪文件”

    如果你没有为调试而编译MySQL,这应该是你可能去做的。只要带--with-debug参数运行configure。 请参阅2.8节,“使用源码分发版安装MySQL ”

27.2. 为MySQL添加新函数

有两个途径来为MySQL添加新函数:

  • 你可以通过自行医函数接口 (UDF)来添加函数。自定义函数被编译为目标文件,然后用CREATE FUNCTION 和DROP FUNCTION 声明动态地添入到服务器中及从服务器中移出。参阅27.2.2节,“CREATE FUNCTION/DROP FUNCTION 语法”

  • 你可以将函数添加为MySQL固有(内建)函数。固有函数被编译进mysqld服务器中,成为永久可用的。

每种途径都有其优点和缺点:

  • 如果你编写自定义函数,你除了安装服务器本身之外还要安装目标文件。如果将你的函数编译进服务器中,你就不需要这么做了。

  • 你可以给二进制版本的MySQL分发版添加UDF。固有函数需要你去修正源码分发版。.

  • 如果你升级你的MySQL分发版,你可以继续使用先前安装了的UDF, 除非你升级到一个UDF接口改变了的新版本。对固有函数而言,每次升级你都必须重复一次修正。

无论你使用哪种方法去添加新函数,它们都可以被SQL声明调用,就像 ABS() 或 SOUNDEX()这样的固有函数一样。

另一个添加函数的方法时创建存储函数。这些函数时用SQL声明编写的,而不是编译目标代码。编写存储函数的语法在第20章:存储程序和函数 中描述。

下面的小节描述UDF接口的特性,给出编写UDF的指令,并讨论MySQL为防止UDF被误用而采取的安全预防措施。

给出源代码的例子来说明如何编写UDF,看一看MySQL源码分发版中提供的sql/udf_example.cc 文件。

27.2.1. 自定义函数接口的特性

MySQL自定义函数接口有如下特性和功能:

  • 函数能分÷返回字符串,整数或实数。

  • 你可以定义一次作用于一行的简单函数,或作用于多行的组的集合函数。

  • 提供给函数的信息使得函数可以检查传递给它们的参量的数目和类型。

  • 你可以让MySQL在将某参量传递给函数之前强制其为某一类型。

  • 你可以表示函数返回NULL 或发生错误。

27.2.2. CREATE FUNCTION/DROP FUNCTION 语法

CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|INTEGER|REAL}
       SONAME shared_library_name

DROP FUNCTION function_name

一个自定义函数 (UDF)就是用一个象ABS() 或 CONCAT()这样的固有(内建)函数一样作用的新函数去扩展MySQL。

function_name 是 用在SQL声明中以备调用的函数名字。RETURNS 子句说明函数返回值的类型。 shared_library_name 是共享目标文件的基本名,共享目标文件含有实现函数的代码。该文件必须位于一个能被你系统的动态连接者搜索的目录里。

你必须有mysql 数据库的INSERT 权限才能创建一个函数,你必须有mysql 数据库的DELETE权限才能撤销一个函数。这是因为CREATE FUNCTION 往记录函数名字,类型和共享名的mysql.func系统表里添加了一行,而DROP FUNCTION则是从表中删掉这一行。如果你没有这个系统表,你应该运行mysql_fix_privilege_tables脚本来创建一个。请参阅2.10.2节,“升级授权表”

一个有效的函数是一个用CREATE FUNCTION加载且没有用DROP FUNCTION移除的函数。每次服务器启动的时候会重新加载所有有效函数,除非你使用--skip-grant-tables参数启动mysqld。在这种情况下, 将跳过UDF的初始化,UDF不可用。

要了解编写自定义函数的说明,请参阅27.2.3节,“添加新的自定义函数”。要使得UDF机制能够起作用,必须使用C或者C++编写函数,你的系统必须支持动态加载,而且你必须是动态编译的mysqld(非静态)。

一个AGGREGATE函数就像一个MySQL固有的集合(总和)函数一样起作用,比如,SUM或COUNT()函数。要使得AGGREGATE 起作用,你的mysql.func表必须包括一个type列。如果你的mysql.func表没有这一 列,你应该运行mysql_fix_privilege_tables脚本来创建此 列。

27.2.3. 添加新的自定义函数

要使得UDF机制能够起作用,必须使用C或者C++编写函数,你的系统必须支持动态加载。MySQL 源码分发版包括一个sql/udf_example.cc 文件,此文件定义了5个新函数。可以参考这个文件,看UDF是如何调用常规工作。

为了能使用UDF,你需要动态链接mysqld。不要配置MySQL使用--with-mysqld-ldflags=-all-static参数。如果你想使用一个需要从mysqld 访问符号的UDF(例如在使用default_charset_info的sql/udf_example.cc文件中的metaphone函数),你必须使用-rdynamic参数来链接程序(参阅man dlopen)。如果你计划使用UDF, 一个经验法则就是,用with-mysqld-ldflags=-rdynamic设定MySQL,除非你有很好的理由不去这么做。

如果你使用的是预编译分发版的MySQL, 请使用MySQL-Max,其中含有一个动态链接了的服务器,它可以支持动态加载。

对于每个你想要使用在SQL声明中的函数,你应该定义相应的C (或 C++)函数。在下面的讨论中,xxx用来表示范例函数的名字,为了区分使用SQL还是C/C++,xxx()(上标)表示SQL函数调用,xxx()(下标)表示C/C++函数调用。

你为xxx()编写来实现接口的C/C++ 函数如下:

  • xxx() (必有)

    主函数。 这是函数结果被计算的地方。SQL函数数据类型与C/C++函数返回类型的对应关系如下:

    SQL 类型 C/C++ 类型
    STRING char *
    INTEGER long long
    REAL double
  • xxx_init() (可选)

    对xxx()的初始化函数。它可以被用来:

    • 检查传递给xxx()的参量数目。

    • 检查参量是否为必需的类型,或者,除此之外,在主函数被调用的时候告诉MySQL将参量强制为想要的类型。

    • 分配主函数需要的内存。

    • 指定结果的最大长度。

    • 指定(对于REAL 函数)小数的最多位数。

    • 指定结果是否可以为 NULL。

  • xxx_deinit() (可选)

    对xxx()的去初始化函数。它释放初始化函数分配的内存。

当SQL声明调用XXX()时,MySQL调用初始化函数xxx_init(),让它执行必要的设置,比如,检查 参量或分配内存。如果xxx_init() 返回一个错误,SQL声明会退出并给出错误信息,而主函数和去初始化函数并没有被调用。 否则,主函数xxx() 对每一行都被调用一次。所有行都处理完之后,调用去初始化函数xxx_deinit() 执行必要的清除。

对于象SUM()一样工作的集合函数,你也必须提供如下的函数:

  • xxx_clear() (在5.1节中必须)

    对一个新组重置当前集合值为初试集合值,但不插入任何参量。

  • xxx_add() (必须)

    添加参量到当前集合值。

MySQL 按下列操作来处理集合UDF:

  1. 调用 xxx_init() 让集合函数分配它需要用来存储结果的内存。

  2. 按照GROUP BY表达式来排序表。

  3. 为每个新组中的第一行调用xxx_clear()函数。

  4. 为属于同组的每一个新行调用xxx_add()函数。

  5. 当组改变时或每组的最后一行被处理完之后,调用xxx()来获取集合结果。

  6. 重复,以上3-步直到所有行被处理完。

  7. 调用xxx_deinit() 函数去释放UDF分配的内存。.

所有函数必须时线程安全的,这不仅对主函数,对初始化和去初始化函数也一样,也包括集合函数要求的附加函数。这个要求的一个结果就是,你不能分配任何变化的全局或静态变量。如果你需要内存,你可以在xxx_init()函数分配内存,然后在xxx_deinit()函数释放掉。

27.2.3.1. UDF 对简单函数的调用顺序

下面介绍创建简单UDF时需要定义的不同函数。27.2.3节,“添加新的自定义函数”中介绍了MySQL调用这些函数的顺序。

如本节所示,应该说明主函数xxx()。注意返回值和参数会有所不同,这取决于你说明的SQL函数xxx()在CREATE FUNCTION声明中返回的是STRING,INTEGER类型还是REAL类型示:

对于STRING 型函数:

char *xxx(UDF_INIT *initid, UDF_ARGS *args,
          char *result, unsigned long *length,
          char *is_null, char *error);

对于INTEGER型函数:

long long xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);

对于REAL型函数:

double xxx(UDF_INIT *initid, UDF_ARGS *args,
              char *is_null, char *error);

初始化和去初始化函数如下说明:

my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

void xxx_deinit(UDF_INIT *initid);

initid 参数被传递给所有的三个函数。它指向一个UDF_INIT 结构,这个结构被用来在函数之间交换信息。UDF_INIT 结构项跟随着。初始化函数应该给任何它想要改变的项赋值。(要使用项的默认值,就让它不被改变)

  • my_bool maybe_null

    如果xxx() 能返回NULL,xxx_init()应maybe_null 为 1 。如果任一参量被说明了 maybe_null值,其 默认值是1 。

  • unsigned int decimals

    小数位数。默认值是传到主函数的参量里小数的最大位数。(例如,如果函数传递 1.34, 1.345, 和1.3, 那么默认值为,因为1.345 有3位小数。

  • unsigned int max_length

    结果的最大长度。max_length 的默认值因函数的结果类型而异。对字符串函数,默认值是最长参量的长度。对整型函数,默认是21位。对实型函数,默认是13再加上initid->decimals指示的小数位数。(对数字函数,长度包含正负号或者小数点符)。

    如果想返回团值,你可以把max_length 设为从65KB到16MB。这个内存不会被分配,但是如果有临时数据需要存储,这个设置了的值被用来决定使用哪种 列的类型。

  • char *ptr

    函数可以用作本身目的的指针。比如,函数可以用initid->ptr 来在分配了的内存内部通讯。 xxx_init() 应该分配内存,并指派给这个指针:

    initid->ptr = allocated_memory;
    

    在 xxx() 和 xxx_deinit()中,借用 initid->ptr 来使用或分配内存。

27.2.3.2. UDF对集合函数的调用顺序

本节介绍创建集合UDF之时需要定义的不同函数。27.2.3节,“添加新的自定义函数” 介绍了MySQL调用这些函数的顺序。

  • xxx_reset()

    当MySQL在一个新组中发现第一行时调用这个函数。它对这个组重置任何内部总和变量,然后使用给定的UDF_ARGS参量作为内部总和值的第一个值。如下说明 xxx_reset() 函数:

    char *xxx_reset(UDF_INIT *initid, UDF_ARGS *args,
                    char *is_null, char *error);
    

     在MySQL5.1版中UDF接口不需要或不使用xxx_reset()函数,而是使用xxx_clear()函数作为替代。但是如果你想让UDF也能在老版本的服务器上运行,你也可以定义 xxx_reset() 和 xxx_clear() 函数。(如果你使用了这两个函数,xxx_reset()函数在很多情况下可以通过调用函数来内部实现,即调用xxx_clear()函数重置所有变量,然后添加UDF_ARGS参量作为组的第一个值。)

  • xxx_clear()

    当MySQL需要重置总和结果时调用此函数。对每一个新组,在开始之时调用它,但是它也可以被调用来为一个没有匹配行在其中的查询重置值。如下说明xxx_clear():

    char *xxx_clear(UDF_INIT *initid, char *is_null, char *error);
    

    在调用xxx_clear()之前is_null 被设置指向 CHAR(0) 。

    如果发生错误,你可以存储一个值在 error参量指向的变量中。error指向一单字节变量,而不是一个字符串缓冲区。

    xxx_clear() 是MySQL 5.1必须的。

  • xxx_add()

    为同组除了第一行之外,所有的行调用这个函数。你应该用它在UDF_ARGS参量中向内部总和变量加值。.

    char *xxx_add(UDF_INIT *initid, UDF_ARGS *args,
                  char *is_null, char *error);
    

对集合UDF而言xxx() 函数应该用与非集合UDF一样的方法来说明。请参阅27.2.3.1节,“UDF调用简单函数的顺序”

对一个集合UDF,MySQL 在组内所有行被处理之后调用xxx()函数。这里你应该一般不会接触到它的UDF_ARGS参量,但是取而代之地根据内部总和变量返回给你值。

在xxx()中处理的返回值应该用与对非集合UDF一样的方法来操作。请参阅27.2.3.4节,“UDF返回值和错误处理”

xxx_reset() 和 xxx_add() 函数用与非集合UDF一样的方法来处理它们的UDF_ARGS 参量。请参阅27.2.3.3节,“UDF参量处理”

到is_null和error的指针 参量和所有到xxx_reset(), xxx_clear(), xxx_add() 和 xxx()调用一样。你可以用这个来提醒你获取一个错误或无论xxx()是否返回NULL的一个结果。你不能把一个字符串存到*error!error指向单字节变量而不是字符串缓冲区。

*is_null 对每一个组都重置(调用xxx_clear()前), *error 从不重置。

如果 xxx()返回时,*is_null 或 *error 被设置,MySQL返回 NULL作为组函数的结果。

27.2.3.3. UDF参量处理

args 参数指向列着结构元的 UDF_ARGS 结构:

  • unsigned int arg_count

    参量个数。如果你需要你的函数带着某个数目的参量被调用,在初始化函数检查这个值,例如:

    if (args->arg_count != 2)
    {
        strcpy(message,"XXX() requires two arguments");
        return 1;
    }
    
  • enum Item_result *arg_type

    一个指针,对每个参量指向包含类型的一个数列。可能的类型值是STRING_RESULT, INT_RESULT 和 REAL_RESULT。

    要确信一个参量是给定类型的,并且如果不是的话就返回一个错误,请检查初始化函数中的arg_type数列。比如:

    if (args->arg_type[0] != STRING_RESULT ||
        args->arg_type[1] != INT_RESULT)
    {
        strcpy(message,"XXX() requires a string and an integer");
        return 1;
    }
    

    要求你函数的参量是某一类型的另一方法是,使用初始化函数设置arg_type元素为你想要的类型。对所有对xxx()的调用而言,这会导致MySQL强制参量为这些类型。比如,要指定投两个参量强制成字符串和整数,在xxx_init()中分别:

    args->arg_type[0] = STRING_RESULT;
    args->arg_type[1] = INT_RESULT;
    
  • char **args

    args->args 与初始化函数做有关传到你函数的参量的一般情况做通讯。对于常参量i,args->args[i] 指向参量值。(看下面的说明了解如何妥善地访问这个值)。对非-常参量,args->args[i] 为 0。一个常参量为仅使用参量的表达式,如 3 或 4*7-2 或 SIN(3.14)。一个非常 参量是一个行与行不同的表达式,如,列名或带非-常参量调用的函数。

    对主函数的每次调用,args->args 包含为每个当前处理的行传递的实际参量。

    如下使用参量i的函数:

    • 给一个STRING_RESULT 型的参量作为一个字符串加一个长度,可以允许所有二进制数或任意长度的数处理。字符串内容作为args->args[i] 而字符串长度为args->lengths[i]。你不能采用null结尾的字符串。

    • 对一个INT_RESULT型的参量,你必须转换args->args[i] 为一个long long 值:

      long long int_val;
      int_val = *((long long*) args->args[i]);
      
    • 对一个REAL_RESULT型参量,你必须转换args->args[i]为一个双精度值:

      double    real_val;
      real_val = *((double*) args->args[i]);
      
  • unsigned long *lengths

    对初始化函数,lengths数列表示对每个参量的最大字符串长度。你不要改变它。对主函数的每次调用,lengths包含了对当前处理行传递的任何字符串 参量的实际长度。对于INT_RESULT 或 REAL_RESULT类型的参量,lengths 仍包含参量的最大长度(对初始化函数)。

27.2.3.4. UDF返回值和错误处理

如果没有错误发生,初始化函数应该返回0,否则就返回1。如果有错误发生,xxx_init() 应该在message 参数存储一个以null结尾的错误消息。该消息被返回给客户端。消息缓冲区是 MYSQL_ERRMSG_SIZE 字符长度,但你应该试着把消息保持在少于80个字符,以便它能适合标准终端屏幕的宽度。

对于long long 和 double 类型的函数,主函数 xxx()的返回返回值是函数值。字符函数返回一个指向结果的指针,并且设置 *result 和 *length  为返回值的内容和长度。例如:

memcpy(result, "result string", 13);
*length = 13;

被传给 xxx() 函数的结果缓冲区是 255 字节长。如果你的结果适合这个长度,你就不需要担心对结果的内存分配。

如果字符串函数需要返回一个超过255字节的字符串,你必须用 malloc() 在你的 xxx_init() 函数或者 xxx() 函数里为字符串分配空间,并且在 xxx_deinit() 函数里释放此空间。你可以将已分配内存存储在 UDF_INIT  结构里的 ptr  位置以备将来 xxx() 调用。请参阅27.2.3.1节,“UDF 对简单函数的调用顺序”

要在主函数中指明一个 NULL 的返回值,设置 *is_null 为 1 :

*is_null = 1;

要在主函数中指明错误返回,设置 *error 为 1 :

*error = 1;

如果 xxx() 对任意行设置 *error 为 1  ,对于任何 XXX()被调用的语句处理的当前行和随后的任意行,该函数值为 NULL (甚至都不为随后的行调用 xxx())。

27.2.3.5. 编译和安装自定义函数

实现UDF的文件必须在运行服务器的主机上编译和安装。这个步骤在下面介绍,以包含在MySQL源码分发版里的UDF文件sql/udf_example.cc 为例。

紧接着下面的指令是对Unix的,对Windows的指令在本节稍后给出。

 udf_example.cc 文件包含下列函数:

  • metaphon() 返回字符串参量的一个变音位(metaphon)字符串,这有点象一个探测法(soundex)字符串,但是它英语更协调。

  • myfunc_double()返回在其参量中所有字符的ASCII值的和,除以其 参量长度之和。

  • myfunc_int()返回其参量长度之和。

  • sequence([const int]) 返回一个序列,从给定数开始,若没有给定数则从1开始。

  • lookup() 返回对应主机名的IP数。

  • reverse_lookup() 返回对应一个IP数的主机名。函数可以带'xxx.xxx.xxx.xxx'形式的一个单字符串 参量调用,要么带4个数字调用。

一个可动态加载的文件应使用如下这样的命令编译为一个可共享的对象文件:

shell> gcc -shared -o udf_example.so udf_example.cc

如果你使用gcc,你应该能用一个更简单的命令创建udf_example.so :

shell> make udf_example.so

通过运行MySQL源码树下sql里的如下命令,你可以容易地为你的系统决定正确的编译器选项:

shell> make udf_example.o

你应该运行一个类似于make所显示那样的编译命令,除了要在行尾附近删除-c选项,并在行尾加上加上 -o udf_example.so。(在某些系统上,你可能需要在命令行留着-c 选项)。

编译好一个包含有UDF的共享目标后,你必须安装它并通知MySQL。从udf_example.cc编译一个共享目标文件产生一个名字类似于udf_example.so 的文件(确切名字可能因平台而异)。把这个文件复制到 /usr/lib 这样被你系统的动态(运行时)链接器搜索到的目录下,或者 把你放共享目标文件的目录添加到链接器配置文件(如,/etc/ld.so.conf )。

动态链接器的名字时系统特定的(如,在FreeBSD上是ld-elf.so.1 ,在Linux上是 ld.so,在Mac OS X上是dyld )。查看一下你系统的文档,看看链接器的名字是什么及如何配置链接器。

在许多系统上,你也可以设置环境变量LD_LIBRARY 或 LD_LIBRARY_PATH 指向你放UDF的目录。dlopen 手册会告诉你,在你系统上用哪个变量名。你可以在mysql.servermysqld_safe 启动脚本里设置这个然后重启 mysqld

在一些系统上,配置动态链接器的ldconfig不能识别不是以lib做名字开头的共享目标。在这种情况下,你应该把udf_example.so 改名为 libudf_example.so。

在Windows系统上,你可以通过下列步骤编译自定义函数:

  1. 你需要获得BitKeeper source repository for MySQL 5.1。 请参阅 2.8.3节,“从开发源树安装”

  2. 在源数据仓里的VC++Files/examples/udf_example目录下,有名为udf_example.def, udf_example.dsp, 和 udf_example.dsw  的文件。

  3. 在数据仓的sql目录下,复制 udf_example.cc 文件到 VC++Files/examples/udf_example 目录,并改其名为udf_example.cpp。

  4. Visual Studio VC++用打开 udf_example.dsw 文件,用它把UDF编译为一个一般项目。

共享目标文件安装完以后,为新函数信息修改 mysqld ,做如下声明:

mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME 'udf_example.so';
mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME 'udf_example.so';
mysql> CREATE FUNCTION lookup RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE FUNCTION reverse_lookup
    ->        RETURNS STRING SONAME 'udf_example.so';
mysql> CREATE AGGREGATE FUNCTION avgcost
    ->        RETURNS REAL SONAME 'udf_example.so';

可以使用DROP FUNCTION删除函数:

mysql> DROP FUNCTION metaphon;
mysql> DROP FUNCTION myfunc_double;
mysql> DROP FUNCTION myfunc_int;
mysql> DROP FUNCTION lookup;
mysql> DROP FUNCTION reverse_lookup;
mysql> DROP FUNCTION avgcost;

CREATE FUNCTION 和 DROP FUNCTION 声明更新mysql 数据库中的func 系统表。函数名,类型和共享库名存进表中。你必须有mysql 数据库的INSERT 和DELETE 权限来创建和移除函数。

你不能使用 CREATE FUNCTION 去田间一个先前已经被创建的函数。如果你需要重新安装一个函数,你可以用DROP FUNCTION移除它,然后再用CREATE FUNCTION重新安装它。你可能会需要这么做,比如你重新编译新版本的函数以便mysqld得到这个新版本。不然,服务器还继续使用旧的版本。

一个有效程序是已被 CREATE FUNCTION加载且没有被DROP FUNCTION移除的函数。所有有效函数在每次服务器启动时重新加载,除非你使用--skip-grant-tables选项来启动mysqld。这种情况下,UDF的初始化将被跳过,UDF不可用。

27.2.3.6. 自定义函数安全预防措施

MySQL 采取下列措施来防止误用自定义函数。

你必须有 INSERT 权限才能使用 CREATE FUNCTION 及有 DELETE 权限才能使用 DROP FUNCTION。这是很必要的,因为这些声明在mysql.func表里添加合删除行。

除了对应主 xxx()函数的xxx 符号,UDF应该至少定义一个符号。这些辅助符号对应 xxx_init(), xxx_deinit(), xxx_reset(), xxx_clear() 和 xxx_add() 函数。mysqld 也支持一个控制仅有一个xxx符号的UDF是否被加载的--allow-suspicious-udfs。这个选项 默认是关,以防止从共享目标文件而不是从这些已包含的合法UDF加载的企图。如果你有仅含xxx符号的老版本UDF,以及不能重编译来包含辅助符号的老版本UDF,那就有必要选--allow-suspicious-udfs 选项。否则,你应该避免打开这个选项。

UDF 目标文件不能放在任意目录。它们必须位于动态链接器被配置来搜索到的一些系统目录。为强制执行这个限制并防止指定被动态链接器搜索到的目录之外的路径,MySQL在加载函数的时候检查在CREATE FUNCTION 中指定的共享目标文件名,以及存在mysql.func表中的文件的路径分隔符。这防止通过直接操作mysql.func表指定非法路径名。有关UDF和运行时链接器,请参阅27.2.3.5节,“编译和安装自定义函数”

27.2.4. 添加新的固有函数

下面介绍添加新固有函数的步骤。要注意你不能添加固有函数到二进制分发版里,因为这个步骤包含修改MySQL源代码。你必须从源码分发版自己编译MySQL。另外要注意,如果你把MySQL移植到另一个版本(比如新版本放出来的时候),你需要用新版本重复这个添加 步骤。

采取下列步骤来添加MySQL新的固有函数:

  1. 在定义函数名的lex.h文件中的sql_functions[]数列里添加一行。

  2. 如果函数原型是简单的(只有零个,一个,二个或三个参量),你应该在lex.h中指定 SYM(FUNC_ARGN) (其中N 是参量的个数)作为sql_functions[]数列中的第二个 参量,并添加一个在item_create.cc中创建函数目标的函数。可以看看 "ABS" 和 create_funcs_abs() 作为举例说明。

    如果函数原型是复杂的(举例,如果函数有多种参量),你应该给sql_yacc.yy添加两行。一行表示yacc应该定义的预处理程序记号,(这应该在文件的开始添加)。然后定义函数 参数,并添加一个带这些参数的项到simple_expr分析规则中。举一个例子,你可以检查 sql_yacc.yy 中所有出现的ATAN 看看这个定义是什么样子的。

  3. 在 item_func.h中说明一个继承自Item_num_func 还是 Item_str_func的类,取决于你的函数是返回一个数还是一个字符串。

  4. 在 item_func.cc中是否添加下列说明之一,取决于你是定义一个数字函数还是字符函数:

    double   Item_func_newname::val()
    longlong Item_func_newname::val_int()
    String  *Item_func_newname::Str(String *str)
    

    如果你从任何标准项继承了你的目标(类似于Item_num_func),你或许只要定义这些函数中的一个,然后让父目标照管别的函数。比如,Item_str_func 类定义了一个 val() 函数,它这个函数对::str()返回的值进行 atof()操作。

  5. 你或许也定义了下列目标函数:

    void Item_func_newname::fix_length_and_dec()
    

    这个函数至少应该计算基于给定参量的max_length。 max_length 是函数可能返回字符的最大个数。如果主函数不能返回 NULL值,这个函数也应该设置 maybe_null = 0。函数可以通过检查函数的maybe_null值来检查是否有函数 参量能返回NULL值。你可以看一下Item_func_mod::fix_length_and_dec 作为典型的例子来说明这个问题。

所有函数都必须是线程安全的,换句话说就是,如果没有互斥体保护,不要在函数中使用任何全局或静态变量。

如果你想要从函数::val(), ::val_int()或::str()返回NULL,你应该设null_value为1,并返回0。

对于目标函数 ::str() 有一些需要而外考虑之处::

  • 字符串参量*str 提供一个字符串缓冲可以用来保持结果(更多关于字符串类型的信息请参阅 sql_string.h文件)。 

  • 如果结果为NULL,::str() 函数应该返回保持这个结果的字符串或(char*) 0。

  • 除非有绝对地需要,所有当前的字符串函数要避免分配内存!

27.3. 为MySQL添加新步骤

在MySQL中,你可以用C++定义一个步骤,在一个查询被发送到客户端之前访问和修改其中的数据。修改可以一行接一行地做,或者按照级别成组(GROUP)地做。

我们创建一个范例步骤来演示你可以做的。

此外,我们推荐你看一下mylua。通过它你可以用  LUA语言把运行时里的一个 步骤加载到mysqld中。

27.3.1. 步骤分析

analyse([max_elements,[max_memory]])

这个步骤在sql/sql_analyse.cc定义,这个步骤检查你查询的结果,并且返回对此结果的一个分析:

  • max_elements (默认值 256) 是analyse注意到每 列不同值的最高数目。analyse使用此 参数来检查是否最优化的列的类型是ENUM类型。

  • max_memory (默认值 8192) 是analyse在查找所有不同值时分配给每 列的最大内存数。i

SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max_elements,[max_memory]])

27.3.2. 编写步骤

当前来说,相关的文档只有源码。

检查下列文件可以获得关于步骤的所有信息:

  • sql/sql_analyse.cc

  • sql/procedure.h

  • sql/procedure.cc

  • sql/sql_select.cc


这是MySQL参考手册的翻译版本,关于MySQL参考手册,请访问dev.mysql.com。 原始参考手册为英文版,与英文版参考手册相比,本翻译版可能不是最新的。 

目录

前言
1. 一般信息
1.1. 关于本手册
1.2. 本手册采用的惯例
1.3. MySQL AB概述
1.4. MySQL数据库管理系统概述
1.4.1. MySQL的历史
1.4.2. MySQL的的主要特性
1.4.3. MySQL稳定性
1.4.4. MySQL表最大能达到多少
1.4.5. 2000年兼容性
1.5. MaxDB数据库管理系统概述
1.5.1. 什么是MaxDB?
1.5.2. MaxDB的历史
1.5.3. MaxDB的特性
1.5.4. 许可和支持
1.5.5. MaxDB和MySQL之间的特性差异
1.5.6. MaxDB和MySQL之间的协同性
1.5.7. 与MaxDB有关的链接
1.6. MySQL发展大事记
1.6.1. MySQL 5.1的新特性
1.7. MySQL信息源
1.7.1. MySQL邮件列表
1.7.2. IRC(在线聊天系统)上的MySQL社区支持
1.7.3. MySQL论坛上的MySQL社区支持
1.8. MySQL标准的兼容性
1.8.1. MySQL遵从的标准是什么
1.8.2. 选择SQL模式
1.8.3. 在ANSI模式下运行MySQL
1.8.4. MySQL对标准SQL的扩展
1.8.5. MySQL与标准SQL的差别
1.8.6. MySQL处理约束的方式
2. 安装MySQL
2.1. 一般安装问题
2.1.1. MySQL支持的操作系统
2.1.2. 选择要安装的MySQL分发版
2.1.3. 怎样获得MySQL
2.1.4. 通过MD5校验和或GnuPG验证软件包的完整性
2.1.5. 安装布局
2.2. 使用二进制分发版的标准MySQL安装
2.3. 在Windows上安装MySQL
2.3.1. Windows系统要求
2.3.2. 选择安装软件包
2.3.3. 用自动安装器安装MySQL
2.3.4. 使用MySQL安装向导
2.3.5. 使用配置向导
2.3.6. 通过非安装Zip文件安装MySQL
2.3.7. 提取安装档案文件
2.3.8. 创建选项文件
2.3.9. 选择MySQL服务器类型
2.3.10. 首次启动服务器
2.3.11. 从Windows命令行启动MySQL
2.3.12. 以Windows服务方式启动MySQL
2.3.13. 测试MySQL安装
2.3.14. 在Windows环境下对MySQL安装的故障诊断与排除
2.3.15. 在Windows下升级MySQL
2.3.16. Windows版MySQL同Unix版MySQL对比
2.4. 在Linux下安装MySQL
2.5.在Mac OS X中安装MySQL
2.6. 在NetWare中安装MySQL
2.7. 在其它类Unix系统中安装MySQL
2.8. 使用源码分发版安装MySQL
2.8.1. 源码安装概述
2.8.2. 典型配置选项
2.8.3. 从开发源码树安装
2.8.4. 处理MySQL编译问题
2.8.5. MIT-pthreads注意事项
2.8.6. 在Windows下从源码安装MySQL
2.8.7. 在Windows下编译MySQL客户端
2.9. 安装后的设置和测试
2.9.1. Windows下安装后的过程
2.9.2. Unix下安装后的过程
2.9.3. 使初始MySQL账户安全
2.10. 升级MySQL
2.10.1. 从5.0版升级
2.10.2. 升级授权表
2.10.3. 将MySQL数据库拷贝到另一台机器
2.11. 降级MySQL
2.12. 具体操作系统相关的注意事项
2.12.1. Linux注意事项
2.12.2. Mac OS X注意事项
2.12.3. Solaris注意事项
2.12.4. BSD注意事项
2.12.5. 其它Unix注意事项
2.12.6. OS/2注意事项
2.13. Perl安装注意事项
2.13.1. 在Unix中安装Perl
2.13.2. 在Windows下安装ActiveState Perl
2.13.3. 使用Perl DBI/DBD接口的问题
3. 教程
3.1. 连接与断开服务器
3.2. 输入查询
3.3. 创建并使用数据库
3.3.1. 创建并选择数据库
3.3.2. 创建表
3.3.3. 将数据装入表中
3.3.4. 从表检索信息
3.4. 获得数据库和表的信息
3.5. 在批处理模式下使用mysql
3.6. 常用查询的例子
3.6.1. 列的最大值
3.6.2. 拥有某个列的最大值的行
3.6.3. 列的最大值:按组
3.6.4. 拥有某个字段的组间最大值的行
3.6.5. 使用用户变量
3.6.6. 使用外键
3.6.7. 根据两个键搜索
3.6.8. 根据天计算访问量
3.6.9. 使用AUTO_INCREMENT
3.7. 孪生项目的查询
3.7.1. 查找所有未分发的孪生项
3.7.2. 显示孪生对状态的表
3.8. 与Apache一起使用MySQL
4. MySQL程序概述
4.1. MySQL程序概述
4.2. 调用MySQL程序
4.3. 指定程序选项
4.3.1. 在命令行上使用选项
4.3.2. 使用选项文件
4.3.3. 用环境变量指定选项
4.3.4. 使用选项设置程序变量
5. 数据库管理
5.1. MySQL服务器和服务器启动脚本
5.1.1. 服务器端脚本和实用工具概述
5.1.2. mysqld-max扩展MySQL服务器
5.1.3. mysqld_safe:MySQL服务器启动脚本
5.1.4. mysql.server:MySQL服务器启动脚本
5.1.5. mysqld_multi:管理多个MySQL服务器的程序
5.2. mysqlmanager:MySQL实例管理器
5.2.1. 用MySQL实例管理器启动MySQL服务器
5.2.2. 连接到MySQL实例管理器并创建用户账户
5.2.3. MySQL实例管理器命令行选项
5.2.4. MySQL实例管理器配置文件
5.2.5. MySQL实例管理器识别的命令
5.3. mysqld:MySQL服务器
5.3.1. mysqld命令行选项
5.3.2. SQL服务器模式
5.3.3. 服务器系统变量
5.3.4. 服务器状态变量
5.4. mysql_fix_privilege_tables:升级MySQL系统表
5.5. MySQL服务器关机进程
5.6. 一般安全问题
5.6.1. 通用安全指南
5.6.2. 使MySQL在攻击者面前保持安全
5.6.3. Mysqld安全相关启动选项
5.6.4. LOAD DATA LOCAL安全问题
5.7. MySQL访问权限系统
5.7.1. 权限系统的作用
5.7.2. 权限系统工作原理
5.7.3. MySQL提供的权限
5.7.4. 与MySQL服务器连接
5.7.5. 访问控制, 阶段1:连接核实
5.7.6. 访问控制, 阶段2:请求核实
5.7.7. 权限更改何时生效
5.7.8. 拒绝访问错误的原因
5.7.9. MySQL 4.1中的密码哈希处理
5.8. MySQL用户账户管理
5.8.1. MySQL用户名和密码
5.8.2. 向MySQL增加新用户账户
5.8.3. 从MySQL删除用户账户
5.8.4. 限制账户资源
5.8.5. 设置账户密码
5.8.6. 使你的密码安全
5.8.7. 使用安全连接
5.9. 备份与恢复
5.9.1. 数据库备份
5.9.2. 示例用备份与恢复策略
5.9.3. 自动恢复
5.9.4. 表维护和崩溃恢复
5.9.5. myisamchk:MyISAM表维护实用工具
5.9.6. 建立表维护计划
5.9.7. 获取关于表的信息
5.10. MySQL本地化和国际应用
5.10.1. 数据和排序用字符集
5.10.2. 设置错误消息语言
5.10.3. 添加新的字符集
5.10.4. 字符定义数组
5.10.5. 字符串比较支持
5.10.6. 多字节字符支持
5.10.7. 字符集问题
5.10.8. MySQL服务器时区支持
5.11. MySQL日志文件
5.11.1. 错误日志
5.11.2. 通用查询日志
5.11.3. 二进制日志
5.11.4. 慢速查询日志
5.11.5. 日志文件维护
5.12. 在同一台机器上运行多个MySQL服务器
5.12.1. 在Windows下运行多个服务器
5.12.2. 在Unix中运行多个服务器
5.12.3. 在多服务器环境中使用客户端程序
5.13. MySQL查询高速缓冲
5.13.1. 查询高速缓冲如何工作
5.13.2. 查询高速缓冲SELECT选项
5.13.3. 查询高速缓冲配置
5.13.4. 查询高速缓冲状态和维护
6. MySQL中的复制
6.1. 复制介绍
6.2. 复制实施概述
6.3. 复制实施细节
6.3.1. 复制主线程状态
6.3.2. 复制从I/O线程状态
6.3.3. 复制从SQL线程状态
6.3.4. 复制传递和状态文件
6.4. 如何设置复制
6.5. 不同MySQL版本之间的复制兼容性
6.6. 升级复制设置
6.6.1. 将复制升级到5.0版
6.7. 复制特性和已知问题
6.8. 复制启动选项
6.9. 复制FAQ
6.10. 复制故障诊断与排除
6.11. 通报复制缺陷
6.12. 多服务器复制中的Auto-Increment
7. 优化
7.1. 优化概述
7.1.1. MySQL设计局限与折衷
7.1.2. 为可移植性设计应用程序
7.1.3. 我们已将MySQL用在何处?
7.1.4. MySQL基准套件
7.1.5. 使用自己的基准
7.2. 优化SELECT语句和其它查询
7.2.1. EXPLAIN语法(获取SELECT相关信息)
7.2.2. 估计查询性能
7.2.3. SELECT查询的速度
7.2.4. MySQL怎样优化WHERE子句
7.2.5. 范围优化
7.2.6. 索引合并优化
7.2.7. MySQL如何优化IS NULL
7.2.8. MySQL如何优化DISTINCT
7.2.9. MySQL如何优化LEFT JOIN和RIGHT JOIN
7.2.10. MySQL如何优化嵌套Join
7.2.11. MySQL如何简化外部联合
7.2.12. MySQL如何优化ORDER BY
7.2.13. MySQL如何优化GROUP BY
7.2.14. MySQL如何优化LIMIT
7.2.15. 如何避免表扫描
7.2.16. INSERT语句的速度
7.2.17. UPDATE语句的速度
7.2.18. DELETE语句的速度
7.2.19. 其它优化技巧
7.3. 锁定事宜
7.3.1. 锁定方法
7.3.2. 表锁定事宜
7.4. 优化数据库结构
7.4.1. 设计选择
7.4.2. 使你的数据尽可能小
7.4.3. 列索引
7.4.4. 多列索引
7.4.5. MySQL如何使用索引
7.4.6. MyISAM键高速缓冲
7.4.7. MyISAM索引统计集合
7.4.8. MySQL如何计算打开的表
7.4.9. MySQL如何打开和关闭表
7.4.10. 在同一个数据库中创建多个表的缺陷
7.5. 优化MySQL服务器
7.5.1. 系统因素和启动参数的调节
7.5.2. 调节服务器参数
7.5.3. 控制查询优化器的性能
7.5.4. 编译和链接怎样影响MySQL的速度
7.5.5. MySQL如何使用内存
7.5.6. MySQL如何使用DNS
7.6. 磁盘事宜
7.6.1. 使用符号链接
8. 客户端和实用工具程序
8.1. 客户端脚本和实用工具概述
8.2. myisampack:生成压缩、只读MyISAM表
8.3. mysql:MySQL命令行工具
8.3.1. 选项
8.3.2. mysql命令
8.3.3. 怎样从文本文件执行SQL语句
8.3.4. mysql技巧
8.4. mysqlaccess:用于检查访问权限的客户端
8.5. mysqladmin:用于管理MySQL服务器的客户端
8.6. mysqlbinlog:用于处理二进制日志文件的实用工具
8.7. mysqlcheck:表维护和维修程序
8.8. mysqldump:数据库备份程序
8.9. mysqlhotcopy:数据库备份程序
8.10. mysqlimport:数据导入程序
8.11. mysqlshow-显示数据库、表和列信息
8.12. myisamlog:显示MyISAM日志文件内容
8.13. perror:解释错误代码
8.14. replace:字符串替换实用工具
8.15. mysql_zap:杀死符合某一模式的进程
9. 语言结构
9.1. 文字值
9.1.1. 字符串
9.1.2. 数值
9.1.3. 十六进制值
9.1.4. 布尔值
9.1.5. 位字段值
9.1.6. NULL值
9.2. 数据库、表、索引、列和别名
9.2.1. 识别符限制条件
9.2.2. 识别符大小写敏感性
9.3. 用户变量
9.4. 系统变量
9.4.1. 结构式系统变量
9.5. 注释语法
9.6. MySQL中保留字的处理
10. 字符集支持
10.1. 常规字符集和校对
10.2. MySQL中的字符集和校对
10.3. 确定默认字符集和校对
10.3.1. 服务器字符集和校对
10.3.2. 数据库字符集和校对
10.3.3. 表字符集和校对
10.3.4. 列字符集和校对
10.3.5. 字符集和校对分配示例
10.3.6. 连接字符集和校对
10.3.7. 字符串文字字符集和校对
10.3.8. 在SQL语句中使用COLLATE
10.3.9. COLLATE子句优先
10.3.10. BINARY操作符
10.3.11. 校对确定较为复杂的一些特殊情况
10.3.12. 校对必须适合字符集
10.3.13. 校对效果的示例
10.4. 字符集支持影响到的操作
10.4.1. 结果字符串
10.4.2. CONVERT()
10.4.3. CAST()
10.4.4. SHOW语句
10.5. Unicode支持
10.6. 用于元数据的UTF8
10.7. 与其它DBMS的兼容性
10.8. 新字符集配置文件格式
10.9. 国家特有字符集
10.10. MySQL支持的字符集和校对
10.10.1. Unicode字符集
10.10.2. 西欧字符集
10.10.3. 中欧字符集
10.10.4. 南欧与中东字符集
10.10.5. 波罗的海字符集
10.10.6. 西里尔字符集
10.10.7. 亚洲字符集
11. 列类型
11.1. 列类型概述
11.1.1. 数值类型概述
11.1.2. 日期和时间类型概述
11.1.3. 字符串类型概述
11.2. 数值类型
11.3. 日期和时间类型
11.3.1. DATETIME、DATE和TIMESTAMP类型
11.3.2. TIME类型
11.3.3. YEAR类型
11.3.4. Y2K事宜和日期类型
11.4. String类型
11.4.1. CHAR和VARCHAR类型
11.4.2. BINARY和VARBINARY类型
11.4.3. BLOB和TEXT类型
11.4.4. ENUM类型
11.4.5. SET类型
11.5. 列类型存储需求
11.6. 选择正确的列类型
11.7. 使用来自其他数据库引擎的列类型
12. 函数和操作符
12.1. 操作符
12.1.1. 操作符优先级
12.1.2. 圆括号
12.1.3. 比较函数和操作符
12.1.4. 逻辑操作符
12.2. 控制流程函数
12.3. 字符串函数
12.3.1. 字符串比较函数
12.4. 数值函数
12.4.1. 算术操作符
12.4.2. 数学函数
12.5. 日期和时间函数
12.6. MySQL使用什么日历?
12.7. 全文搜索功能
12.7.1. 布尔全文搜索
12.7.2. 全文搜索带查询扩展
12.7.3. 全文停止字
12.7.4. 全文限定条件
12.7.5. 微调MySQL全文搜索
12.8. Cast函数和操作符
12.9. 其他函数
12.9.1. 位函数
12.9.2. 加密函数
12.9.3. 信息函数
12.9.4. 其他函数
12.10. 与GROUP BY子句同时使用的函数和修改程序
12.10.1. GROUP BY(聚合)函数
12.10.2. GROUP BY修改程序
12.10.3. 具有隐含字段的GROUP BY
13. SQL语句语法
13.1. 数据定义语句
13.1.1. ALTER DATABASE语法
13.1.2. ALTER TABLE语法
13.1.3. CREATE DATABASE语法
13.1.4. CREATE INDEX语法
13.1.5. CREATE TABLE语法
13.1.6. DROP DATABASE语法
13.1.7. DROP INDEX语法
13.1.8. DROP TABLE语法
13.1.9. RENAME TABLE语法
13.2. 数据操作语句
13.2.1. DELETE语法
13.2.2. DO语法
13.2.3. HANDLER语法
13.2.4. INSERT语法
13.2.5. LOAD DATA INFILE语法
13.2.6. REPLACE语法
13.2.7. SELECT语法
13.2.8. Subquery语法
13.2.9. TRUNCATE语法
13.2.10. UPDATE语法
13.3. MySQL实用工具语句
13.3.1. DESCRIBE语法(获取有关列的信息)
13.3.2. USE语法
13.4. MySQL事务处理和锁定语句
13.4.1. START TRANSACTION, COMMIT和ROLLBACK语法
13.4.2. 不能回滚的语句
13.4.3. 会造成隐式提交的语句
13.4.4. SAVEPOINT和ROLLBACK TO SAVEPOINT语法
13.4.5. LOCK TABLES和UNLOCK TABLES语法
13.4.6. SET TRANSACTION语法
13.4.7. XA事务
13.5. 数据库管理语句
13.5.1. 账户管理语句
13.5.2. 表维护语句
13.5.3. SET语法
13.5.4. SHOW语法
13.5.5. 其它管理语句
13.6. 复制语句
13.6.1. 用于控制主服务器的SQL语句
13.6.2. 用于控制从服务器的SQL语句
13.7. 用于预处理语句的SQL语法
14. 插件式存储引擎体系结构
14.1. 前言
14.2. 概述
14.3. 公共MySQL数据库服务器层
14.4. 选择存储引擎
14.5. 将存储引擎指定给表
14.6. 存储引擎和事务
14.7. 插入存储引擎
14.8. 拔出存储引擎
14.9. 插件式存储器的安全含义
15. 存储引擎和表类型
15.1. MyISAM存储引擎
15.1.1. MyISAM启动选项
15.1.2. 键所需的空间
15.1.3. MyISAM表的存储格式
15.1.4. MyISAM表方面的问题
15.2. InnoDB存储引擎
15.2.1. InnoDB概述
15.2.2. InnoDB联系信息
15.2.3. InnoDB配置
15.2.4. InnoDB启动选项
15.2.5. 创建InnoDB表空间
15.2.6. 创建InnoDB表
15.2.7. 添加和删除InnoDB数据和日志文件
15.2.8. InnoDB数据库的备份和恢复
15.2.9. 将InnoDB数据库移到另一台机器上
15.2.10. InnoDB事务模型和锁定
15.2.11. InnoDB性能调节提示
15.2.12. 多版本的实施
15.2.13. 表和索引结构
15.2.14. 文件空间管理和磁盘I/O
15.2.15. InnoDB错误处理
15.2.16. 对InnoDB表的限制
15.2.17. InnoDB故障诊断与排除
15.3. MERGE存储引擎
15.3.1. MERGE表方面的问题
15.4. MEMORY (HEAP)存储引擎
15.5. BDB (BerkeleyDB)存储引擎
15.5.1. BDB支持的操作系统
15.5.2. 安装BDB
15.5.3. BDB启动选项
15.5.4. BDB表的特性
15.5.5. 修改BDB所需的事宜
15.5.6. 对BDB表的限制
15.5.7. 使用BDB表时可能出现的错误
15.6. EXAMPLE存储引擎
15.7. FEDERATED存储引擎
15.7.1. 安装FEDERATED存储引擎
15.7.2. FEDERATED存储引擎介绍
15.7.3. 如何使用FEDERATED表
15.7.4. FEDERATED存储引擎的局限性
15.8. ARCHIVE存储引擎
15.9. CSV存储引擎
15.10. BLACKHOLE存储引擎
16. 编写自定义存储引擎
16.1. 前言
16.2. 概述
16.3. 创建存储引擎源文件
16.4. 创建handlerton
16.5. 对处理程序进行实例化处理
16.6. 定义表扩展
16.7. 创建表
16.8. 打开表
16.9. 实施基本的表扫描功能
16.9.1. 实施store_lock()函数
16.9.2. 实施external_lock()函数
16.9.3. 实施rnd_init()函数
16.9.4. 实施info()函数
16.9.5. 实施extra()函数
16.9.6. 实施rnd_next()函数
16.10. 关闭表
16.11. 为存储引擎添加对INSERT的支持
16.12. 为存储引擎添加对UPDATE的支持
16.13. 为存储引擎添加对DELETE的支持
16.14. API引用
16.14.1. bas_ext
16.14.2. close
16.14.3. create
16.14.4. delete_row
16.14.5. delete_table
16.14.6. external_lock
16.14.7. extra
16.14.8. info
16.14.9. open
16.14.10. rnd_init
16.14.11. rnd_next
16.14.12. store_lock
16.14.13. update_row
16.14.14. write_row
17. MySQL簇
17.1. MySQL簇概述
17.2. MySQL簇的基本概念
17.3. 多计算机的简单基础知识
17.3.1. 硬件、软件和联网
17.3.2. 安装
17.3.3. 配置
17.3.4. 首次启动
17.3.5. 加载示例数据并执行查询
17.3.6. 安全关闭和重启
17.4. MySQL簇的配置
17.4.1. 从源码创建MySQL簇
17.4.2. 安装软件
17.4.3. MySQL簇的快速测试设置
17.4.4. 配置文件
17.5. MySQL簇中的进程管理
17.5.1. 用于MySQL簇的MySQL服务器进程使用
17.5.2. ndbd,存储引擎节点进程
17.5.3. ndb_mgmd,“管理服务器”进程
17.5.4. ndb_mgm,“管理客户端”进程
17.5.5. 用于MySQL簇进程的命令选项
17.6. MySQL簇的管理
17.6.1. MySQL簇的启动阶段
17.6.2. “管理客户端”中的命令
17.6.3. MySQL簇中生成的事件报告
17.6.4. 单用户模式
17.6.5. MySQL簇的联机备份
17.7. 使用与MySQL簇的高速互连
17.7.1. 配置MySQL簇以使用SCI套接字
17.7.2. 理解簇互连的影响
17.8. MySQL簇的已知限制
17.9. MySQL簇发展的重要历程
17.9.1. MySQL 5.0中的MySQL簇变化
17.9.2. 关于MySQL簇的MySQL 5.1发展历程
17.10. MySQL簇常见问题解答
17.11. MySQL簇术语表
18. 分区
18.1. MySQL中的分区概述
18.2. 分区类型
18.2.1. RANGE分区
18.2.2. LIST分区
18.2.3. HASH分区
18.2.4. KEY分区
18.2.5. 子分区
18.2.6. MySQL分区处理NULL值的方式
18.3. 分区管理
18.3.1. RANGE和LIST分区的管理
18.3.2. HASH和KEY分区的管理
18.3.3. 分区维护
18.3.4. 获取关于分区的信息
19. MySQL中的空间扩展
19.1. 前言
19.2. OpenGIS几何模型
19.2.1. Geometry类的层次
19.2.2. 类Geometry
19.2.3. 类Point
19.2.4. 类Curve
19.2.5. 类LineString
19.2.6. 类Surface
19.2.7. 类Polygon
19.2.8. 类GeometryCollection
19.2.9. 类MultiPoint
19.2.10. 类MultiCurve
19.2.11. 类MultiLineString
19.2.12. 类MultiSurface
19.2.13. 类MultiPolygon
19.3. 支持的空间数据格式
19.3.1. 著名的文本(WKT)格式
19.3.2. 著名的二进制(WKB)格式
19.4. 创建具备空间功能的MySQL数据库
19.4.1. MySQL空间数据类型
19.4.2. 创建空间值
19.4.3. 创建空间列
19.4.4. 填充空间列
19.4.5. 获取空间数据
19.5. 分析空间信息
19.5.1. Geometry格式转换函数
19.5.2. Geometry函数
19.5.3. 从已有Geometry创建新Geometry的函数
19.5.4. 测试几何对象间空间关系的函数
19.5.5. 关于几何最小边界矩形(MBR)的关系
19.5.6. 测试几何类之间空间关系的函数
19.6. 优化空间分析
19.6.1. 创建空间索引
19.6.2. 使用空间索引
19.7. MySQL的一致性和兼容性
19.7.1. 尚未实施的GIS特性
20. 存储程序和函数
20.1. 存储程序和授权表
20.2. 存储程序的语法
20.2.1. CREATE PROCEDURE和CREATE FUNCTION
20.2.2. ALTER PROCEDURE和ALTER FUNCTION
20.2.3. DROP PROCEDURE和DROP FUNCTION
20.2.4. SHOW CREATE PROCEDURE和SHOW CREATE FUNCTION
20.2.5. SHOW PROCEDURE STATUS和SHOW FUNCTION STATUS
20.2.6. CALL语句
20.2.7. BEGIN ... END复合语句
20.2.8. DECLARE语句
20.2.9. 存储程序中的变量
20.2.10. 条件和处理程序
20.2.11. 光标
20.2.12. 流程控制构造
20.3. 存储程序、函数、触发程序和复制:常见问题
20.4. 存储子程序和触发程序的二进制日志功能
21. 触发程序
21.1. CREATE TRIGGER语法
21.2. DROP TRIGGER语法
21.3. 使用触发程序
22. 视图
22.1. ALTER VIEW语法
22.2. CREATE VIEW语法
22.3. DROP VIEW语法
22.4. SHOW CREATE VIEW语法
23. INFORMATION_SCHEMA信息数据库
23.1. INFORMATION_SCHEMA表
23.1.1. INFORMATION_SCHEMA SCHEMATA表
23.1.2. INFORMATION_SCHEMA TABLES表
23.1.3. INFORMATION_SCHEMA COLUMNS表
23.1.4. INFORMATION_SCHEMA STATISTICS表
23.1.5. INFORMATION_SCHEMA USER_PRIVILEGES表
23.1.6. INFORMATION_SCHEMA SCHEMA_PRIVILEGES表
23.1.7. INFORMATION_SCHEMA TABLE_PRIVILEGES表
23.1.8. INFORMATION_SCHEMA COLUMN_PRIVILEGES表
23.1.9. INFORMATION_SCHEMA CHARACTER_SETS表
23.1.10. INFORMATION_SCHEMA COLLATIONS表
23.1.11. INFORMATION_SCHEMA COLLATION_CHARACTER_SET_APPLICABILITY表
23.1.12. INFORMATION_SCHEMA TABLE_CONSTRAINTS表
23.1.13. INFORMATION_SCHEMA KEY_COLUMN_USAGE表
23.1.14. INFORMATION_SCHEMA ROUTINES表
23.1.15. INFORMATION_SCHEMA VIEWS表
23.1.16. INFORMATION_SCHEMA TRIGGERS表
23.1.17. 其他INFORMATION_SCHEMA表
23.2. SHOW语句的扩展
24. 精度数学
24.1. 数值的类型
24.2. DECIMAL数据类型更改
24.3. 表达式处理
24.4. 四舍五入
24.5. 精度数学示例
25. API和库
25.1. libmysqld,嵌入式MySQL服务器库
25.1.1. 嵌入式MySQL服务器库概述
25.1.2. 使用libmysqld编译程序
25.1.3. 使用嵌入式MySQL服务器时的限制
25.1.4. 与嵌入式服务器一起使用的选项
25.1.5. 嵌入式服务器中尚需完成的事项(TODO)
25.1.6. 嵌入式服务器示例
25.1.7. 嵌入式服务器的许可
25.2. MySQL C API
25.2.1. C API数据类型
25.2.2. C API函数概述
25.2.3. C API函数描述
25.2.4. C API预处理语句
25.2.5. C API预处理语句的数据类型
25.2.6. C API预处理语句函数概述
25.2.7. C API预处理语句函数描述
25.2.8. C API预处理语句方面的问题
25.2.9. 多查询执行的C API处理
25.2.10. 日期和时间值的C API处理
25.2.11. C API线程函数介绍
25.2.12. C API嵌入式服务器函数介绍
25.2.13. 使用C API时的常见问题
25.2.14. 创建客户端程序
25.2.15. 如何生成线程式客户端
25.3. MySQL PHP API
25.3.1. 使用MySQL和PHP的常见问题
25.4. MySQL Perl API
25.5. MySQL C++ API
25.5.1. Borland C++
25.6. MySQL Python API
25.7. MySQL Tcl API
25.8. MySQL Eiffel Wrapper
25.9. MySQL程序开发实用工具
25.9.1. msql2mysql:转换mSQL程序以用于MySQL
25.9.2. mysql_config:获取编译客户端的编译选项
26. 连接器
26.1. MySQL Connector/ODBC
26.1.1. MyODBC介绍
26.1.2. 关于ODBC和MyODBC的一般信息
26.1.3. 如何安装MyODBC
26.1.4. 在Windows平台上从二进制版本安装MyODBC
26.1.5. I在Unix平台上从二进制版本安装MyODBC
26.1.6. 在Windows平台上从源码版本安装MyODBC
26.1.7. 在Unix平台上从源码版本安装MyODBC
26.1.8. 从BitKeeper开发源码树安装MyODBC
26.1.9. MyODBC配置
26.1.10. 与MyODBC连接相关的事宜
26.1.11. MyODBC和Microsoft Access
26.1.12. MyODBC和Microsoft VBA及ASP
26.1.13. MyODBC和第三方ODBC工具
26.1.14. MyODBC通用功能
26.1.15. 基本的MyODBC应用步骤
26.1.16. MyODBC API引用
26.1.17. MyODBC数据类型
26.1.18. MyODBC错误代码
26.1.19. MyODBC与VB:ADO、DAO和RDO
26.1.20. MyODBC与Microsoft.NET
26.1.21. 感谢
26.2. MySQL Connector/NET
26.2.1. 前言
26.2.2. 下载并安装MySQL Connector/NET
26.2.3. Connector/NET体系结构
26.2.4. 使用MySQL Connector/NET
26.2.5. MySQL Connector/NET变更史
26.3. MySQL Connector/J
26.3.1. 基本的JDBC概念
26.3.2. 安装 Connector/J
26.3.3. JDBC引用
26.3.4. 与J2EE和其他Java框架一起使用 Connector/J
26.3.5. 诊断 Connector/J方面的问题
26.3.6. Changelog
26.4. MySQL Connector/MXJ
26.4.1. 前言
26.4.2. 支持平台:
26.4.3. Junit测试要求
26.4.4. 运行Junit测试
26.4.5. 作为JDBC驱动程序的一部分运行
26.4.6. 在Java对象中运行
26.4.7. MysqldResource API
26.4.8. 在JMX代理(custom)中运行
26.4.9. 部署在标准的JMX代理环境下 (JBoss)
26.4.10. 安装
27. 扩展MySQL
27.1. MySQL内部控件
27.1.1. MySQL线程
27.1.2. MySQL测试套件
27.2. 为MySQL添加新函数
27.2.1. 自定义函数接口的特性
27.2.2. CREATE FUNCTION/DROP FUNCTION语法
27.2.3. 添加新的自定义函数
27.2.4. 添加新的固有函数
27.3. 为MySQL添加新步骤
27.3.1. 步骤分析
27.3.2. 编写步骤
A. 问题和常见错误
A.1. 如何确定导致问题的原因
A.2. 使用MySQL程序时的常见错误
A.2.1. 拒绝访问
A.2.2. 无法连接到[local] MySQL服务器
A.2.3. 客户端不支持鉴定协议
A.2.4. 输入密码时出现密码错误
A.2.5. 主机的host_name被屏蔽
A.2.6. 连接数过多
A.2.7. 内存溢出
A.2.8. MySQL服务器不可用
A.2.9. 信息包过大
A.2.10. 通信错误和失效连接
A.2.11. 表已满
A.2.12. 无法创建文件/写入文件
A.2.13. 命令不同步
A.2.14. 忽略用户
A.2.15. 表tbl_name不存在
A.2.16. 无法初始化字符集
A.2.17. 文件未找到
A.3. 与安装有关的事宜
A.3.1. 与MySQL客户端库的链接问题
A.3.2. 如何以普通用户身份运行MySQL
A.3.3. 与文件许可有关的问题
A.4. 与管理有关的事宜
A.4.1. 如何复位根用户密码
A.4.2. 如果MySQL依然崩溃,应作些什么
A.4.3. MySQL处理磁盘满的方式
A.4.4. MySQL将临时文件储存在哪里
A.4.5. 如何保护或更改MySQL套接字文件/tmp/mysql.sock
A.4.6. 时区问题
A.5. 与查询有关的事宜
A.5.1. 搜索中的大小写敏感性
A.5.2. 使用DATE列方面的问题
A.5.3. 与NULL值有关的问题
A.5.4. 与列别名有关的问题
A.5.5. 非事务表回滚失败
A.5.6. 从相关表删除行
A.5.7. 解决与不匹配行有关的问题
A.5.8. 与浮点比较有关的问题
A.6. 与优化器有关的事宜
A.7. 与表定义有关的事宜
A.7.1. 与ALTER TABLE有关的问题
A.7.2. 如何更改表中的列顺序
A.7.3. TEMPORARY TABLE问题
A.8. MySQL中的已知事宜
A.8.1. MySQL中的打开事宜
B. 错误代码和消息
B.1. 服务器错误代码和消息
B.2. 客户端错误代码和消息
C. 感谢
C.1. MySQL AB处的开发人
C.2. MySQL贡献人
C.3. 资料员和译员
C.4. MySQL使用和包含的库
C.5. 支持MySQL的软件包
C.6. 用于创建MySQL的工具
C.7. MySQL支持人员
D. MySQL变更史
D.1. 5.1.x版中的变更情况(开发)
D.1.1. 5.1.2版中的变更情况(尚未发布)
D.1.2. 5.1.1版中的变更情况(尚未发布)
D.2. MyODBC的变更情况
D.2.1. MyODBC 3.51.12的变更情况
D.2.2. MyODBC 3.51.11的变更情况
E. 移植到其他系统
E.1. 调试MySQL服务器
E.1.1. 针对调试编译MySQL
E.1.2. 创建跟踪文件
E.1.3. 在gdb环境下调试mysqld
E.1.4. 使用堆栈跟踪
E.1.5. 使用日志文件找出mysqld中的错误原因
E.1.6. 如果出现表崩溃,请生成测试案例
E.2. 调试MySQL客户端
E.3. DBUG软件包
E.4. 关于RTS线程的注释
E.5. 线程软件包之间的差异
F. 环境变量
G. MySQL正则表达式
H. MySQL中的限制
H.1. 联合的限制
I. 特性限制
I.1. 对存储子程序和触发程序的限制
I.2. 对服务器端光标的限制
I.3. 对子查询的限制
I.4. 对视图的限制
I.5. 对XA事务的限制
J. GNU通用公共许可
K. MySQL FLOSS许可例外
索引