7 min read

(For more resources on MySQL, see here.)

A Hello World! Daemon plugin

Now, let’s look at our first complete plugin example. This plugin is probably the most basic plugin we can have. It simply prints a message into the MySQL error log when loaded:

#include <stdio.h>
#include <mysql/plugin.h>
#include <mysql_version.h>


These are the basic includes required for most Daemon plugins. The most important being mysql/plugin.h, which contains macros and data structures necessary for a MySQL plugin.

static int hello_world_plugin_init(void *p)
{
fprintf(stderr, “Hello World: ”
“This is a static text daemon example plugin!n”);
return 0;
}


In the plugin initialization function we simply write a message to stderr. MySQL redirects stderr to the error log (if there is one) so our message will end up there. We then return 0 to indicate that the initialization was successful.

struct st_mysql_daemon hello_world_info =
{ MYSQL_DAEMON_INTERFACE_VERSION };


This structure is used for the info part of the plugin declaration. In Daemon plugins it simply contains the API version that this plugin was compiled against. The Daemon plugin API version matches the MySQL server version, which means MySQL Daemon plugins can only be used with a MySQL server version they have been compiled against. Indeed, for a Daemon plugin to do something non-trivial it will invariably need access to the server’s internal functions and data structures that change with every MySQL version. Other plugins that are implemented according to a certain functionality API are separated from the server internals and are binary compatible with a wide range of server releases.

Having defined all of the functions and auxiliary structures, we can declare a plugin:

mysql_declare_plugin(hello_world)
{


This is a Daemon plugin so we need to specify it as such with this defined constant:

MYSQL_DAEMON_PLUGIN,


info points to the structure declared earlier. With other plugin types this may contain additional information valuable to the plugin functionality:

&hello_world_info,


We are calling this plugin “hello_world”. This is its name for the INSTALL PLUGIN command and any plugin status:

“hello_world”,


The author string, is useful for providing contact information about the author of the plugin:

“Andrew Hutchings (<a href=”[email protected]” target=”_blank”>[email protected])”,


A Simple line of text that gives a basic description of what our plugin does:

“Daemon hello world example, outputs some static text”,


This plugin is licensed under GPL so we set the license type to this:

PLUGIN_LICENSE_GPL,


This is our initialization function that has been defined earlier in the code:

hello_world_plugin_init,


As our simple plugin does not need a de-initialization function, we put NULL here:

NULL,


This plugin is given version 1.0 because it is our first GA release of the plugin. In future versions we can increment this:

0x0100,


There are no status or system variables in this example. Hence, everything below the version is set to NULL:

NULL,
  NULL,
  NULL
}
mysql_declare_plugin_end;

We can now install this plugin using the INSTALL PLUGIN syntax

Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 2
Server version: 5.1.47 Source distribution

Type ‘help;’ or ‘h’ for help. Type ‘c’ to clear the current
input statement.

mysql> INSTALL PLUGIN hello_world SONAME ‘hello_world.so’;
Query OK, 0 rows affected (0.00 sec)


Going to the error log we see:

090801 22:18:00 [Note] /home/linuxjedi/Programming/Builds/mysql-5.1.47/
libexec/mysqld: ready for connections.
Version: ‘5.1.47’ socket: ‘/tmp/mysql.sock’ port: 3306 Source
distribution
Hello World: This is a static text daemon example plugin!


A system and status variables demo plugin

Let’s see a more complex example. This plugin shows how to create system and status variables. It has one global system variable and one status variable, both defined as long long. When you set the global system variable, its value is copied into the status variable.

#include <stdio.h>
#include <mysql/plugin.h>
#include <mysql_version.h>

long long system_var = 0;
long long status_var = 0;

struct st_mysql_show_var vars_status_var[] =
{
{“vars_status_var”, (char *) &status_var, SHOW_LONGLONG},
{0, 0, 0}
};


We have one status variable in this plugin called vars_status_var which is bound to the status_var variable defined near the top of this source code. We are defining this variable as long long so we use the SHOW_LONGLONG type.

int sysvar_check(MYSQL_THD thd,
struct st_mysql_sys_var *var,
void *save, struct st_mysql_value *value)
{


This function is to be called before our system variable is updated. A plugin is not required to provide it but it can be used to check if the data entered is valid and, as an example, we will only allow values that are not too close to status_var.

long long buf;
value->val_int(value, &buf);


First we retrieve the new value-to-be and store it in buf.

*(longlong*) save = buf;


We then set save to the contents of buf, so that the update function could access it and store the value in our system_var variable. If we do not implement our own sysvar_check() function for our system variable, MySQL will provide a default one that performs all of the above (but nothing of the following).

if (buf * 2 < status_var || buf > status_var * 3)
return 0;
else
return 1;
}


This is our special condition. In this example we allow an update only if the new value is either less than a half of or three times bigger than the value of status_var. We return 0 when the new value is valid, and an update should be allowed, and 1 when an update should be canceled. In our update function we copy the value of the system_var to a status_var, to see how its value changes in SHOW STATUS and to get a different range on valid values for the system_var on every update. Note that the update function cannot return a value. It is not supposed to fail!

void sysvar_update(MYSQL_THD thd,
struct st_mysql_sys_var *var,
void *var_ptr, const void *save)
{
system_var = *(long long *)save;
status_var = system_var;
}


We update our system_var variable without any mutex protection, even though many threads may try to execute the SET statement at the same time. Nevertheless, it is safe. MySQL internally guards all accesses to global system variables with a mutex, which means we do not have to.

MYSQL_SYSVAR_LONGLONG(vars_system, system_var, 0,
“A demo system var”, sysvar_check, sysvar_update,
0, 0, 123456789, 0);


This is the declaration for our system variable. It is a long long and is called vars_system. In fact as this is a variable for the vars plugin, the full name will be vars_vars_system in SHOW VARIABLES. It is associated with the system_var variable in the code, has the check function sysvar_check() and an update function sysvar_update() as defined above, and it can only take values between 0 and 123456789.

struct st_mysql_sys_var* vars_system_var[] = {
MYSQL_SYSVAR(vars_system),
NULL
};


This is the structure which stores all system variables to be passed to the declaration for this plugin. As we only have one variable we shall only include that.

struct st_mysql_daemon vars_plugin_info=
{ MYSQL_DAEMON_INTERFACE_VERSION };
mysql_declare_plugin(vars)
{
MYSQL_DAEMON_PLUGIN,
&vars_plugin_info,
“vars”,
“Andrew Hutchings”,
“A system and status variables example”,
PLUGIN_LICENSE_GPL,
NULL,
NULL,
0x0100,
vars_status_var,
vars_system_var,
NULL
}
mysql_declare_plugin_end;


This is very similar to the declaration of our first plugin, but this one has structures for the status variables and system variable listed.

When putting our new plugin into action we should see the following:

mysql> INSTALL PLUGIN vars SONAME ‘vars.so’;
Query OK, 0 rows affected (0.00 sec)
mysql> SHOW STATUS LIKE ‘vars_%’;
+—————–+——-+
| Variable_name | Value |
+—————–+——-+
| vars_status_var | 0 |
+—————–+——-+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE ‘vars_%’;
+——————+——-+
| Variable_name | Value |
+——————+——-+
| vars_vars_system | 0 |
+——————+——-+
1 row in set (0.00 sec)


Our status and system variables are both set to 0 by default.

mysql> SET GLOBAL vars_vars_system=2384;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW STATUS LIKE ‘vars_%’;
+—————–+——-+
| Variable_name | Value |
+—————–+——-+
| vars_status_var | 2384 |
+—————–+——-+
1 row in set (0.00 sec)

mysql> SHOW VARIABLES LIKE ‘vars_%’;
+——————+——-+
| Variable_name | Value |
+——————+——-+
| vars_vars_system | 2384 |
+——————+——-+
1 row in set (0.00 sec)


Setting our system variable to 2384 has altered both the system variable and the status variable, so we have success!

mysql> SET GLOBAL vars_vars_system=2383;
ERROR 1210 (HY000): Incorrect arguments to SET


Our special check function works too. The variable cannot be updated to a value that is too close to its old value!

LEAVE A REPLY

Please enter your comment!
Please enter your name here