libmysqld, the Embedded MySQL Server Library

Overview of the Embedded MySQL Server Library

The embedded MySQL server library makes it possible to run a full-featured MySQL server inside a client application. The main benefits are increased speed and more simple management for embedded applications.

The embedded server library is based on the client/server version of MySQL, which is written in C/C++. Consequently, the embedded server also is written in C/C++. There is no embedded server available in other languages.

The API is identical for the embedded MySQL version and the client/server version. To change an old threaded application to use the embedded library, you normally only have to add calls to the following functions:

FunctionWhen to call
mysql_server_init()Should be called before any other MySQL function is called, preferably early in the main() function.
mysql_server_end()Should be called before your program exits.
mysql_thread_init()Should be called in each thread you create that will access MySQL.
mysql_thread_end()Should be called before calling pthread_exit()

Then you must link your code with libmysqld.a instead of libmysqlclient.a.

The above mysql_server_xxx functions are also included in libmysqlclient.a to allow you to change between the embedded and the client/server version by just linking your application with the right library. See mysql_server_init().

Compiling Programs with libmysqld

To get a libmysqld library you should configure MySQL with the --with-embedded-server option.

When you link your program with libmysqld, you must also include the system-specific pthread libraries and some libraries that the MySQL server uses. You can get the full list of libraries by executing mysql_config --libmysqld-libs.

The correct flags for compiling and linking a threaded program must be used, even if you do not directly call any thread functions in your code.

Restrictions when using the Embedded MySQL Server

The embedded server has the following limitations:

  • No support for ISAM tables. (This is mainly done to make the library smaller)

  • No user-defined functions (UDFs).

  • No stack trace on core dump.

  • No internal RAID support. (This is not normally needed as most OS has nowadays support for big files).

  • You cannot set this up as a master or a slave (no replication).

  • You can't connect to an embedded server from an outside process with sockets or TCP/IP.

Some of these limitations can be changed by editing the mysql_embed.h include file and recompiling MySQL.

Using Option Files with the Embedded Server

The following is the recommended way to use option files to make it easy to switch between a client/server application and one where MySQL is embedded. See Option files.

  • Put common options in the [server] section. These will be read by both MySQL versions.

  • Put client/server-specific options in the [mysqld] section.

  • Put embedded MySQL-specific options in the [embedded] section.

  • Put application-specific options in a [ApplicationName_SERVER] section.

Things left to do in Embedded Server (TODO)

  • We are going to provide options to leave out some parts of MySQL to make the library smaller.

  • There is still a lot of speed optimization to do.

  • Errors are written to stderr. We will add an option to specify a filename for these.

  • We have to change InnoDB to not be so verbose when using in the embedded version.

A Simple Embedded Server Example

This example program and makefile should work without any changes on a Linux or FreeBSD system. For other operating systems, minor changes will be needed. This example is designed to give enough details to understand the problem, without the clutter that is a necessary part of a real application.

To try out the example, create an test_libmysqld directory at the same level as the mysql-4.0 source directory. Save the test_libmysqld.c source and the GNUmakefile in the directory, and run GNU make from inside the test_libmysqld directory.

test_libmysqld.c

 /*
  * A simple example client, using the embedded MySQL server library
  */
 #include <mysql.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 MYSQL *db_connect(const char *dbname);
 void db_disconnect(MYSQL *db);
 void db_do_query(MYSQL *db, const char *query);
 const char *server_groups[] = {
   "test_libmysqld_SERVER", "embedded", "server", NULL
 };
 int
 main(int argc, char **argv)
 {
   MYSQL *one, *two;
   /* mysql_server_init() must be called before any other mysql
    * functions.
    *
    * You can use mysql_server_init(0, NULL, NULL), and it will
    * initialize the server using groups = {
    *   "server", "embedded", NULL
    *  }.
    *
    * In your $HOME/.my.cnf file, you probably want to put:
 [test_libmysqld_SERVER]
 language = /path/to/source/of/mysql/sql/share/english
    * You could, of course, modify argc and argv before passing
    * them to this function.  Or you could create new ones in any
    * way you like.  But all of the arguments in argv (except for
    * argv[0], which is the program name) should be valid options
    * for the MySQL server.
    *
    * If you link this client against the normal mysqlclient
    * library, this function is just a stub that does nothing.
    */
   mysql_server_init(argc, argv, (char **)server_groups);
   one = db_connect("test");
   two = db_connect(NULL);
   db_do_query(one, "SHOW TABLE STATUS");
   db_do_query(two, "SHOW DATABASES");
   mysql_close(two);
   mysql_close(one);
   /* This must be called after all other mysql functions */
   mysql_server_end();
   exit(EXIT_SUCCESS);
 }
 static void
 die(MYSQL *db, char *fmt, ...)
 {
   va_list ap;
   va_start(ap, fmt);
   vfprintf(stderr, fmt, ap);
   va_end(ap);
   (void)putc('\n', stderr);
   if (db)
     db_disconnect(db);
   exit(EXIT_FAILURE);
 }
 MYSQL *
 db_connect(const char *dbname)
 {
   MYSQL *db = mysql_init(NULL);
   if (!db)
     die(db, "mysql_init failed: no memory");
   /*
    * Notice that the client and server use separate group names.
    * This is critical, because the server will not accept the
    * client's options, and vice versa.
    */
   mysql_options(db, MYSQL_READ_DEFAULT_GROUP, "test_libmysqld_CLIENT");
   if (!mysql_real_connect(db, NULL, NULL, NULL, dbname, 0, NULL, 0))
     die(db, "mysql_real_connect failed: %s", mysql_error(db));
   return db;
 }
 void
 db_disconnect(MYSQL *db)
 {
   mysql_close(db);
 }
 void
 db_do_query(MYSQL *db, const char *query)
 {
   if (mysql_query(db, query) != 0)
     goto err;
   if (mysql_field_count(db) > 0)
   {
     MYSQL_RES   *res;
     MYSQL_ROW    row, end_row;
     int num_fields;
     if (!(res = mysql_store_result(db)))
       goto err;
     num_fields = mysql_num_fields(res);
     while ((row = mysql_fetch_row(res)))
     {
       (void)fputs(">> ", stdout);
       for (end_row = row + num_fields; row < end_row; ++row)
         (void)printf("%s\t", row ? (char*)*row : "NULL");
       (void)fputc('\n', stdout);
     }
     (void)fputc('\n', stdout);
     mysql_free_result(res);
   }
   else
     (void)printf("Affected rows: %lld\n", mysql_affected_rows(db));
   return;
 err:
   die(db, "db_do_query failed: %s [%s]", mysql_error(db), query);
 }
 

GNUmakefile

 # This assumes the MySQL software is installed in /usr/local/mysql
 inc      := /usr/local/mysql/include/mysql
 lib      := /usr/local/mysql/lib
 # If you have not installed the MySQL software yet, try this instead
 #inc      := $(HOME)/mysql-4.0/include
 #lib      := $(HOME)/mysql-4.0/libmysqld
 CC       := gcc
 CPPFLAGS := -I$(inc) -D_THREAD_SAFE -D_REENTRANT
 CFLAGS   := -g -W -Wall
 LDFLAGS  := -static
 # You can change -lmysqld to -lmysqlclient to use the
 # client/server library
 LDLIBS    = -L$(lib) -lmysqld -lz -lm -lcrypt
 ifneq (,$(shell grep FreeBSD /COPYRIGHT 2>/dev/null))
 # FreeBSD
 LDFLAGS += -pthread
 else
 # Assume Linux
 LDLIBS += -lpthread
 endif
 # This works for simple one-file test programs
 sources := $(wildcard *.c)
 objects := $(patsubst %c,%o,$(sources))
 targets := $(basename $(sources))
 all: $(targets)
 clean:
         rm -f $(targets) $(objects) *.core
 

Licensing the Embedded Server

The MySQL source code is covered by the GNU GPL license (see GPL license). One result of this is that any program which includes, by linking with libmysqld, the MySQL source code must be released as free software (under a license compatible with the GPL).

We encourage everyone to promote free software by releasing code under the GPL or a compatible license. For those who are not able to do this, another option is to purchase a commercial license for the MySQL code from MySQL AB. For details, please see MySQL licenses.