Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
73a98018
Commit
73a98018
authored
Nov 02, 2001
by
arjen@co3064164-a.bitbike.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improved improvement of Internals story and location.
parent
176631c7
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
767 additions
and
764 deletions
+767
-764
Docs/manual.texi
Docs/manual.texi
+767
-764
No files found.
Docs/manual.texi
View file @
73a98018
...
@@ -44261,1003 +44261,1006 @@ contains an Eiffel wrapper written by Michael Ravits.
...
@@ -44261,1003 +44261,1006 @@ contains an Eiffel wrapper written by Michael Ravits.
@chapter Extending MySQL
@chapter Extending MySQL
@menu
@menu
* MySQL internals:: MySQL Internals
* Adding functions:: Adding New Functions to MySQL
* Adding functions:: Adding New Functions to MySQL
* Adding procedures:: Adding New Procedures to MySQL
* Adding procedures:: Adding New Procedures to MySQL
* MySQL internals:: MySQL Internals
@end menu
@end menu
@node Adding functions, Adding procedures, Extending MySQL, Extending MySQL
@node MySQL internals, Adding functions, Extending MySQL, Extending MySQL
@section Adding New Functions to MySQL
@section MySQL Internals
@cindex functions, new
@cindex adding, new functions
@cindex user-defined functions, adding
@cindex UDFs, defined
@cindex functions, user-defined
There are two ways to add new functions to MySQL:
@cindex internals
@cindex threads
@itemize @bullet
This chapter describes a lot of things that you need to know when
@item You can add the function through the user-definable function (UDF)
working on the MySQL code. If you plan to contribute to MySQL
interface. User-definable functions are added and removed dynamically using
development, want to have access to the bleeding-edge in-between
the @code{CREATE FUNCTION} and @code{DROP FUNCTION} statements.
versions code, or just want to keep track of development, follow the
@xref{CREATE FUNCTION, , @code{CREATE FUNCTION}}.
instructions in @xref{Installing source tree}.
If you are interested in MySQL internals, you should also subscribe
to our @code{internals} mailing list. This list is relatively low
traffic. For details on how to subscribe, please see
@ref{Mailing-list}.
All developers at MySQL AB are on the @code{internals} list and we
help other people who are working on the MySQL code. Feel free to
use this list both to ask questions about the code and to send
patches that you would like to contribute to the MySQL project!
@
item You can add the function as a native (built in) MySQL function.
@
menu
Native functions are compiled into the @code{mysqld} server and become
* MySQL threads:: MySQL threads
available on a permanent basis.
* MySQL test suite:: MySQL test suite
@end
itemize
@end
menu
Each method has advantages and disadvantages:
@itemize @bullet
@node MySQL threads, MySQL test suite, MySQL internals, MySQL internals
@item
@subsection MySQL Threads
If you write a user-definable function, you must install the object file
in addition to the server itself. If you compile your function into the
server, you don't need to do that.
@item
You can add UDFs to a binary MySQL distribution. Native functions
require you to modify a source distribution.
@item
If you upgrade your MySQL distribution, you can continue to use your
previously installed UDFs. For native functions, you must repeat your
modifications each time you upgrade.
@end itemize
Whichever method you use to add new functions, they may be used just like
The MySQL server creates the following threads:
native functions such as @code{ABS()} or @code{SOUNDEX()}.
@menu
@itemize @bullet
* CREATE FUNCTION:: @code{CREATE FUNCTION/DROP FUNCTION} Syntax
* Adding UDF:: Adding a new user-definable function
* Adding native function:: Adding a new native function
@end menu
@item
The TCP/IP connection thread handles all connection requests and
creates a new dedicated thread to handle the authentication and
and SQL query processing for each connection.
@node CREATE FUNCTION, Adding UDF, Adding functions, Adding functions
@item
@subsection @code{CREATE FUNCTION/DROP FUNCTION} Syntax
On Windows NT there is a named pipe handler thread that does the same work as
the TCP/IP connection thread on named pipe connect requests.
@findex CREATE FUNCTION
@item
@findex DROP FUNCTION
The signal thread handles all signals. This thread also normally handles
@findex UDF functions
alarms and calls @code{process_alarm()} to force timeouts on connections
@findex User-defined functions
that have been idle too long.
@findex Functions, user-defined
@example
@item
CREATE [AGGREGATE] FUNCTION function_name RETURNS @{STRING|REAL|INTEGER@}
If @code{mysqld} is compiled with @code{-DUSE_ALARM_THREAD}, a dedicated
SONAME shared_library_name
thread that handles alarms is created. This is only used on some systems where
there are problems with @code{sigwait()} or if one wants to use the
@code{thr_alarm()} code in ones application without a dedicated signal
handling thread.
DROP FUNCTION function_name
@item
@end example
If one uses the @code{--flush_time=#} option, a dedicated thread is created
to flush all tables at the given interval.
A user-definable function (UDF) is a way to extend MySQL with a new
@item
function that works like native (built in) MySQL functions such as
Every connection has its own thread.
@code{ABS()} and @code{CONCAT()}.
@
code{AGGREGATE} is a new option for MySQL Version 3.23. An
@
item
@code{AGGREGATE} function works exactly like a native MySQL
Every different table on which one uses @code{INSERT DELAYED} gets its
@code{GROUP} function like @code{SUM} or @code{COUNT()}
.
own thread
.
@
code{CREATE FUNCTION} saves the function's name, type, and shared library
@
item
name in the @code{mysql.func} system table. You must have th
e
If you use @code{--master-host}, a slave replication thread will b
e
@strong{insert} and @strong{delete} privileges for the @code{mysql} database
started to read and apply updates from the master.
to create and drop functions.
@end itemize
All active functions are reloaded each time the server starts, unless
@code{mysqladmin processlist} only shows the connection, @code{INSERT DELAYED},
you start @code{mysqld} with the @code{--skip-grant-tables} option. In
and replication threads.
this case, UDF initialisation is skipped and UDFs are unavailable.
(An active function is one that has been loaded with @code{CREATE FUNCTION}
and not removed with @code{DROP FUNCTION}.)
For instructions on writing user-definable functions, see @ref{Adding
functions}. For the UDF mechanism to work, functions must be written in C or
C++, your operating system must support dynamic loading and you must have
compiled @code{mysqld} dynamically (not statically).
Note that to make @code{AGGREGATE} work, you must have a
@node MySQL test suite, , MySQL threads, MySQL internals
@code{mysql.func} table that contains the column @code{type}. If this
@subsection MySQL Test Suite
is not the case, you should run the script
@code{mysql_fix_privilege_tables} to get this fixed.
@cindex mysqltest, MySQL Test Suite
@cindex testing mysqld, mysqltest
@node Adding UDF, Adding native function, CREATE FUNCTION, Adding functions
Until recently, our main full-coverage test suite was based on proprietary
@subsection Adding a New User-definable Function
customer data and for that reason has not been publicly available. The only
publicly available part of our testing process consisted of the @code{crash-me}
test, a Perl DBI/DBD benchmark found in the @code{sql-bench} directory, and
miscellaneous tests located in @code{tests} directory. The lack of a
standardised publicly available test suite has made it difficult for our users,
as well developers, to do regression tests on the MySQL code. To
address this problem, we have created a new test system that is included in
the source and binary distributions starting in Version 3.23.29.
@cindex adding, user-definable functions
The current set of test cases doesn't test everything in MySQL, but it
@cindex user-defined functions, adding
should catch most obvious bugs in the SQL processing code, OS/library
@cindex functions, user-definable, adding
issues, and is quite thorough in testing replication. Our eventual goal
is to have the tests cover 100% of the code. We welcome contributions
to our test suite. You may especially want to contribute tests that
examine the functionality critical to your system, as this will ensure
that all future MySQL releases will work well with your
applications.
@menu
@menu
* UDF calling sequences:: UDF calling sequences
* running mysqltest:: Running the MySQL Test Suite
* UDF arguments:: Argument processing
* extending mysqltest:: Extending the MySQL Test Suite
* UDF return values:: Return values and error handling
* Reporting mysqltest bugs:: Reporting Bugs in the MySQL Test Suite
* UDF compiling:: Compiling and installing user-definable functions
@end menu
@end menu
For the UDF mechanism to work, functions must be written in C or C++ and your
@node running mysqltest, extending mysqltest, MySQL test suite, MySQL test suite
operating system must support dynamic loading. The MySQL source
@subsubsection Running the MySQL Test Suite
distribution includes a file @file{sql/udf_example.cc} that defines 5 new
functions. Consult this file to see how UDF calling conventions work.
For @code{mysqld} to be able to use UDF functions, you should configure MySQL
The test system consist of a test language interpreter
with @code{--with-mysqld-ldflags=-rdynamic} The reason is that to on
(@code{mysqltest}), a shell script to run all
many platforms (including Linux) you can load a dynamic library (with
tests(@code{mysql-test-run}), the actual test cases written in a special
@code{dlopen()}) from a static linked program, which you would get if
test language, and their expected results. To run the test suite on
you are using @code{--with-mysqld-ldflags=-all-static} If you want to
your system after a build, type @code{make test} or
use an UDF that needs to access symbols from @code{mysqld} (like the
@code{mysql-test/mysql-test-run} from the source root. If you have
@code{methaphone} example in @file{sql/udf_example.cc} that uses
installed a binary distribution, @code{cd} to the install root
@code{default_charset_info}), you must link the program with
(eg. @code{/usr/local/mysql}), and do @code{scripts/mysql-test-run}.
@code{-rdynamic} (see @code{man dlopen}).
All tests should succeed. If not, you should try to find out why and
report the problem if this is a bug in MySQL.
@xref{Reporting mysqltest bugs}.
For each function that you want to use in SQL statements, you should define
If you have a copy of @code{mysqld} running on the machine where you want to
corresponding C (or C++) functions. In the discussion below, the name
run the test suite you do not have to stop it, as long as it is not using
``xxx'' is used for an example function name. To distinquish between SQL an
d
ports @code{9306} and @code{9307}. If one of those ports is taken, you shoul
d
C/C++ usage, @code{XXX()} (uppercase) indicates a SQL function call, and
edit @code{mysql-test-run} and change the values of the master and/or slave
@code{xxx()} (lowercase) indicates a C/C++ function call
.
port to one that is available
.
The C/C++ functions that you write to implement the interface for
You can run one individual test case with
@code{
XXX()} are:
@code{
mysql-test/mysql-test-run test_name}.
@table @asis
If one test fails, you should test running @code{mysql-test-run} with
@item @code{xxx()} (required)
the @code{--force} option to check if any other tests fails.
The main function. This is where the function result is computed.
The correspondence between the SQL type and return type of your C/C++
function is shown below:
@multitable @columnfractions .2 .8
@item @strong{SQL type} @tab @strong{C/C++ type}
@item @code{STRING} @tab @code{char *}
@item @code{INTEGER} @tab @code{long long}
@item @code{REAL} @tab @code{double}
@end multitable
@item @code{xxx_init()} (optional)
@node extending mysqltest, Reporting mysqltest bugs, running mysqltest, MySQL test suite
The initialisation function for @code{xxx()}. It can be used to:
@subsubsection Extending the MySQL Test Suite
You can use the @code{mysqltest} language to write your own test cases.
Unfortunately, we have not yet written full documentation for it - we plan to
do this shortly. You can, however, look at our current test cases and use
them as an example. The following points should help you get started:
@itemize @bullet
@itemize @bullet
@item
@item
Check the number of arguments to @code{XXX()}.
The tests are located in @code{mysql-test/t/*.test}
@item
Check that the arguments are of a required type or, alternatively,
tell MySQL to coerce arguments to the types you want when
the main function is called.
@item
@item
Allocate any memory required by the main function.
A test case consists of @code{;} terminated statements and is similar to the
input of @code{mysql} command line client. A statement by default is a query
to be sent to MySQL server, unless it is recognised as internal
command (eg. @code{sleep}).
@item
@item
Specify the maximum length of the result.
All queries that produce results, e.g. @code{SELECT}, @code{SHOW},
@code{EXPLAIN}, etc., must be preceded with @code{@@/path/to/result/file}. The
file must contain the expected results. An easy way to generate the result
file is to run @code{mysqltest -r < t/test-case-name.test} from
@code{mysql-test} directory, and then edit the generated result files, if
needed, to adjust them to the expected output. In that case, be very careful
about not adding or deleting any invisible characters - make sure to only
change the text and/or delete lines. If you have to insert a line, make sure
the fields are separated with a hard tab, and there is a hard tab at the end.
You may want to use @code{od -c} to make sure your text editor has not messed
anything up during edit. We, of course, hope that you will never have to edit
the output of @code{mysqltest -r} as you only have to do it when you find a
bug.
@item
@item
Specify (for @code{REAL} functions) the maximum number of decimals.
To be consistent with our setup, you should put your result files in
@code{mysql-test/r} directory and name them @code{test_name.result}. If the
test produces more than one result, you should use @code{test_name.a.result},
@code{test_name.b.result}, etc.
@item
@item
Specify whether or not the result can be @code{NULL}.
If a statement returns an error, you should on the line before the statement
@end itemize
specify with the @code{--error error-number}. The error number can be
a list of possible error numbers separated with @code{','}.
@item @code{xxx_deinit()} (optional)
@item
The deinitialisation function for @code{xxx()}. It should deallocate any
If you are writing a replication test case, you should on the first line of
memory allocated by the initialisation function.
the test file, put @code{source include/master-slave.inc;}. To switch between
@end table
master and slave, use @code{connection master;} and @code{connection slave;}.
If you need to do something on an alternate connection, you can do
When a SQL statement invokes @code{XXX()}, MySQL calls the
@code{connection master1;} for the master, and @code{connection slave1;} for
initialisation function @code{xxx_init()} to let it perform any required
the slave.
setup, such as argument checking or memory allocation. If @code{xxx_init()}
returns an error, the SQL statement is aborted with an error message and the
main and deinitialisation functions are not called. Otherwise, the main
function @code{xxx()} is called once for each row. After all rows have been
processed, the deinitialisation function @code{xxx_deinit()} is called so it
can perform any required cleanup.
All functions must be thread safe (not just the main function,
but the initialisation and deinitialisation functions as well). This means
that you are not allowed to allocate any global or static variables that
change! If you need memory, you should allocate it in @code{xxx_init()}
and free it in @code{xxx_deinit()}.
@node UDF calling sequences, UDF arguments, Adding UDF, Adding UDF
@subsubsection UDF Calling Sequences
@cindex calling sequences, UDF
The main function should be declared as shown below. Note that the return
type and parameters differ, depending on whether you will declare the SQL
function @code{XXX()} to return @code{STRING}, @code{INTEGER}, or @code{REAL}
in the @code{CREATE FUNCTION} statement:
@noindent
For @code{STRING} functions:
@example
char *xxx(UDF_INIT *initid, UDF_ARGS *args,
char *result, unsigned long *length,
char *is_null, char *error);
@end example
@noindent
For @code{INTEGER} functions:
@example
long long xxx(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error);
@end example
@noindent
For @code{REAL} functions:
@item
If you need to do something in a loop, you can use something like this:
@example
@example
double xxx(UDF_INIT *initid, UDF_ARGS *args,
let $1=1000;
char *is_null, char *error);
while ($1)
@{
# do your queries here
dec $1;
@}
@end example
@end example
The initialisation and deinitialisation functions are declared like this:
@item
To sleep between queries, use the @code{sleep} command. It supports fractions
@example
of a second, so you can do @code{sleep 1.3;}, for example, to sleep 1.3
my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
seconds.
void xxx_deinit(UDF_INIT *initid);
@item
@end example
To run the slave with additional options for your test case, put them
in the command-line format in @code{mysql-test/t/test_name-slave.opt}. For
the master, put them in @code{mysql-test/t/test_name-master.opt}.
The @code{initid} parameter is passed to all three functions. It points to a
@item
@code{UDF_INIT} structure that is used to communicate information between
If you have a question about the test suite, or have a test case to contribute,
functions. The @code{UDF_INIT} structure members are listed below. The
e-mail to @email{internals@@lists.mysql.com}. As the list does not accept
initialisation function should fill in any members that it wishes to change.
attachments, you should ftp all the relevant files to:
(To use the default for a member, leave it unchanged.):
@uref{ftp://support.mysql.com/pub/mysql/Incoming}
@table @code
@end itemize
@item my_bool maybe_null
@code{xxx_init()} should set @code{maybe_null} to @code{1} if @code{xxx()}
can return @code{NULL}. The default value is @code{1} if any of the
arguments are declared @code{maybe_null}.
@item unsigned int decimals
Number of decimals. The default value is the maximum number of decimals in
the arguments passed to the main function. (For example, if the function is
passed @code{1.34}, @code{1.345}, and @code{1.3}, the default would be 3,
because @code{1.345} has 3 decimals.
@item unsigned int max_length
@node Reporting mysqltest bugs, , extending mysqltest, MySQL test suite
The maximum length of the string result. The default value differs depending
@subsubsection Reporting Bugs in the MySQL Test Suite
on the result type of the function. For string functions, the default is the
length of the longest argument. For integer functions, the default is 21
digits. For real functions, the default is 13 plus the number of decimals
indicated by @code{initid->decimals}. (For numeric functions, the length
includes any sign or decimal point characters.)
If you want to return a blob, you can set this to 65K or 16M; This
If your MySQL version doesn't pass the test suite you should
memory is not allocated but used to decide which column type to use if
do the following:
there is a need to temporary store the data.
@item char *ptr
@itemize @bullet
A pointer that the function can use for its own purposes. For example,
@item
functions can use @code{initid->ptr} to communicate allocated memory
Don't send a bug report before you have found out as much as possible of
between functions. In @code{xxx_init()}, allocate the memory and assign it
what when wrong! When you do it, please use the @code{mysqlbug} script
to this pointer:
so that we can get information about your system and @code{MySQL}
version. @xref{Bug reports}.
@item
Make sure to include the output of @code{mysql-test-run}, as well as
contents of all @code{.reject} files in @code{mysql-test/r} directory.
@item
If a test in the test suite fails, check if the test fails also when run
by its own:
@example
@example
initid->ptr = allocated_memory;
cd mysql-test
mysql-test-run --local test-name
@end example
@end example
In @code{xxx()} and @code{xxx_deinit()}, refer to @code{initid->ptr} to use
If this fails, then you should configure MySQL with
or deallocate the memory.
@code{--with-debug} and run @code{mysql-test-run} with the
@end table
@code{--debug} option. If this also fails send the trace file
@file{var/tmp/master.trace} to ftp://support.mysql.com/pub/mysql/secret
so that we can examine it. Please remember to also include a full
description of your system, the version of the mysqld binary and how you
compiled it.
@node UDF arguments, UDF return values, UDF calling sequences, Adding UDF
@item
@subsubsection Argument Processing
Try also to run @code{mysql-test-run} with the @code{--force} option to
see if there is any other test that fails.
@cindex argument processing
@item
@cindex processing, arguments
If you have compiled MySQL yourself, check our manual for how
to compile MySQL on your platform or, preferable, use one of
the binaries we have compiled for you at
@uref{http://www.mysql.com/downloads/}. All our standard binaries should
pass the test suite !
The @code{args} parameter points to a @code{UDF_ARGS} structure that thas the
@item
members listed below:
If you get an error, like @code{Result length mismatch} or @code{Result
content mismatch} it means that the output of the test didn't match
exactly the expected output. This could be a bug in MySQL or
that your mysqld version produces slight different results under some
circumstances.
@table @cod
e
Failed test results are put in a file with the same base name as th
e
@item unsigned int arg_count
result file with the @code{.reject} extension. If your test case is
The number of arguments. Check this value in the initialisation function
failing, you should do a diff on the two files. If you cannot see how
if you want your function to be called with a particular number of arguments.
they are different, examine both with @code{od -c} and also check their
For example:
lengths.
@example
@item
if (args->arg_count != 2)
If a test fails totally, you should check the logs file in the
@{
@code{mysql-test/var/log} directory for hints of what went wrong.
strcpy(message,"XXX() requires two arguments");
return 1;
@}
@end example
@item
If you have compiled MySQL with debugging you can try to debug this
by running @code{mysql-test-run} with the @code{--gdb} and/or @code{--debug}
options.
@xref{Making trace files}.
@item enum Item_result *arg_type
If you have not compiled MySQL for debugging you should probably
The types for each argument. The possible type values are
do that. Just specify the @code{--with-debug} options to @code{configure}!
@code{STRING_RESULT}, @code{INT_RESULT}, and @code{REAL_RESULT}.
@xref{Installing source}.
@end itemize
To make sure that arguments are of a given type and return an
error if they are not, check the @code{arg_type} array in the initialisation
function. For example:
@example
@node Adding functions, Adding procedures, MySQL internals, Extending MySQL
if (args->arg_type[0] != STRING_RESULT ||
@section Adding New Functions to MySQL
args->arg_type[1] != INT_RESULT)
@{
strcpy(message,"XXX() requires a string and an integer");
return 1;
@}
@end example
As an alternative to requiring your function's arguments to be of particular
@cindex functions, new
types, you can use the initialisation function to set the @code{arg_type}
@cindex adding, new functions
elements to the types you want. This causes MySQL to coerce
@cindex user-defined functions, adding
arguments to those types for each call to @code{xxx()}. For example, to
@cindex UDFs, defined
specify coercion of the first two arguments to string and integer, do this in
@cindex functions, user-defined
@code{xxx_init()}:
@example
There are two ways to add new functions to MySQL:
args->arg_type[0] = STRING_RESULT;
args->arg_type[1] = INT_RESULT;
@end example
@item char **args
@itemize @bullet
@code{args->args} communicates information to the initialisation function
@item You can add the function through the user-definable function (UDF)
about the general nature of the arguments your function was called with. For a
interface. User-definable functions are added and removed dynamically using
constant argument @code{i}, @code{args->args[i]} points to the argument
the @code{CREATE FUNCTION} and @code{DROP FUNCTION} statements.
value. (See below for instructions on how to access the value properly.)
@xref{CREATE FUNCTION, , @code{CREATE FUNCTION}}.
For a non-constant argument, @code{args->args[i]} is @code{0}.
A constant argument is an expression that uses only constants, such as
@code{3} or @code{4*7-2} or @code{SIN(3.14)}. A non-constant argument is an
expression that refers to values that may change from row to row, such as
column names or functions that are called with non-constant arguments.
For each invocation of the main function, @code{args->args} contains the
@item You can add the function as a native (built in) MySQL function.
actual arguments that are passed for the row currently being processed.
Native functions are compiled into the @code{mysqld} server and become
available on a permanent basis.
@end itemize
Functions can refer to an argument @code{i} as follow
s:
Each method has advantages and disadvantage
s:
@itemize @bullet
@itemize @bullet
@item
@item
An argument of type @code{STRING_RESULT} is given as a string pointer plus a
If you write a user-definable function, you must install the object file
length, to allow handling of binary data or data of arbitrary length. The
in addition to the server itself. If you compile your function into the
string contents are available as @code{args->args[i]} and the string length
server, you don't need to do that.
is @code{args->lengths[i]}. You should not assume that strings are
null-terminated.
@item
@item
For an argument of type @code{INT_RESULT}, you must cast
You can add UDFs to a binary MySQL distribution. Native functions
@code{args->args[i]} to a @code{long long} value:
require you to modify a source distribution.
@item
If you upgrade your MySQL distribution, you can continue to use your
previously installed UDFs. For native functions, you must repeat your
modifications each time you upgrade.
@end itemize
@example
Whichever method you use to add new functions, they may be used just like
long long int_val;
native functions such as @code{ABS()} or @code{SOUNDEX()}.
int_val = *((long long*) args->args[i]);
@end example
@item
@menu
For an argument of type @code{REAL_RESULT}, you must cast
* CREATE FUNCTION:: @code{CREATE FUNCTION/DROP FUNCTION} Syntax
@code{args->args[i]} to a @code{double} value:
* Adding UDF:: Adding a new user-definable function
* Adding native function:: Adding a new native function
@end menu
@example
double real_val;
real_val = *((double*) args->args[i]);
@end example
@end itemize
@item unsigned long *lengths
@node CREATE FUNCTION, Adding UDF, Adding functions, Adding functions
For the initialisation function, the @code{lengths} array indicates the
@subsection @code{CREATE FUNCTION/DROP FUNCTION} Syntax
maximum string length for each argument. For each invocation of the main
function, @code{lengths} contains the actual lengths of any string arguments
that are passed for the row currently being processed. For arguments of
types @code{INT_RESULT} or @code{REAL_RESULT}, @code{lengths} still contains
the maximum length of the argument (as for the initialisation function).
@end table
@findex CREATE FUNCTION
@findex DROP FUNCTION
@findex UDF functions
@findex User-defined functions
@findex Functions, user-defined
@node UDF return values, UDF compiling, UDF arguments, Adding UDF
@example
@subsubsection Return Values and Error Handling
CREATE [AGGREGATE] FUNCTION function_name RETURNS @{STRING|REAL|INTEGER@}
SONAME shared_library_name
@cindex UDFs, return values
DROP FUNCTION function_name
@cindex return values, UDFs
@end example
@cindex errors, handling for UDFs
@cindex handling, errors
The initialisation function should return @code{0} if no error occurred and
A user-definable function (UDF) is a way to extend MySQL with a new
@code{1} otherwise. If an error occurs, @code{xxx_init()} should store a
function that works like native (built in) MySQL functions such as
null-terminated error message in the @code{message} parameter. The message
@code{ABS()} and @code{CONCAT()}.
will be returned to the client. The message buffer is
@code{MYSQL_ERRMSG_SIZE} characters long, but you should try to keep the
message to less than 80 characters so that it fits the width of a standard
terminal screen.
The return value of the main function @code{xxx()} is the function value, for
@code{AGGREGATE} is a new option for MySQL Version 3.23. An
@code{long long} and @code{double} functions. A string functions should
@code{AGGREGATE} function works exactly like a native MySQL
return a pointer to the result and store the length of the string in the
@code{GROUP} function like @code{SUM} or @code{COUNT()}.
@code{length} arguments.
Set these to the contents and length of the return value. For example:
@code{CREATE FUNCTION} saves the function's name, type, and shared library
name in the @code{mysql.func} system table. You must have the
@strong{insert} and @strong{delete} privileges for the @code{mysql} database
to create and drop functions.
@example
All active functions are reloaded each time the server starts, unless
memcpy(result, "result string", 13);
you start @code{mysqld} with the @code{--skip-grant-tables} option. In
*length = 13;
this case, UDF initialisation is skipped and UDFs are unavailable.
@end example
(An active function is one that has been loaded with @code{CREATE FUNCTION}
and not removed with @code{DROP FUNCTION}.)
The @code{result} buffer that is passed to the calc function is 255 byte
For instructions on writing user-definable functions, see @ref{Adding
big. If your result fits in this, you don't have to worry about memory
functions}. For the UDF mechanism to work, functions must be written in C or
allocation for results.
C++, your operating system must support dynamic loading and you must have
compiled @code{mysqld} dynamically (not statically).
If your string function needs to return a string longer than 255 bytes,
Note that to make @code{AGGREGATE} work, you must have a
you must allocate the space for it with @code{malloc()} in your
@code{mysql.func} table that contains the column @code{type}. If this
@code{xxx_init()} function or your @code{xxx()} function and free it in
is not the case, you should run the script
your @code{xxx_deinit()} function. You can store the allocated memory
@code{mysql_fix_privilege_tables} to get this fixed.
in the @code{ptr} slot in the @code{UDF_INIT} structure for reuse by
future @code{xxx()} calls. @xref{UDF calling sequences}.
To indicate a return value of @code{NULL} in the main function, set
@code{is_null} to @code{1}:
@example
@node Adding UDF, Adding native function, CREATE FUNCTION, Adding functions
*is_null = 1;
@subsection Adding a New User-definable Function
@end example
To indicate an error return in the main function, set the @code{error}
@cindex adding, user-definable functions
parameter to @code{1}:
@cindex user-defined functions, adding
@cindex functions, user-definable, adding
@example
@menu
*error = 1;
* UDF calling sequences:: UDF calling sequences
@end example
* UDF arguments:: Argument processing
* UDF return values:: Return values and error handling
* UDF compiling:: Compiling and installing user-definable functions
@end menu
If @code{xxx()} sets @code{*error} to @code{1} for any row, the function
value is @code{NULL} for the current row and for any subsequent rows
processed by the statement in which @code{XXX()} was invoked. (@code{xxx()}
will not even be called for subsequent rows.) @strong{NOTE:} In
MySQL versions prior to 3.22.10, you should set both @code{*error}
and @code{*is_null}:
@example
For the UDF mechanism to work, functions must be written in C or C++ and your
*error = 1;
operating system must support dynamic loading. The MySQL source
*is_null = 1;
distribution includes a file @file{sql/udf_example.cc} that defines 5 new
@end example
functions. Consult this file to see how UDF calling conventions work.
For @code{mysqld} to be able to use UDF functions, you should configure MySQL
with @code{--with-mysqld-ldflags=-rdynamic} The reason is that to on
many platforms (including Linux) you can load a dynamic library (with
@code{dlopen()}) from a static linked program, which you would get if
you are using @code{--with-mysqld-ldflags=-all-static} If you want to
use an UDF that needs to access symbols from @code{mysqld} (like the
@code{methaphone} example in @file{sql/udf_example.cc} that uses
@code{default_charset_info}), you must link the program with
@code{-rdynamic} (see @code{man dlopen}).
@node UDF compiling, , UDF return values, Adding UDF
For each function that you want to use in SQL statements, you should define
@subsubsection Compiling and Installing User-definable Functions
corresponding C (or C++) functions. In the discussion below, the name
``xxx'' is used for an example function name. To distinquish between SQL and
C/C++ usage, @code{XXX()} (uppercase) indicates a SQL function call, and
@code{xxx()} (lowercase) indicates a C/C++ function call.
@cindex compiling, user-defined functions
The C/C++ functions that you write to implement the interface for
@cindex UDFs, compiling
@code{XXX()} are:
@cindex installing, user-defined functions
Files implementing UDFs must be compiled and installed on the host where the
@table @asis
server runs. This process is described below for the example UDF file
@item @code{xxx()} (required)
@file{udf_example.cc} that is included in the MySQL source
The main function. This is where the function result is computed.
distribution. This file contains the following functions:
The correspondence between the SQL type and return type of your C/C++
function is shown below:
@multitable @columnfractions .2 .8
@item @strong{SQL type} @tab @strong{C/C++ type}
@item @code{STRING} @tab @code{char *}
@item @code{INTEGER} @tab @code{long long}
@item @code{REAL} @tab @code{double}
@end multitable
@item @code{xxx_init()} (optional)
The initialisation function for @code{xxx()}. It can be used to:
@itemize @bullet
@itemize @bullet
@item
@item
@code{metaphon()} returns a metaphon string of the string argument.
Check the number of arguments to @code{XXX()}.
This is something like a soundex string, but it's more tuned for English.
@item
@item
@code{myfunc_double()} returns the sum of the ASCII values of the
Check that the arguments are of a required type or, alternatively,
characters in its arguments, divided by the sum of the length of its arguments.
tell MySQL to coerce arguments to the types you want when
the main function is called.
@item
@item
@code{myfunc_int()} returns the sum of the length of its arguments
.
Allocate any memory required by the main function
.
@item
@item
@code{sequence([const int])} returns an sequence starting from the given
Specify the maximum length of the result.
number or 1 if no number has been given.
@item
@item
@code{lookup()} returns the IP number for a hostname
.
Specify (for @code{REAL} functions) the maximum number of decimals
.
@item
@item
@code{reverse_lookup()} returns the hostname for an IP number.
Specify whether or not the result can be @code{NULL}.
The function may be called with a string @code{"xxx.xxx.xxx.xxx"} or
four numbers.
@end itemize
@end itemize
A dynamically loadable file should be compiled as a sharable object file,
@item @code{xxx_deinit()} (optional)
using a command something like this:
The deinitialisation function for @code{xxx()}. It should deallocate any
memory allocated by the initialisation function.
@end table
When a SQL statement invokes @code{XXX()}, MySQL calls the
initialisation function @code{xxx_init()} to let it perform any required
setup, such as argument checking or memory allocation. If @code{xxx_init()}
returns an error, the SQL statement is aborted with an error message and the
main and deinitialisation functions are not called. Otherwise, the main
function @code{xxx()} is called once for each row. After all rows have been
processed, the deinitialisation function @code{xxx_deinit()} is called so it
can perform any required cleanup.
All functions must be thread safe (not just the main function,
but the initialisation and deinitialisation functions as well). This means
that you are not allowed to allocate any global or static variables that
change! If you need memory, you should allocate it in @code{xxx_init()}
and free it in @code{xxx_deinit()}.
@node UDF calling sequences, UDF arguments, Adding UDF, Adding UDF
@subsubsection UDF Calling Sequences
@cindex calling sequences, UDF
The main function should be declared as shown below. Note that the return
type and parameters differ, depending on whether you will declare the SQL
function @code{XXX()} to return @code{STRING}, @code{INTEGER}, or @code{REAL}
in the @code{CREATE FUNCTION} statement:
@noindent
For @code{STRING} functions:
@example
@example
shell> gcc -shared -o udf_example.so myfunc.cc
char *xxx(UDF_INIT *initid, UDF_ARGS *args,
char *result, unsigned long *length,
char *is_null, char *error);
@end example
@end example
You can easily find out the correct compiler options for your system by
@noindent
running this command in the @file{sql} directory of your MySQL
For @code{INTEGER} functions:
source tree:
@example
@example
shell> make udf_example.o
long long xxx(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error);
@end example
@end example
You should run a compile command similar to the one that @code{make} displays,
@noindent
except that you should remove the @code{-c} option near the end of the line
For @code{REAL} functions:
and add @code{-o udf_example.so} to the end of the line. (On some systems,
you may need to leave the @code{-c} on the command.)
Once you compile a shared object containing UDFs, you must install it
@example
and tell MySQL about it. Compiling a shared object from
double xxx(UDF_INIT *initid, UDF_ARGS *args,
@file{udf_example.cc} produces a file named something like
char *is_null, char *error);
@file{udf_example.so} (the exact name may vary from platform to platform).
@end example
Copy this file to some directory searched by @code{ld}, such as
@file{/usr/lib}. On many systems, you can set the @code{LD_LIBRARY} or
@code{LD_LIBRARY_PATH} environment variable to point at the directory where
you have your UDF function files. The @code{dlopen} manual page tells you
which variable you should use on your system. You should set this in
@code{mysql.server} or @code{safe_mysqld} and restart @code{mysqld}.
After the library is installed, notify @code{mysqld} about the new
The initialisation and deinitialisation functions are declared like this:
functions with these commands:
@example
@example
mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
void xxx_deinit(UDF_INIT *initid);
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";
@end example
@end example
Functions can be deleted using @code{DROP FUNCTION}:
The @code{initid} parameter is passed to all three functions. It points to a
@code{UDF_INIT} structure that is used to communicate information between
functions. The @code{UDF_INIT} structure members are listed below. The
initialisation function should fill in any members that it wishes to change.
(To use the default for a member, leave it unchanged.):
@table @code
@item my_bool maybe_null
@code{xxx_init()} should set @code{maybe_null} to @code{1} if @code{xxx()}
can return @code{NULL}. The default value is @code{1} if any of the
arguments are declared @code{maybe_null}.
@item unsigned int decimals
Number of decimals. The default value is the maximum number of decimals in
the arguments passed to the main function. (For example, if the function is
passed @code{1.34}, @code{1.345}, and @code{1.3}, the default would be 3,
because @code{1.345} has 3 decimals.
@item unsigned int max_length
The maximum length of the string result. The default value differs depending
on the result type of the function. For string functions, the default is the
length of the longest argument. For integer functions, the default is 21
digits. For real functions, the default is 13 plus the number of decimals
indicated by @code{initid->decimals}. (For numeric functions, the length
includes any sign or decimal point characters.)
If you want to return a blob, you can set this to 65K or 16M; This
memory is not allocated but used to decide which column type to use if
there is a need to temporary store the data.
@item char *ptr
A pointer that the function can use for its own purposes. For example,
functions can use @code{initid->ptr} to communicate allocated memory
between functions. In @code{xxx_init()}, allocate the memory and assign it
to this pointer:
@example
@example
mysql> DROP FUNCTION metaphon;
initid->ptr = allocated_memory;
mysql> DROP FUNCTION myfunc_double;
mysql> DROP FUNCTION myfunc_int;
mysql> DROP FUNCTION lookup;
mysql> DROP FUNCTION reverse_lookup;
mysql> DROP FUNCTION avgcost;
@end example
@end example
The @code{CREATE FUNCTION} and @code{DROP FUNCTION} statements update the
In @code{xxx()} and @code{xxx_deinit()}, refer to @code{initid->ptr} to use
system table @code{func} in the @code{mysql} database. The function's name,
or deallocate the memory.
type and shared library name are saved in the table. You must have the
@end table
@strong{insert} and @strong{delete} privileges for the @code{mysql} database
to create and drop functions.
You should not use @code{CREATE FUNCTION} to add a function that has already
been created. If you need to reinstall a function, you should remove it with
@code{DROP FUNCTION} and then reinstall it with @code{CREATE FUNCTION}. You
would need to do this, for example, if you recompile a new version of your
function, so that @code{mysqld} gets the new version. Otherwise the server
will continue to use the old version.
Active functions are reloaded each time the server starts, unless you start
@node UDF arguments, UDF return values, UDF calling sequences, Adding UDF
@code{mysqld} with the @code{--skip-grant-tables} option. In this case, UDF
@subsubsection Argument Processing
initialisation is skipped and UDFs are unavailable. (An active function is
one that has been loaded with @code{CREATE FUNCTION} and not removed with
@code{DROP FUNCTION}.)
@cindex argument processing
@cindex processing, arguments
@node Adding native function, , Adding UDF, Adding functions
The @code{args} parameter points to a @code{UDF_ARGS} structure that thas the
@subsection Adding a New Native Function
members listed below:
@cindex adding, native functions
@table @code
@cindex native functions, adding
@item unsigned int arg_count
@cindex functions, native, adding
The number of arguments. Check this value in the initialisation function
if you want your function to be called with a particular number of arguments.
For example:
The procedure for adding a new native function is described below. Not
e
@exampl
e
that you cannot add native functions to a binary distribution because
if (args->arg_count != 2)
the procedure involves modifying MySQL source code. You must
@{
compile MySQL yourself from a source distribution. Also note
strcpy(message,"XXX() requires two arguments");
that if you migrate to another version of MySQL (for example,
return 1;
when a new version is released), you will need to repeat the procedure
@}
with the new version.
@end example
To add a new native MySQL function, follow these steps:
@enumerate
@item enum Item_result *arg_type
@item
The types for each argument. The possible type values are
Add one line to @file{lex.h} that defines the function name in the
@code{STRING_RESULT}, @code{INT_RESULT}, and @code{REAL_RESULT}.
@code{sql_functions[]} array.
@item
To make sure that arguments are of a given type and return an
If the function prototype is simple (just takes zero, one, two or three
error if they are not, check the @code{arg_type} array in the initialisation
arguments), you should in lex.h specify SYM(FUNC_ARG#) (where # is the
function. For example:
number of arguments) as the second argument in the
@code{sql_functions[]} array and add a function that creates a function
object in @file{item_create.cc}. Take a look at @code{"ABS"} and
@code{create_funcs_abs()} for an example of this.
If the function prototype is complicated (for example takes a variable number
of arguments), you should add two lines to @file{sql_yacc.yy}. One
indicates the preprocessor symbol that @code{yacc} should define (this
should be added at the beginning of the file). Then define the function
parameters and add an ``item'' with these parameters to the
@code{simple_expr} parsing rule. For an example, check all occurrences
of @code{ATAN} in @file{sql_yacc.yy} to see how this is done.
@item
In @file{item_func.h}, declare a class inheriting from @code{Item_num_func} or
@code{Item_str_func}, depending on whether your function returns a number or a
string.
@item
In @file{item_func.cc}, add one of the following declarations, depending
on whether you are defining a numeric or string function:
@example
@example
double Item_func_newname::val()
if (args->arg_type[0] != STRING_RESULT ||
longlong Item_func_newname::val_int()
args->arg_type[1] != INT_RESULT)
String *Item_func_newname::Str(String *str)
@{
strcpy(message,"XXX() requires a string and an integer");
return 1;
@}
@end example
@end example
If you inherit your object from any of the standard items (like
As an alternative to requiring your function's arguments to be of particular
@code{Item_num_func} you probably only have to define one of the above
types, you can use the initialisation function to set the @code{arg_type}
functions and let the parent object take care of the other functions.
elements to the types you want. This causes MySQL to coerce
For example, the @code{Item_str_func} class defines a @code{val()} function
arguments to those types for each call to @code{xxx()}. For example, to
that executes @code{atof()} on the value returned by @code{::str()}.
specify coercion of the first two arguments to string and integer, do this in
@code{xxx_init()}:
@item
You should probably also define the following object function:
@example
@example
void Item_func_newname::fix_length_and_dec()
args->arg_type[0] = STRING_RESULT;
args->arg_type[1] = INT_RESULT;
@end example
@end example
This function should at least calculate @code{max_length} based on the
given arguments. @code{max_length} is the maximum number of characters
the function may return. This function should also set @code{maybe_null
= 0} if the main function can't return a @code{NULL} value. The
function can check if any of the function arguments can return
@code{NULL} by checking the arguments @code{maybe_null} variable. You
can take a look at @code{Item_func_mod::fix_length_and_dec} for a
typical example of how to do this.
@end enumerate
All functions must be thread safe (in other words, don't use any global or
@item char **args
static variables in the functions without protecting them with mutexes).
@code{args->args} communicates information to the initialisation function
about the general nature of the arguments your function was called with. For a
constant argument @code{i}, @code{args->args[i]} points to the argument
value. (See below for instructions on how to access the value properly.)
For a non-constant argument, @code{args->args[i]} is @code{0}.
A constant argument is an expression that uses only constants, such as
@code{3} or @code{4*7-2} or @code{SIN(3.14)}. A non-constant argument is an
expression that refers to values that may change from row to row, such as
column names or functions that are called with non-constant arguments.
If you want to return @code{NULL}, from @code{::val()}, @code{::val_int()}
For each invocation of the main function, @code{args->args} contains the
or @code{::str()} you should set @code{null_value} to 1 and return 0
.
actual arguments that are passed for the row currently being processed
.
For @code{::str()} object functions, there are some additional
Functions can refer to an argument @code{i} as follows:
considerations to be aware of:
@itemize @bullet
@itemize @bullet
@item
@item
The @code{String *str} argument provides a string buffer that may be
An argument of type @code{STRING_RESULT} is given as a string pointer plus a
used to hold the result. (For more information about the @code{String} type,
length, to allow handling of binary data or data of arbitrary length. The
take a look at the @file{sql_string.h} file.)
string contents are available as @code{args->args[i]} and the string length
@item
is @code{args->lengths[i]}. You should not assume that strings are
The @code{::str()} function should return the string that holds the result or
null-terminated.
@code{(char*) 0} if the result is @code{NULL}.
@item
All current string functions try to avoid allocating any memory unless
absolutely necessary!
@end itemize
@node Adding procedures, MySQL internals, Adding functions, Extending MySQL
@item
@section Adding New Procedures to MySQL
For an argument of type @code{INT_RESULT}, you must cast
@code{args->args[i]} to a @code{long long} value:
@cindex procedures, adding
@example
@cindex adding, procedures
long long int_val;
@cindex new procedures, adding
int_val = *((long long*) args->args[i]);
@end example
In MySQL, you can define a procedure in C++ that can access and
@item
modify the data in a query before it is sent to the client. The modification
For an argument of type @code{REAL_RESULT}, you must cast
can be done on row-by-row or @code{GROUP BY} level.
@code{args->args[i]} to a @code{double} value:
We have created an example procedure in MySQL Version 3.23 to
@example
show you what can be done.
double real_val;
real_val = *((double*) args->args[i]);
@end example
@end itemize
Additionally we recommend you to take a look at 'mylua', which you can find in the Contrib directory. @xref{Contrib}. Which this you can use the LUA
@item unsigned long *lengths
language to load a procedure at runtime into @code{mysqld}.
For the initialisation function, the @code{lengths} array indicates the
maximum string length for each argument. For each invocation of the main
function, @code{lengths} contains the actual lengths of any string arguments
that are passed for the row currently being processed. For arguments of
types @code{INT_RESULT} or @code{REAL_RESULT}, @code{lengths} still contains
the maximum length of the argument (as for the initialisation function).
@end table
@menu
* procedure analyse:: Procedure analyse
* Writing a procedure:: Writing a procedure.
@end menu
@node UDF return values, UDF compiling, UDF arguments, Adding UDF
@subsubsection Return Values and Error Handling
@node procedure analyse, Writing a procedure, Adding procedures, Adding procedures
@cindex UDFs, return values
@subsection Procedure Analyse
@cindex return values, UDFs
@cindex errors, handling for UDFs
@cindex handling, errors
@code{analyse([max elements,[max memory]])}
The initialisation function should return @code{0} if no error occurred and
@code{1} otherwise. If an error occurs, @code{xxx_init()} should store a
null-terminated error message in the @code{message} parameter. The message
will be returned to the client. The message buffer is
@code{MYSQL_ERRMSG_SIZE} characters long, but you should try to keep the
message to less than 80 characters so that it fits the width of a standard
terminal screen.
This procedure is defined in the @file{sql/sql_analyse.cc}. This
The return value of the main function @code{xxx()} is the function value, for
examines the result from your query and returns an analysis of the
@code{long long} and @code{double} functions. A string functions should
results:
return a pointer to the result and store the length of the string in the
@code{length} arguments.
@itemize @bullet
Set these to the contents and length of the return value. For example:
@item
@code{max elements} (default 256) is the maximum number of distinct values
@code{analyse} will notice per column. This is used by @code{analyse} to check if
the optimal column type should be of type @code{ENUM}.
@item
@code{max memory} (default 8192) is the maximum memory @code{analyse} should
allocate per column while trying to find all distinct values.
@end itemize
@example
@example
SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])
memcpy(result, "result string", 13);
*length = 13;
@end example
@end example
The @code{result} buffer that is passed to the calc function is 255 byte
big. If your result fits in this, you don't have to worry about memory
allocation for results.
@node Writing a procedure, , procedure analyse, Adding procedures
If your string function needs to return a string longer than 255 bytes,
@subsection Writing a Procedure
you must allocate the space for it with @code{malloc()} in your
@code{xxx_init()} function or your @code{xxx()} function and free it in
For the moment, the only documentation for this is the source.
your @code{xxx_deinit()} function. You can store the allocated memory
in the @code{ptr} slot in the @code{UDF_INIT} structure for reuse by
future @code{xxx()} calls. @xref{UDF calling sequences}.
You can find all information about procedures by examining the following files:
To indicate a return value of @code{NULL} in the main function, set
@code{is_null} to @code{1}:
@itemize @bullet
@example
@item @file{sql/sql_analyse.cc}
*is_null = 1;
@item @file{sql/procedure.h}
@end example
@item @file{sql/procedure.cc}
@item @file{sql/sql_select.cc}
@end itemize
To indicate an error return in the main function, set the @code{error}
parameter to @code{1}:
@node MySQL internals, , Adding procedures, Extending MySQL
@example
@section MySQL Internals
*error = 1;
@end example
@cindex internals
If @code{xxx()} sets @code{*error} to @code{1} for any row, the function
@cindex threads
value is @code{NULL} for the current row and for any subsequent rows
processed by the statement in which @code{XXX()} was invoked. (@code{xxx()}
will not even be called for subsequent rows.) @strong{NOTE:} In
MySQL versions prior to 3.22.10, you should set both @code{*error}
and @code{*is_null}:
This chapter describes a lot of things that you need to know when
@example
working on the MySQL code. If you plan to contribute to MySQL
*error = 1;
development, want to have access to the bleeding-edge in-between
*is_null = 1;
versions code, or just want to keep track of development, follow the
@end example
instructions in @xref{Installing source tree}. If you are interested
in MySQL internals, you should also subscribe to our @code{internals}
mailing list. This list is relatively low traffic. For details on how
to subscribe, please see @ref{Mailing-list}.
@menu
* MySQL threads:: MySQL threads
* MySQL test suite:: MySQL test suite
@end menu
@node UDF compiling, , UDF return values, Adding UDF
@subsubsection Compiling and Installing User-definable Functions
@node MySQL threads, MySQL test suite, MySQL internals, MySQL internals
@cindex compiling, user-defined functions
@subsection MySQL Threads
@cindex UDFs, compiling
@cindex installing, user-defined functions
The MySQL server creates the following threads:
Files implementing UDFs must be compiled and installed on the host where the
server runs. This process is described below for the example UDF file
@file{udf_example.cc} that is included in the MySQL source
distribution. This file contains the following functions:
@itemize @bullet
@itemize @bullet
@item
The TCP/IP connection thread handles all connection requests and
creates a new dedicated thread to handle the authentication and
and SQL query processing for each connection.
@item
On Windows NT there is a named pipe handler thread that does the same work as
the TCP/IP connection thread on named pipe connect requests.
@item
@item
The signal thread handles all signals. This thread also normally handles
@code{metaphon()} returns a metaphon string of the string argument.
alarms and calls @code{process_alarm()} to force timeouts on connections
This is something like a soundex string, but it's more tuned for English.
that have been idle too long.
@item
@item
If @code{mysqld} is compiled with @code{-DUSE_ALARM_THREAD}, a dedicated
@code{myfunc_double()} returns the sum of the ASCII values of the
thread that handles alarms is created. This is only used on some systems where
characters in its arguments, divided by the sum of the length of its arguments.
there are problems with @code{sigwait()} or if one wants to use the
@code{thr_alarm()} code in ones application without a dedicated signal
handling thread.
@item
@item
If one uses the @code{--flush_time=#} option, a dedicated thread is created
@code{myfunc_int()} returns the sum of the length of its arguments.
to flush all tables at the given interval.
@item
@item
Every connection has its own thread.
@code{sequence([const int])} returns an sequence starting from the given
number or 1 if no number has been given.
@item
@item
Every different table on which one uses @code{INSERT DELAYED} gets its
@code{lookup()} returns the IP number for a hostname.
own thread.
@item
@item
If you use @code{--master-host}, a slave replication thread will be
@code{reverse_lookup()} returns the hostname for an IP number.
started to read and apply updates from the master.
The function may be called with a string @code{"xxx.xxx.xxx.xxx"} or
four numbers.
@end itemize
@end itemize
@code{mysqladmin processlist} only shows the connection, @code{INSERT DELAYED},
A dynamically loadable file should be compiled as a sharable object file,
and replication threads.
using a command something like this:
@node MySQL test suite, , MySQL threads, MySQL internals
@subsection MySQL Test Suite
@cindex mysqltest, MySQL Test Suite
@example
@cindex testing mysqld, mysqltest
shell> gcc -shared -o udf_example.so myfunc.cc
@end example
Until recently, our main full-coverage test suite was based on proprietary
You can easily find out the correct compiler options for your system by
customer data and for that reason has not been publicly available. The only
running this command in the @file{sql} directory of your MySQL
publicly available part of our testing process consisted of the @code{crash-me}
source tree:
test, a Perl DBI/DBD benchmark found in the @code{sql-bench} directory, and
miscellaneous tests located in @code{tests} directory. The lack of a
standardised publicly available test suite has made it difficult for our users,
as well developers, to do regression tests on the MySQL code. To
address this problem, we have created a new test system that is included in
the source and binary distributions starting in Version 3.23.29.
The current set of test cases doesn't test everything in MySQL, but it
@example
should catch most obvious bugs in the SQL processing code, OS/library
shell> make udf_example.o
issues, and is quite thorough in testing replication. Our eventual goal
@end example
is to have the tests cover 100% of the code. We welcome contributions
to our test suite. You may especially want to contribute tests that
examine the functionality critical to your system, as this will ensure
that all future MySQL releases will work well with your
applications.
@menu
You should run a compile command similar to the one that @code{make} displays,
* running mysqltest:: Running the MySQL Test Suite
except that you should remove the @code{-c} option near the end of the line
* extending mysqltest:: Extending the MySQL Test Suite
and add @code{-o udf_example.so} to the end of the line. (On some systems,
* Reporting mysqltest bugs:: Reporting Bugs in the MySQL Test Suite
you may need to leave the @code{-c} on the command.)
@end menu
Once you compile a shared object containing UDFs, you must install it
and tell MySQL about it. Compiling a shared object from
@file{udf_example.cc} produces a file named something like
@file{udf_example.so} (the exact name may vary from platform to platform).
Copy this file to some directory searched by @code{ld}, such as
@file{/usr/lib}. On many systems, you can set the @code{LD_LIBRARY} or
@code{LD_LIBRARY_PATH} environment variable to point at the directory where
you have your UDF function files. The @code{dlopen} manual page tells you
which variable you should use on your system. You should set this in
@code{mysql.server} or @code{safe_mysqld} and restart @code{mysqld}.
@node running mysqltest, extending mysqltest, MySQL test suite, MySQL test suite
After the library is installed, notify @code{mysqld} about the new
@subsubsection Running the MySQL Test Suite
functions with these commands:
The test system consist of a test language interpreter
@example
(@code{mysqltest}), a shell script to run all
mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
tests(@code{mysql-test-run}), the actual test cases written in a special
mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
test language, and their expected results. To run the test suite on
mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
your system after a build, type @code{make test} or
mysql> CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
@code{mysql-test/mysql-test-run} from the source root. If you have
mysql> CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";
installed a binary distribution, @code{cd} to the install root
mysql> CREATE AGGREGATE FUNCTION avgcost RETURNS REAL SONAME "udf_example.so";
(eg. @code{/usr/local/mysql}), and do @code{scripts/mysql-test-run}.
@end example
All tests should succeed. If not, you should try to find out why and
report the problem if this is a bug in MySQL.
@xref{Reporting mysqltest bugs}.
If you have a copy of @code{mysqld} running on the machine where you want to
Functions can be deleted using @code{DROP FUNCTION}:
run the test suite you do not have to stop it, as long as it is not using
ports @code{9306} and @code{9307}. If one of those ports is taken, you should
edit @code{mysql-test-run} and change the values of the master and/or slave
port to one that is available.
You can run one individual test case with
@example
@code{mysql-test/mysql-test-run test_name}.
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;
@end example
If one test fails, you should test running @code{mysql-test-run} with
The @code{CREATE FUNCTION} and @code{DROP FUNCTION} statements update the
the @code{--force} option to check if any other tests fails.
system table @code{func} in the @code{mysql} database. The function's name,
type and shared library name are saved in the table. You must have the
@strong{insert} and @strong{delete} privileges for the @code{mysql} database
to create and drop functions.
You should not use @code{CREATE FUNCTION} to add a function that has already
been created. If you need to reinstall a function, you should remove it with
@code{DROP FUNCTION} and then reinstall it with @code{CREATE FUNCTION}. You
would need to do this, for example, if you recompile a new version of your
function, so that @code{mysqld} gets the new version. Otherwise the server
will continue to use the old version.
@node extending mysqltest, Reporting mysqltest bugs, running mysqltest, MySQL test suite
Active functions are reloaded each time the server starts, unless you start
@subsubsection Extending the MySQL Test Suite
@code{mysqld} with the @code{--skip-grant-tables} option. In this case, UDF
initialisation is skipped and UDFs are unavailable. (An active function is
one that has been loaded with @code{CREATE FUNCTION} and not removed with
@code{DROP FUNCTION}.)
You can use the @code{mysqltest} language to write your own test cases.
Unfortunately, we have not yet written full documentation for it - we plan to
do this shortly. You can, however, look at our current test cases and use
them as an example. The following points should help you get started:
@itemize @bullet
@node Adding native function, , Adding UDF, Adding functions
@item
@subsection Adding a New Native Function
The tests are located in @code{mysql-test/t/*.test}
@item
@cindex adding, native functions
A test case consists of @code{;} terminated statements and is similar to the
@cindex native functions, adding
input of @code{mysql} command line client. A statement by default is a query
@cindex functions, native, adding
to be sent to MySQL server, unless it is recognised as internal
command (eg. @code{sleep}).
@item
The procedure for adding a new native function is described below. Note
All queries that produce results, e.g. @code{SELECT}, @code{SHOW},
that you cannot add native functions to a binary distribution because
@code{EXPLAIN}, etc., must be preceded with @code{@@/path/to/result/file}. The
the procedure involves modifying MySQL source code. You must
file must contain the expected results. An easy way to generate the result
compile MySQL yourself from a source distribution. Also note
file is to run @code{mysqltest -r < t/test-case-name.test} from
that if you migrate to another version of MySQL (for example,
@code{mysql-test} directory, and then edit the generated result files, if
when a new version is released), you will need to repeat the procedure
needed, to adjust them to the expected output. In that case, be very careful
with the new version.
about not adding or deleting any invisible characters - make sure to only
change the text and/or delete lines. If you have to insert a line, make sure
the fields are separated with a hard tab, and there is a hard tab at the end.
You may want to use @code{od -c} to make sure your text editor has not messed
anything up during edit. We, of course, hope that you will never have to edit
the output of @code{mysqltest -r} as you only have to do it when you find a
bug.
@item
To add a new native MySQL function, follow these steps:
To be consistent with our setup, you should put your result files in
@code{mysql-test/r} directory and name them @code{test_name.result}. If the
test produces more than one result, you should use @code{test_name.a.result},
@code{test_name.b.result}, etc.
@enumerate
@item
@item
If a statement returns an error, you should on the line before the statement
Add one line to @file{lex.h} that defines the function name in the
specify with the @code{--error error-number}. The error number can be
@code{sql_functions[]} array.
a list of possible error numbers separated with @code{','}.
@item
@item
If
you are writing a replication test case, you should on the first line of
If
the function prototype is simple (just takes zero, one, two or three
the test file, put @code{source include/master-slave.inc;}. To switch between
arguments), you should in lex.h specify SYM(FUNC_ARG#) (where # is the
master and slave, use @code{connection master;} and @code{connection slave;}.
number of arguments) as the second argument in the
If you need to do something on an alternate connection, you can do
@code{sql_functions[]} array and add a function that creates a function
@code{connection master1;} for the master, and @code{connection slave1;} for
object in @file{item_create.cc}. Take a look at @code{"ABS"} and
the slave
.
@code{create_funcs_abs()} for an example of this
.
If the function prototype is complicated (for example takes a variable number
of arguments), you should add two lines to @file{sql_yacc.yy}. One
indicates the preprocessor symbol that @code{yacc} should define (this
should be added at the beginning of the file). Then define the function
parameters and add an ``item'' with these parameters to the
@code{simple_expr} parsing rule. For an example, check all occurrences
of @code{ATAN} in @file{sql_yacc.yy} to see how this is done.
@item
@item
If you need to do something in a loop, you can use something like this:
In @file{item_func.h}, declare a class inheriting from @code{Item_num_func} or
@code{Item_str_func}, depending on whether your function returns a number or a
string.
@item
In @file{item_func.cc}, add one of the following declarations, depending
on whether you are defining a numeric or string function:
@example
@example
let $1=1000;
double Item_func_newname::val()
while ($1)
longlong Item_func_newname::val_int()
@{
String *Item_func_newname::Str(String *str)
# do your queries here
dec $1;
@}
@end example
@end example
@item
If you inherit your object from any of the standard items (like
To sleep between queries, use the @code{sleep} command. It supports fractions
@code{Item_num_func} you probably only have to define one of the above
of a second, so you can do @code{sleep 1.3;}, for example, to sleep 1.3
functions and let the parent object take care of the other functions.
seconds.
For example, the @code{Item_str_func} class defines a @code{val()} function
that executes @code{atof()} on the value returned by @code{::str()}.
@item
To run the slave with additional options for your test case, put them
in the command-line format in @code{mysql-test/t/test_name-slave.opt}. For
the master, put them in @code{mysql-test/t/test_name-master.opt}.
@item
@item
If you have a question about the test suite, or have a test case to contribute,
You should probably also define the following object function:
e-mail to @email{internals@@lists.mysql.com}. As the list does not accept
@example
attachments, you should ftp all the relevant files to:
void Item_func_newname::fix_length_and_dec()
@uref{ftp://support.mysql.com/pub/mysql/Incoming}
@end example
This function should at least calculate @code{max_length} based on the
@end itemize
given arguments. @code{max_length} is the maximum number of characters
the function may return. This function should also set @code{maybe_null
= 0} if the main function can't return a @code{NULL} value. The
function can check if any of the function arguments can return
@code{NULL} by checking the arguments @code{maybe_null} variable. You
can take a look at @code{Item_func_mod::fix_length_and_dec} for a
typical example of how to do this.
@end enumerate
All functions must be thread safe (in other words, don't use any global or
static variables in the functions without protecting them with mutexes).
@node Reporting mysqltest bugs, , extending mysqltest, MySQL test suite
If you want to return @code{NULL}, from @code{::val()}, @code{::val_int()}
@subsubsection Reporting Bugs in the MySQL Test Suite
or @code{::str()} you should set @code{null_value} to 1 and return 0.
If your MySQL version doesn't pass the test suite you should
For @code{::str()} object functions, there are some additional
do the following
:
considerations to be aware of
:
@itemize @bullet
@itemize @bullet
@item
@item
Don't send a bug report before you have found out as much as possible of
The @code{String *str} argument provides a string buffer that may be
what when wrong! When you do it, please use the @code{mysqlbug} script
used to hold the result. (For more information about the @code{String} type,
so that we can get information about your system and @code{MySQL}
take a look at the @file{sql_string.h} file.)
version. @xref{Bug reports}.
@item
@item
Make sure to include the output of @code{mysql-test-run}, as well as
The @code{::str()} function should return the string that holds the result or
contents of all @code{.reject} files in @code{mysql-test/r} directory
.
@code{(char*) 0} if the result is @code{NULL}
.
@item
@item
If a test in the test suite fails, check if the test fails also when run
All current string functions try to avoid allocating any memory unless
by its own:
absolutely necessary!
@end itemize
@example
cd mysql-test
mysql-test-run --local test-name
@end example
If this fails, then you should configure MySQL with
@node Adding procedures, , Adding functions, Extending MySQL
@code{--with-debug} and run @code{mysql-test-run} with the
@section Adding New Procedures to MySQL
@code{--debug} option. If this also fails send the trace file
@file{var/tmp/master.trace} to ftp://support.mysql.com/pub/mysql/secret
so that we can examine it. Please remember to also include a full
description of your system, the version of the mysqld binary and how you
compiled it.
@
item
@
cindex procedures, adding
Try also to run @code{mysql-test-run} with the @code{--force} option to
@cindex adding, procedures
see if there is any other test that fails.
@cindex new procedures, adding
@item
In MySQL, you can define a procedure in C++ that can access and
If you have compiled MySQL yourself, check our manual for how
modify the data in a query before it is sent to the client. The modification
to compile MySQL on your platform or, preferable, use one of
can be done on row-by-row or @code{GROUP BY} level.
the binaries we have compiled for you at
@uref{http://www.mysql.com/downloads/}. All our standard binaries should
pass the test suite !
@item
We have created an example procedure in MySQL Version 3.23 to
If you get an error, like @code{Result length mismatch} or @code{Result
show you what can be done.
content mismatch} it means that the output of the test didn't match
exactly the expected output. This could be a bug in MySQL or
that your mysqld version produces slight different results under some
circumstances.
Failed test results are put in a file with the same base name as the
Additionally we recommend you to take a look at 'mylua', which you can find in the Contrib directory. @xref{Contrib}. Which this you can use the LUA
result file with the @code{.reject} extension. If your test case is
language to load a procedure at runtime into @code{mysqld}.
failing, you should do a diff on the two files. If you cannot see how
they are different, examine both with @code{od -c} and also check their
lengths.
@item
@menu
If a test fails totally, you should check the logs file in the
* procedure analyse:: Procedure analyse
@code{mysql-test/var/log} directory for hints of what went wrong.
* Writing a procedure:: Writing a procedure.
@end menu
@item
If you have compiled MySQL with debugging you can try to debug this
by running @code{mysql-test-run} with the @code{--gdb} and/or @code{--debug}
options.
@xref{Making trace files}.
If you have not compiled MySQL for debugging you should probably
@node procedure analyse, Writing a procedure, Adding procedures, Adding procedures
do that. Just specify the @code{--with-debug} options to @code{configure}!
@subsection Procedure Analyse
@xref{Installing source}.
@code{analyse([max elements,[max memory]])}
This procedure is defined in the @file{sql/sql_analyse.cc}. This
examines the result from your query and returns an analysis of the
results:
@itemize @bullet
@item
@code{max elements} (default 256) is the maximum number of distinct values
@code{analyse} will notice per column. This is used by @code{analyse} to check if
the optimal column type should be of type @code{ENUM}.
@item
@code{max memory} (default 8192) is the maximum memory @code{analyse} should
allocate per column while trying to find all distinct values.
@end itemize
@end itemize
@example
SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])
@end example
@node Writing a procedure, , procedure analyse, Adding procedures
@subsection Writing a Procedure
For the moment, the only documentation for this is the source.
You can find all information about procedures by examining the following files:
@itemize @bullet
@item @file{sql/sql_analyse.cc}
@item @file{sql/procedure.h}
@item @file{sql/procedure.cc}
@item @file{sql/sql_select.cc}
@end itemize
@node Problems, Users, Extending MySQL, Top
@node Problems, Users, Extending MySQL, Top
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment