MySQL compatibility, memory leaks fixed, moved to C++, docs
This commit is contained in:
parent
b6600f9b33
commit
5d8c6555a4
|
@ -14,3 +14,4 @@ Makefile.in
|
|||
*.lo
|
||||
*.o
|
||||
*.la
|
||||
config.ini
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
ACLOCAL_AMFLAGS = -I build/m4
|
||||
|
||||
SUBDIRS = src
|
||||
SUBDIRS = proxy-auth udfs
|
||||
|
||||
|
|
|
@ -3,13 +3,30 @@ mysql_LIBS = `mysql_config --libs`
|
|||
mysql_CFLAGS = `mysql_config --cflags`
|
||||
|
||||
vn_mysql_libdir = /usr/lib/mysql/plugin
|
||||
|
||||
if MYSQL8
|
||||
|
||||
MYSQLD_SOURCE = /var/mysql/mysql-8.0.15
|
||||
vn_mysql_CFLAGS = \
|
||||
-Wall -O3 \
|
||||
-DMYSQL8=1 \
|
||||
-I$(MYSQLD_SOURCE)/include \
|
||||
-I$(MYSQLD_SOURCE) \
|
||||
-I$(MYSQLD_SOURCE)/bld/include \
|
||||
-I$(MYSQLD_SOURCE)libbinlogevents/export \
|
||||
$(mysql_CFLAGS)
|
||||
|
||||
else
|
||||
|
||||
vn_mysql_CFLAGS = \
|
||||
-Wall -O3 \
|
||||
$(mysql_CFLAGS)
|
||||
|
||||
endif
|
||||
|
||||
vn_mysql_LDFLAGS = \
|
||||
-no-undefined \
|
||||
-module \
|
||||
-avoid-version \
|
||||
-export-dynamic \
|
||||
$(mysql_LIBS)
|
||||
|
||||
$(mysql_LIBS)
|
|
@ -0,0 +1,63 @@
|
|||
# MySQL extensions
|
||||
|
||||
This project contains an authentication plugin and functions to extend MySQL
|
||||
functionality.
|
||||
|
||||
## Compiling
|
||||
|
||||
Install basic tools for compiling.
|
||||
```
|
||||
$ apt-get install build-essential devscripts dh-autoreconf
|
||||
```
|
||||
|
||||
Install MySQL and GLib development libraries.
|
||||
```
|
||||
$ apt-get install libmysqld-dev libglib2.0-dev
|
||||
```
|
||||
|
||||
Compile and generate Debian package for MySQL 5.
|
||||
```
|
||||
$ debuild -uc -us -b
|
||||
```
|
||||
|
||||
Compile and generate Debian package for MySQL 8.
|
||||
```
|
||||
$ debuild --set-envvar MYSQL8=TRUE -uc -us -b
|
||||
```
|
||||
|
||||
## Installing
|
||||
|
||||
Install Debian package.
|
||||
```
|
||||
$ dpkg -i vn-mysql_[version]_[arch].deb
|
||||
```
|
||||
|
||||
Register plugin and functions into MySQL.
|
||||
```
|
||||
INSTALL PLUGIN proxy_auth SONAME 'proxy_auth.so';
|
||||
CREATE AGGREGATE FUNCTION minacum RETURNS INT SONAME 'minacum.so';
|
||||
CREATE AGGREGATE FUNCTION multimax RETURNS INT SONAME 'multimax.so';
|
||||
CREATE FUNCTION sql_printf RETURNS STRING SONAME 'sql_printf.so';
|
||||
```
|
||||
|
||||
## Uninstalling
|
||||
|
||||
Deregister plugin and functions from MySQL.
|
||||
```
|
||||
UNINSTALL PLUGIN proxy_auth;
|
||||
DROP FUNCTION IF EXISTS minacum;
|
||||
DROP FUNCTION IF EXISTS multimax;
|
||||
DROP FUNCTION IF EXISTS sql_printf;
|
||||
```
|
||||
|
||||
## Built with
|
||||
|
||||
* [MySQL](https://dev.mysql.com/doc/refman/8.0/en/extending-mysql.html)
|
||||
* [GLib](https://developer.gnome.org/glib/)
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Writing plugins](https://dev.mysql.com/doc/refman/8.0/en/writing-plugins.html)
|
||||
* [Authentication plugins](https://dev.mysql.com/doc/refman/8.0/en/writing-authentication-plugins.html)
|
||||
* [Adding UDF](https://dev.mysql.com/doc/refman/8.0/en/adding-udf.html)
|
||||
* [GLib API reference](https://developer.gnome.org/glib/)
|
1
clean.sh
1
clean.sh
|
@ -8,6 +8,7 @@ then
|
|||
exit 2
|
||||
fi
|
||||
|
||||
$dir/debian/rules clean
|
||||
rm -rf $dir/build
|
||||
rm -rf $dir/configure
|
||||
rm -rf $dir/gtk-doc.make
|
||||
|
|
|
@ -9,14 +9,15 @@ AM_INIT_AUTOMAKE()
|
|||
AM_SILENT_RULES([yes])
|
||||
|
||||
# Check for program dependencies
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_CC
|
||||
PKG_CHECK_MODULES([glib], [glib-2.0])
|
||||
|
||||
AM_CONDITIONAL([MYSQL8], [test ! -z "$MYSQL8"])
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
src/Makefile
|
||||
src/proxy-auth/Makefile
|
||||
src/functions/Makefile
|
||||
proxy-auth/Makefile
|
||||
udfs/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
vn-mysql (1.5.0) unstable; urgency=low
|
||||
vn-mysql (1.6.0) unstable; urgency=low
|
||||
|
||||
* Initial Release.
|
||||
|
||||
|
|
|
@ -2,13 +2,13 @@ Source: vn-mysql
|
|||
Section: misc
|
||||
Priority: extra
|
||||
Maintainer: Alejandro T. Colombini Gómez <atcolombini@verdnatura.es>
|
||||
Build-Depends: build-essential, dh-autoreconf, devscripts, libglib2.0-dev, libmysqld-dev
|
||||
Build-Depends: build-essential, dh-autoreconf, devscripts, libglib2.0-dev
|
||||
Standards-Version: 3.9.4
|
||||
Homepage: http://www.verdnatura.es
|
||||
|
||||
Package: vn-mysql
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}, mysql-server (>= 5.5.27) | mariadb-galera-server (>= 5.5.27) | mariadb-server (>= 5.5.27), libglib2.0-0
|
||||
Depends: mysql-server (>= 5.5.27) | mariadb-server (>= 5.5.27), libglib2.0-0, ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: MySQL plugins
|
||||
This package contains some useful MySQL plugins
|
||||
developed by Verdnatura.
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
INSTALL PLUGIN proxy_auth SONAME 'proxy_auth.so';
|
||||
|
||||
CREATE AGGREGATE FUNCTION minacum RETURNS INT SONAME 'minacum.so';
|
||||
CREATE AGGREGATE FUNCTION multimax RETURNS INT SONAME 'multimax.so';
|
||||
CREATE FUNCTION sql_printf RETURNS STRING SONAME 'sql_printf.so';
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
UNINSTALL PLUGIN proxy_auth;
|
||||
|
||||
DROP FUNCTION IF EXISTS minacum;
|
||||
DROP FUNCTION IF EXISTS multimax;
|
||||
DROP FUNCTION IF EXISTS sql_printf;
|
||||
|
|
@ -7,7 +7,7 @@ proxy_auth_data_DATA = \
|
|||
proxy-auth.ini
|
||||
|
||||
proxy_auth_LTLIBRARIES = proxy_auth.la
|
||||
proxy_auth_la_SOURCES = proxy-auth.c
|
||||
proxy_auth_la_SOURCES = proxy-auth.cc
|
||||
proxy_auth_la_LIBADD = \
|
||||
$(glib_LIBS) \
|
||||
$(vn_mysql_LIBS)
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* Copyright (C) 2013 - Alejandro T. Colombini
|
||||
* Copyright(C) 2013 - Alejandro T. Colombini
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*(at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
@ -15,21 +15,29 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define MYSQL_ABI_CHECK
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#ifndef MYSQL8
|
||||
#define MYSQL_ABI_CHECK
|
||||
#endif
|
||||
|
||||
//#include <stdbool.h>
|
||||
#include <mysql.h>
|
||||
#include <mysql/errmsg.h>
|
||||
#include <mysql/plugin_auth.h>
|
||||
|
||||
#include <glib-unix.h>
|
||||
#ifdef MYSQL8
|
||||
#include <ctype.h>
|
||||
#include <mysql/plugin.h>
|
||||
#endif
|
||||
|
||||
#define CONFIG_FILE _CONFIG_DIR"/proxy-auth.ini"
|
||||
#define SQL_FILE _SQL_DIR"/proxy-auth.sql"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
gboolean initialized;
|
||||
gchar * socket;
|
||||
gchar * host;
|
||||
|
@ -49,8 +57,7 @@ typedef struct
|
|||
}
|
||||
ProxyAuth;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
MYSQL * conn;
|
||||
gchar * user;
|
||||
gulong user_len;
|
||||
|
@ -60,8 +67,7 @@ typedef struct
|
|||
RegexData;
|
||||
|
||||
ProxyAuth *
|
||||
proxy_auth_new()
|
||||
{
|
||||
proxy_auth_new() {
|
||||
ProxyAuth * self = g_new(ProxyAuth, 1);
|
||||
self->initialized = FALSE;
|
||||
g_mutex_init(&self->mutex);
|
||||
|
@ -69,8 +75,7 @@ proxy_auth_new()
|
|||
}
|
||||
|
||||
void
|
||||
proxy_auth_deinit(ProxyAuth * self)
|
||||
{
|
||||
proxy_auth_deinit(ProxyAuth * self) {
|
||||
if (!self->initialized)
|
||||
return;
|
||||
|
||||
|
@ -92,8 +97,7 @@ proxy_auth_deinit(ProxyAuth * self)
|
|||
}
|
||||
|
||||
void
|
||||
proxy_auth_free(ProxyAuth * self)
|
||||
{
|
||||
proxy_auth_free(ProxyAuth * self) {
|
||||
g_return_if_fail(self != NULL);
|
||||
|
||||
proxy_auth_deinit(self);
|
||||
|
@ -102,8 +106,7 @@ proxy_auth_free(ProxyAuth * self)
|
|||
}
|
||||
|
||||
gboolean
|
||||
proxy_auth_init(ProxyAuth * self)
|
||||
{
|
||||
proxy_auth_init(ProxyAuth * self) {
|
||||
g_return_val_if_fail(self != NULL, FALSE);
|
||||
|
||||
gboolean res = FALSE;
|
||||
|
@ -129,8 +132,7 @@ proxy_auth_init(ProxyAuth * self)
|
|||
|
||||
GKeyFile * key_file = g_key_file_new();
|
||||
|
||||
if (!g_key_file_load_from_file(key_file, CONFIG_FILE, G_KEY_FILE_NONE, &error))
|
||||
{
|
||||
if (!g_key_file_load_from_file(key_file, CONFIG_FILE, G_KEY_FILE_NONE, &error)) {
|
||||
g_warning("ProxyAuth: Can't open configuration file: %s", error->message);
|
||||
goto end;
|
||||
}
|
||||
|
@ -150,8 +152,7 @@ proxy_auth_init(ProxyAuth * self)
|
|||
|
||||
// Reading the query template
|
||||
|
||||
if (!g_file_get_contents(SQL_FILE, &self->queryt, &self->queryt_len, &error))
|
||||
{
|
||||
if (!g_file_get_contents(SQL_FILE, &self->queryt, &self->queryt_len, &error)) {
|
||||
g_warning("ProxyAuth: Can't read the query template: %s", error->message);
|
||||
goto end;
|
||||
}
|
||||
|
@ -159,10 +160,9 @@ proxy_auth_init(ProxyAuth * self)
|
|||
// Creates the regular expression
|
||||
|
||||
self->regex = g_regex_new("#\\w+",
|
||||
G_REGEX_OPTIMIZE | G_REGEX_MULTILINE, 0, &error);
|
||||
(GRegexCompileFlags)(G_REGEX_OPTIMIZE | G_REGEX_MULTILINE),(GRegexMatchFlags) 0, &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
g_warning("ProxyAuth: Can't create the regex: %s", error->message);
|
||||
goto end;
|
||||
}
|
||||
|
@ -184,27 +184,22 @@ end:
|
|||
}
|
||||
|
||||
static gboolean
|
||||
proxy_auth_regex_func(const GMatchInfo * info, GString * res, gpointer data)
|
||||
{
|
||||
proxy_auth_regex_func(const GMatchInfo * info, GString * res, gpointer data) {
|
||||
RegexData * regex_data = (RegexData *) data;
|
||||
gchar * match = g_match_info_fetch(info, 0);
|
||||
|
||||
gchar * str = NULL;
|
||||
gulong str_len;
|
||||
|
||||
if (!g_strcmp0(match, "#user"))
|
||||
{
|
||||
if (!g_strcmp0(match, "#user")) {
|
||||
str = regex_data->user;
|
||||
str_len = regex_data->user_len;
|
||||
}
|
||||
else if (!g_strcmp0(match, "#pass"))
|
||||
{
|
||||
} else if (!g_strcmp0(match, "#pass")) {
|
||||
str = regex_data->pass;
|
||||
str_len = regex_data->pass_len;
|
||||
}
|
||||
|
||||
if (str)
|
||||
{
|
||||
if (str) {
|
||||
unsigned long scaped_len;
|
||||
char escaped_str[str_len * 2 + 1];
|
||||
|
||||
|
@ -216,8 +211,7 @@ proxy_auth_regex_func(const GMatchInfo * info, GString * res, gpointer data)
|
|||
|
||||
g_string_append_len(res, escaped_str,(gssize) scaped_len);
|
||||
g_string_append_c(res, '\'');
|
||||
}
|
||||
else
|
||||
} else
|
||||
g_string_append(res, match);
|
||||
|
||||
g_free(match);
|
||||
|
@ -225,8 +219,7 @@ proxy_auth_regex_func(const GMatchInfo * info, GString * res, gpointer data)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
proxy_auth_reconnect(ProxyAuth * self, MYSQL * conn)
|
||||
{
|
||||
proxy_auth_reconnect(ProxyAuth * self, MYSQL * conn) {
|
||||
g_return_val_if_fail(self != NULL, FALSE);
|
||||
|
||||
gboolean connected = mysql_real_connect(conn,
|
||||
|
@ -240,11 +233,10 @@ proxy_auth_reconnect(ProxyAuth * self, MYSQL * conn)
|
|||
|
||||
self->last_error = conn_error;
|
||||
return connected;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info)
|
||||
{
|
||||
proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info) {
|
||||
g_return_val_if_fail(self != NULL, CR_ERROR);
|
||||
|
||||
int res = CR_ERROR;
|
||||
|
@ -257,7 +249,7 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
|||
int user_len = info->user_name_length;
|
||||
|
||||
if (info->user_name == NULL
|
||||
&&(user_len = vio->read_packet(vio, &pkt)) < 0)
|
||||
&& (user_len = vio->read_packet(vio, &pkt)) < 0)
|
||||
return CR_ERROR;
|
||||
|
||||
if (user_len > MYSQL_USERNAME_LENGTH)
|
||||
|
@ -270,8 +262,7 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
|||
if (pass_len < 0)
|
||||
return CR_ERROR;
|
||||
|
||||
if (!pass_len || *pkt == '\0')
|
||||
{
|
||||
if (!pass_len || *pkt == '\0') {
|
||||
info->password_used = PASSWORD_USED_NO;
|
||||
return CR_ERROR;
|
||||
}
|
||||
|
@ -286,19 +277,16 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
|||
|
||||
MYSQL * conn = (MYSQL *) g_async_queue_try_pop(self->conn_pool);
|
||||
|
||||
if (!conn)
|
||||
{
|
||||
if (!conn) {
|
||||
g_mutex_lock(&self->mutex);
|
||||
|
||||
if (self->pool_size < self->max_connections)
|
||||
{
|
||||
if (self->pool_size < self->max_connections) {
|
||||
self->pool_size++;
|
||||
g_mutex_unlock(&self->mutex);
|
||||
|
||||
conn = mysql_init(NULL);
|
||||
|
||||
if (!proxy_auth_reconnect(self, conn))
|
||||
{
|
||||
if (!proxy_auth_reconnect(self, conn)) {
|
||||
g_mutex_lock(&self->mutex);
|
||||
self->pool_size--;
|
||||
g_mutex_unlock(&self->mutex);
|
||||
|
@ -307,16 +295,13 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
|||
conn = NULL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
g_mutex_unlock(&self->mutex);
|
||||
conn = (MYSQL *) g_async_queue_pop(self->conn_pool);
|
||||
}
|
||||
}
|
||||
|
||||
switch (mysql_errno(conn))
|
||||
{
|
||||
switch (mysql_errno(conn)) {
|
||||
case CR_SERVER_LOST:
|
||||
case CR_SERVER_GONE_ERROR:
|
||||
if (!proxy_auth_reconnect(self, conn))
|
||||
|
@ -333,10 +318,9 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
|||
regex_data.pass_len = pass_len;
|
||||
|
||||
query = g_regex_replace_eval(self->regex,
|
||||
self->queryt, self->queryt_len, 0, 0, proxy_auth_regex_func, ®ex_data, &error);
|
||||
self->queryt, self->queryt_len, 0,(GRegexMatchFlags) 0, proxy_auth_regex_func, ®ex_data, &error);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
g_warning("ProxyAuth: Can't evaluate regex: %s", error->message);
|
||||
goto end;
|
||||
}
|
||||
|
@ -349,16 +333,13 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
|||
MYSQL_RES * result;
|
||||
|
||||
if (!mysql_query(conn, query)
|
||||
&&(result = mysql_store_result(conn)))
|
||||
{
|
||||
&& (result = mysql_store_result(conn))) {
|
||||
MYSQL_ROW row = mysql_fetch_row(result);
|
||||
|
||||
if (row && row[0])
|
||||
{
|
||||
if (row && row[0]) {
|
||||
unsigned long row_len = mysql_fetch_lengths(result)[0];
|
||||
|
||||
if (row_len > 0 && row_len <= MYSQL_USERNAME_LENGTH)
|
||||
{
|
||||
if (row_len > 0 && row_len <= MYSQL_USERNAME_LENGTH) {
|
||||
strcpy(info->external_user, info->user_name);
|
||||
strncpy(info->authenticated_as, row[0], row_len);
|
||||
info->authenticated_as[row_len] = '\0';
|
||||
|
@ -370,8 +351,7 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
|||
}
|
||||
|
||||
mysql_free_result(result);
|
||||
}
|
||||
else
|
||||
} else
|
||||
g_warning("ProxyAuth: Error executing query: %s", mysql_error(conn));
|
||||
end:
|
||||
if (conn)
|
||||
|
@ -385,21 +365,18 @@ end:
|
|||
ProxyAuth * pauth = NULL;
|
||||
|
||||
static int
|
||||
proxy_auth_plugin_main(MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info)
|
||||
{
|
||||
proxy_auth_plugin_main(MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_AUTH_INFO * info) {
|
||||
return proxy_auth_authenticate(pauth, vio, info);
|
||||
}
|
||||
|
||||
static int
|
||||
proxy_auth_plugin_init()
|
||||
{
|
||||
proxy_auth_plugin_init(MYSQL_PLUGIN plugin_info) {
|
||||
pauth = proxy_auth_new();
|
||||
return proxy_auth_init(pauth) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int
|
||||
proxy_auth_plugin_deinit()
|
||||
{
|
||||
proxy_auth_plugin_deinit(MYSQL_PLUGIN plugin_info) {
|
||||
proxy_auth_free(pauth);
|
||||
return 0;
|
||||
}
|
||||
|
@ -408,8 +385,7 @@ int
|
|||
generate_auth_string_hash(
|
||||
char *outbuf, unsigned int *buflen,
|
||||
const char *inbuf,
|
||||
unsigned int inbuflen)
|
||||
{
|
||||
unsigned int inbuflen) {
|
||||
if (*buflen < inbuflen)
|
||||
return 1;
|
||||
|
||||
|
@ -421,8 +397,7 @@ generate_auth_string_hash(
|
|||
int
|
||||
validate_auth_string_hash(
|
||||
char* const inbuf __attribute__((unused)),
|
||||
unsigned int buflen __attribute__((unused)))
|
||||
{
|
||||
unsigned int buflen __attribute__((unused))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -431,26 +406,26 @@ set_salt(
|
|||
const char* password __attribute__((unused)),
|
||||
unsigned int password_len __attribute__((unused)),
|
||||
unsigned char* salt __attribute__((unused)),
|
||||
unsigned char* salt_len)
|
||||
{
|
||||
unsigned char* salt_len) {
|
||||
*salt_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct st_mysql_auth
|
||||
proxy_auth_handler =
|
||||
{
|
||||
proxy_auth_handler = {
|
||||
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
|
||||
"mysql_clear_password", // Cleartext plugin required in the client
|
||||
proxy_auth_plugin_main,
|
||||
generate_auth_string_hash,
|
||||
validate_auth_string_hash,
|
||||
set_salt,
|
||||
AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE
|
||||
AUTH_FLAG_PRIVILEGED_USER_FOR_PASSWORD_CHANGE,
|
||||
#ifdef MYSQL8
|
||||
NULL
|
||||
#endif
|
||||
};
|
||||
|
||||
mysql_declare_plugin(proxy_auth)
|
||||
{
|
||||
mysql_declare_plugin(proxy_auth) {
|
||||
MYSQL_AUTHENTICATION_PLUGIN,
|
||||
&proxy_auth_handler,
|
||||
"proxy_auth",
|
||||
|
@ -458,6 +433,9 @@ mysql_declare_plugin(proxy_auth)
|
|||
"Proxy user authentication server-side plugin",
|
||||
PLUGIN_LICENSE_GPL,
|
||||
proxy_auth_plugin_init,
|
||||
#ifdef MYSQL8
|
||||
NULL,
|
||||
#endif
|
||||
proxy_auth_plugin_deinit,
|
||||
0x0100, // version 1.0,
|
||||
NULL,
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/bash
|
||||
|
||||
mysql --defaults-file=config.ini --skip-column-names --enable-cleartext-plugin < query.sql
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
CONCURRENCY=400
|
||||
NATTEMPS=40
|
||||
CONCURRENCY=50
|
||||
NATTEMPS=500
|
||||
|
||||
I=0
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
mysql --enable-cleartext-plugin -u test-user --password=1234 < query.sql
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
SUBDIRS = \
|
||||
proxy-auth \
|
||||
functions
|
|
@ -1,84 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
/*
|
||||
DROP FUNCTION minacum;
|
||||
CREATE AGGREGATE FUNCTION minacum RETURNS INT SONAME 'minacum.so';
|
||||
*/
|
||||
|
||||
#define GET_ARG(n) (!args->args[n]) ? 0 : *((long long*) args->args[n])
|
||||
|
||||
typedef struct _Interval Interval;
|
||||
struct _Interval {
|
||||
long long num;
|
||||
long long sum;
|
||||
Interval* next;
|
||||
};
|
||||
|
||||
long long minacum (UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) {
|
||||
Interval* ival = (Interval*) initid->ptr;
|
||||
long long num = GET_ARG(2);
|
||||
long long min = (ival->num != num) ? 0 : 9999999;
|
||||
long long acum = 0;
|
||||
while (ival != NULL) {
|
||||
acum += ival->sum;
|
||||
if (acum < min)
|
||||
min = acum;
|
||||
ival = ival->next;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
void minacum_add (UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) {
|
||||
long long num = GET_ARG(0);
|
||||
long long amount = GET_ARG(1);
|
||||
Interval* ival = (Interval*) initid->ptr;
|
||||
Interval* prev = ival;
|
||||
while (ival != NULL && ival->num < num) {
|
||||
prev = ival;
|
||||
ival = ival->next;
|
||||
}
|
||||
if (ival == NULL || ival->num > num) {
|
||||
Interval* new;
|
||||
if ((new = (Interval*) malloc (sizeof (Interval)))) {
|
||||
new->num = num;
|
||||
new->sum = amount;
|
||||
new->next = ival;
|
||||
if (prev != ival)
|
||||
prev->next = new;
|
||||
else
|
||||
initid->ptr = (char *) new;
|
||||
}
|
||||
} else
|
||||
ival->sum += amount;
|
||||
}
|
||||
|
||||
void minacum_clear (UDF_INIT *initid, char *is_null, char *error) {
|
||||
Interval* ival = (Interval*) initid->ptr;
|
||||
Interval* cur;
|
||||
while (ival != NULL) {
|
||||
cur = ival;
|
||||
ival = ival->next;
|
||||
free (cur);
|
||||
}
|
||||
initid->ptr = NULL;
|
||||
}
|
||||
|
||||
my_bool minacum_init (UDF_INIT *initid, UDF_ARGS *args, char *message) {
|
||||
if (args->arg_count == 3) {
|
||||
args->arg_type[0] = INT_RESULT;
|
||||
args->arg_type[1] = INT_RESULT;
|
||||
args->arg_type[2] = INT_RESULT;
|
||||
initid->maybe_null = 0;
|
||||
initid->const_item = 0;
|
||||
initid->ptr = NULL;
|
||||
return 0;
|
||||
} else {
|
||||
strcpy(message, "minacum must have 3 parameters");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void minacum_deinit (UDF_INIT *initid) {}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
#define NAME "multimax"
|
||||
#define PARAMC 2
|
||||
|
||||
#define DATA(ptr) ((void **) ptr)
|
||||
#define INT(ptr) (*((long long *) ptr))
|
||||
#define DOUBLE(ptr) (*((double *) ptr))
|
||||
|
||||
long long multimax (UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
|
||||
{
|
||||
return INT (DATA (initid->ptr)[1]);
|
||||
}
|
||||
|
||||
void multimax_add (UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
|
||||
{
|
||||
size_t set;
|
||||
void ** data = DATA (initid->ptr);
|
||||
|
||||
if (args->args[0] && data[0])
|
||||
{
|
||||
switch (args->arg_type[0])
|
||||
{
|
||||
case INT_RESULT:
|
||||
set = INT (args->args[0]) > INT (data[0]);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
set = DOUBLE (args->args[0]) > DOUBLE (data[0]);
|
||||
break;
|
||||
default: // STRING
|
||||
set = strcmp (args->args[0], data[0]) > 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
set = data[0] == NULL;
|
||||
|
||||
if (set)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < PARAMC; n++)
|
||||
{
|
||||
free (data[n]);
|
||||
|
||||
switch (args->arg_type[0])
|
||||
{
|
||||
case INT_RESULT:
|
||||
set = sizeof (long long);
|
||||
data[n] = malloc (set);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
set = sizeof (double);
|
||||
data[n] = malloc (set);
|
||||
break;
|
||||
default: // STRING
|
||||
set = args->lengths[0];
|
||||
data[n] = malloc (set + 1);
|
||||
((char *) data[n])[set] = '\0';
|
||||
}
|
||||
|
||||
memcpy (data[n], args->args[n], set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void multimax_clear (UDF_INIT *initid, char *is_null, char *error)
|
||||
{
|
||||
void ** data = DATA (initid->ptr);
|
||||
free (data[0]);
|
||||
free (data[1]);
|
||||
data[0] = NULL;
|
||||
data[1] = NULL;
|
||||
}
|
||||
|
||||
my_bool multimax_init (UDF_INIT *initid, UDF_ARGS *args, char *message)
|
||||
{
|
||||
if (args->arg_count == PARAMC)
|
||||
{
|
||||
void ** data = malloc (sizeof (void *) * 2);
|
||||
data[0] = NULL;
|
||||
data[1] = NULL;
|
||||
|
||||
args->arg_type[1] = INT_RESULT;
|
||||
initid->ptr = (void *) data;
|
||||
initid->maybe_null = 0;
|
||||
initid->const_item = 0;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (message, "%s must have %d parameters", NAME, PARAMC);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void multimax_deinit (UDF_INIT *initid)
|
||||
{
|
||||
free (initid->ptr);
|
||||
}
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
#define NAME "multimax"
|
||||
#define NPARAMS 1
|
||||
#define BLOCK_SIZE 1024
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int * org_type;
|
||||
char * data;
|
||||
unsigned long len;
|
||||
unsigned long alloc;
|
||||
}
|
||||
Buffer;
|
||||
|
||||
static void buffer_append (Buffer *buffer, char *string, unsigned long len)
|
||||
{
|
||||
if (!string)
|
||||
return;
|
||||
|
||||
unsigned long new_len = buffer->len + len;
|
||||
|
||||
if (new_len > buffer->alloc)
|
||||
{
|
||||
buffer->alloc = new_len + BLOCK_SIZE - (new_len % BLOCK_SIZE);
|
||||
buffer->data = realloc (buffer->data, sizeof (char) * buffer->alloc);
|
||||
}
|
||||
|
||||
strncpy (&buffer->data[buffer->len], string, len);
|
||||
buffer->len = new_len;
|
||||
}
|
||||
|
||||
char * sql_printf (UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error)
|
||||
{
|
||||
int i = 1;
|
||||
unsigned long j = 0;
|
||||
Buffer *buffer = (Buffer *) initid->ptr;
|
||||
char *format = args->args[0];
|
||||
|
||||
if (!format)
|
||||
{
|
||||
*is_null = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *delimiter = NULL;
|
||||
unsigned long aux = j;
|
||||
|
||||
while (j < args->lengths[0] && format[j] != '%')
|
||||
j++;
|
||||
|
||||
buffer_append (buffer, &format[aux], j - aux);
|
||||
|
||||
if (j == args->lengths[0])
|
||||
break;
|
||||
|
||||
char c = format[j+1];
|
||||
j += 2;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 't':
|
||||
delimiter = "`";
|
||||
break;
|
||||
case 'v':
|
||||
if (buffer->org_type[i] == STRING_RESULT)
|
||||
delimiter = "'";
|
||||
break;
|
||||
case 's':
|
||||
break;
|
||||
case '%':
|
||||
buffer_append (buffer, "%", 1);
|
||||
continue;
|
||||
default:
|
||||
*error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (i >= args->arg_count)
|
||||
{
|
||||
*error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *arg = args->args[i];
|
||||
unsigned long len = args->lengths[i];
|
||||
|
||||
if (!arg)
|
||||
{
|
||||
arg = "NULL";
|
||||
len = strlen (arg);
|
||||
delimiter = NULL;
|
||||
}
|
||||
|
||||
buffer_append (buffer, delimiter, 1);
|
||||
buffer_append (buffer, arg, len);
|
||||
buffer_append (buffer, delimiter, 1);
|
||||
i++;
|
||||
}
|
||||
|
||||
*length = buffer->len;
|
||||
return buffer->data;
|
||||
}
|
||||
|
||||
my_bool sql_printf_init (UDF_INIT *initid, UDF_ARGS *args, char *message)
|
||||
{
|
||||
if (args->arg_count >= NPARAMS)
|
||||
{
|
||||
int i;
|
||||
Buffer *buffer = malloc (sizeof (Buffer));
|
||||
buffer->org_type = malloc (sizeof (int) * args->arg_count);
|
||||
buffer->alloc = BLOCK_SIZE;
|
||||
buffer->data = malloc (sizeof (char) * buffer->alloc);
|
||||
buffer->len = 0;
|
||||
|
||||
for (i = 0; i < args->arg_count; i++)
|
||||
{
|
||||
buffer->org_type[i] = args->arg_type[i];
|
||||
args->arg_type[i] = STRING_RESULT;
|
||||
}
|
||||
|
||||
initid->ptr = (void *) buffer;
|
||||
initid->maybe_null = 1;
|
||||
initid->const_item = 0;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (message, "%s must have at least %d parameters", NAME, NPARAMS);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sql_printf_deinit (UDF_INIT *initid)
|
||||
{
|
||||
Buffer *buffer = (Buffer *) initid->ptr;
|
||||
free (buffer->org_type);
|
||||
free (buffer->data);
|
||||
free (buffer);
|
||||
}
|
||||
|
|
@ -4,8 +4,9 @@ include $(top_srcdir)/Makefile.decl
|
|||
# minacum
|
||||
|
||||
minacum_LTLIBRARIES = minacum.la
|
||||
minacum_la_SOURCES = minacum.c
|
||||
minacum_la_SOURCES = minacum.cc
|
||||
minacum_la_LIBADD = $(vn_mysql_LIBS)
|
||||
minacum_la_CPPFLAGS = $(vn_mysql_CFLAGS)
|
||||
minacum_la_CFLAGS = $(vn_mysql_CFLAGS)
|
||||
minacum_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
||||
minacumdir = $(vn_mysql_libdir)
|
||||
|
@ -13,18 +14,20 @@ minacumdir = $(vn_mysql_libdir)
|
|||
# sql_printf
|
||||
|
||||
sql_printf_LTLIBRARIES = sql_printf.la
|
||||
sql_printf_la_SOURCES = sql_printf.c
|
||||
sql_printf_la_SOURCES = sql_printf.cc
|
||||
sql_printf_la_LIBADD = $(vn_mysql_LIBS)
|
||||
sql_printf_la_CFLAGS = $(vn_mysql_CFLAGS)
|
||||
sql_printf_la_CPPFLAGS = $(vn_mysql_CFLAGS)
|
||||
sql_printf_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
||||
sql_printfdir = $(vn_mysql_libdir)
|
||||
|
||||
# multimax
|
||||
|
||||
multimax_LTLIBRARIES = multimax.la
|
||||
multimax_la_SOURCES = multimax.c
|
||||
multimax_la_SOURCES = multimax.cc
|
||||
multimax_la_LIBADD = $(vn_mysql_LIBS)
|
||||
multimax_la_CFLAGS = $(vn_mysql_CFLAGS)
|
||||
multimax_la_CPPFLAGS = $(vn_mysql_CFLAGS)
|
||||
multimax_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
||||
multimaxdir = $(vn_mysql_libdir)
|
||||
|
||||
|
@ -40,4 +43,3 @@ install-data-hook:
|
|||
|
||||
#$(FILE): $(SRC)
|
||||
# gcc -shared -o $@ $< -fPIC
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
#define NAME "minacum"
|
||||
#define N_ARGS 3
|
||||
|
||||
#define ARG_IVAL 0
|
||||
#define ARG_NUM 1
|
||||
#define ARG_BASE 2
|
||||
|
||||
#define INTERVAL(ptr) ((Interval *) ptr)
|
||||
#define GET_ARG(n) (args->args[n] == NULL ? 0 : *((long long*) args->args[n]))
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef struct _Interval Interval;
|
||||
struct _Interval {
|
||||
long long num;
|
||||
long long sum;
|
||||
Interval* next;
|
||||
};
|
||||
|
||||
void free_data(UDF_INIT *initid) {
|
||||
Interval* ival = INTERVAL(initid->ptr);
|
||||
Interval* cur;
|
||||
while (ival != NULL) {
|
||||
cur = ival;
|
||||
ival = ival->next;
|
||||
free(cur);
|
||||
}
|
||||
initid->ptr = NULL;
|
||||
}
|
||||
|
||||
long long minacum(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) {
|
||||
Interval* ival = INTERVAL(initid->ptr);
|
||||
if (ival == NULL) return 0;
|
||||
|
||||
long long min;
|
||||
long long base = GET_ARG(ARG_BASE);
|
||||
|
||||
if (ival->num == base) {
|
||||
min = ival->sum;
|
||||
ival = ival->next;
|
||||
} else
|
||||
min = 0;
|
||||
|
||||
long long acum = min;
|
||||
|
||||
while (ival != NULL) {
|
||||
acum += ival->sum;
|
||||
if (acum < min) min = acum;
|
||||
ival = ival->next;
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
void minacum_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) {
|
||||
long long num = GET_ARG(ARG_IVAL);
|
||||
long long amount = GET_ARG(ARG_NUM);
|
||||
|
||||
Interval* ival = INTERVAL(initid->ptr);
|
||||
Interval* prev = ival;
|
||||
|
||||
while (ival != NULL && ival->num < num) {
|
||||
prev = ival;
|
||||
ival = ival->next;
|
||||
}
|
||||
|
||||
if (ival == NULL || ival->num > num) {
|
||||
Interval* new_ival = INTERVAL(malloc(sizeof(Interval)));
|
||||
new_ival->num = num;
|
||||
new_ival->sum = amount;
|
||||
new_ival->next = ival;
|
||||
if (prev != ival)
|
||||
prev->next = new_ival;
|
||||
else
|
||||
initid->ptr = (char *) new_ival;
|
||||
} else
|
||||
ival->sum += amount;
|
||||
}
|
||||
|
||||
void minacum_clear(UDF_INIT *initid, char *is_null, char *error) {
|
||||
free_data(initid);
|
||||
}
|
||||
|
||||
bool minacum_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
|
||||
if (args->arg_count == N_ARGS) {
|
||||
args->arg_type[ARG_IVAL] = INT_RESULT;
|
||||
args->arg_type[ARG_NUM] = INT_RESULT;
|
||||
args->arg_type[ARG_BASE] = INT_RESULT;
|
||||
initid->maybe_null = 0;
|
||||
initid->const_item = 0;
|
||||
initid->ptr = NULL;
|
||||
return 0;
|
||||
} else {
|
||||
sprintf(message, "%s must have %d parameters", NAME, N_ARGS);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void minacum_deinit(UDF_INIT *initid) {
|
||||
free_data(initid);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
#define NAME "multimax"
|
||||
#define N_ARGS 2
|
||||
|
||||
#define ARG_MAX 0
|
||||
#define ARG_VALUE 1
|
||||
|
||||
#define DATA(ptr) ((Data *) ptr)
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include "value.cc"
|
||||
|
||||
typedef struct {
|
||||
Value max;
|
||||
Value value;
|
||||
}
|
||||
Data;
|
||||
|
||||
void free_data(UDF_INIT *initid) {
|
||||
Data* data = (Data *) initid->ptr;
|
||||
value_set_null(&data->max);
|
||||
value_set_null(&data->value);
|
||||
}
|
||||
|
||||
long long multimax(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) {
|
||||
Value * value = &DATA(initid->ptr)->value;
|
||||
if (value->is_null) {
|
||||
*is_null = 1;
|
||||
return 0;
|
||||
}
|
||||
return value->val.i;
|
||||
}
|
||||
|
||||
void multimax_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error) {
|
||||
Data *data = (Data *) initid->ptr;
|
||||
Value max;
|
||||
value_from_arg(&max, args, ARG_MAX);
|
||||
|
||||
if (value_compare(&max, &data->max) > 0) {
|
||||
value_copy_arg(&data->max, args, ARG_MAX);
|
||||
value_copy_arg(&data->value, args, ARG_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
void multimax_clear(UDF_INIT *initid, char *is_null, char *error) {
|
||||
free_data(initid);
|
||||
}
|
||||
|
||||
bool multimax_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
|
||||
if (args->arg_count == N_ARGS) {
|
||||
Data *data = DATA(malloc(sizeof(Data)));
|
||||
value_init(&data->max);
|
||||
value_init(&data->value);
|
||||
|
||||
args->arg_type[ARG_VALUE] = INT_RESULT;
|
||||
initid->ptr = (char *) data;
|
||||
initid->maybe_null = 1;
|
||||
initid->const_item = 0;
|
||||
return 0;
|
||||
} else {
|
||||
sprintf(message, "%s must have %d parameters", NAME, N_ARGS);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void multimax_deinit(UDF_INIT *initid) {
|
||||
free_data(initid);
|
||||
free(initid->ptr);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <mysql/mysql.h>
|
||||
|
||||
#define NAME "sql_printf"
|
||||
#define N_ARGS 1
|
||||
#define BLOCK_SIZE 1024
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef struct {
|
||||
int * org_type;
|
||||
char * data;
|
||||
unsigned long len;
|
||||
unsigned long alloc;
|
||||
}
|
||||
Buffer;
|
||||
|
||||
static void buffer_append_len(Buffer *buffer, const char *string, unsigned long len) {
|
||||
if (!string) return;
|
||||
unsigned long new_len = buffer->len + len;
|
||||
|
||||
if (new_len > buffer->alloc) {
|
||||
buffer->alloc = new_len + BLOCK_SIZE - (new_len % BLOCK_SIZE);
|
||||
buffer->data = (char *) realloc(buffer->data, sizeof(char) * buffer->alloc);
|
||||
}
|
||||
|
||||
strncpy(&buffer->data[buffer->len], string, len);
|
||||
buffer->len = new_len;
|
||||
}
|
||||
|
||||
static void buffer_append(Buffer *buffer, const char *string) {
|
||||
if (!string) return;
|
||||
buffer_append_len(buffer, string, strlen(string));
|
||||
}
|
||||
|
||||
char * sql_printf(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
|
||||
unsigned int i = 1;
|
||||
unsigned long j = 0;
|
||||
Buffer *buffer = (Buffer *) initid->ptr;
|
||||
char *format = args->args[0];
|
||||
|
||||
if (!format) {
|
||||
*is_null = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
const char *delimiter = NULL;
|
||||
unsigned long aux = j;
|
||||
|
||||
while (j < args->lengths[0] && format[j] != '%')
|
||||
j++;
|
||||
|
||||
buffer_append_len(buffer, &format[aux], j - aux);
|
||||
|
||||
if (j == args->lengths[0])
|
||||
break;
|
||||
|
||||
char c = format[j+1];
|
||||
j += 2;
|
||||
|
||||
switch (c) {
|
||||
case 't':
|
||||
delimiter = "`";
|
||||
break;
|
||||
case 'v':
|
||||
if (buffer->org_type[i] == STRING_RESULT)
|
||||
delimiter = "'";
|
||||
break;
|
||||
case 's':
|
||||
break;
|
||||
case '%':
|
||||
buffer_append(buffer, "%");
|
||||
continue;
|
||||
default:
|
||||
*error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (i >= args->arg_count) {
|
||||
*error = 1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *arg = args->args[i];
|
||||
unsigned long len = args->lengths[i];
|
||||
|
||||
if (arg) {
|
||||
buffer_append(buffer, delimiter);
|
||||
buffer_append_len(buffer, arg, len);
|
||||
buffer_append(buffer, delimiter);
|
||||
} else
|
||||
buffer_append(buffer, "NULL");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
*length = buffer->len;
|
||||
return buffer->data;
|
||||
}
|
||||
|
||||
bool sql_printf_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
|
||||
if (args->arg_count >= N_ARGS) {
|
||||
unsigned int i;
|
||||
Buffer *buffer = (Buffer *) malloc(sizeof(Buffer));
|
||||
buffer->org_type = (int *) malloc(sizeof(int) * args->arg_count);
|
||||
buffer->alloc = BLOCK_SIZE;
|
||||
buffer->data = (char *) malloc(sizeof(char) * buffer->alloc);
|
||||
buffer->len = 0;
|
||||
|
||||
for (i = 0; i < args->arg_count; i++) {
|
||||
buffer->org_type[i] = args->arg_type[i];
|
||||
args->arg_type[i] = STRING_RESULT;
|
||||
}
|
||||
|
||||
initid->ptr = (char *) buffer;
|
||||
initid->maybe_null = 1;
|
||||
initid->const_item = 0;
|
||||
return 0;
|
||||
} else {
|
||||
sprintf(message, "%s must have at least %d parameters", NAME, N_ARGS);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
void sql_printf_deinit(UDF_INIT *initid) {
|
||||
Buffer *buffer = (Buffer *) initid->ptr;
|
||||
free(buffer->org_type);
|
||||
free(buffer->data);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
// Value handling functions
|
||||
|
||||
#define INT(ptr) (*((long long *) ptr))
|
||||
#define DOUBLE(ptr) (*((double *) ptr))
|
||||
#define min(a,b) (a < b ? a : b)
|
||||
|
||||
typedef union {
|
||||
long long i;
|
||||
double d;
|
||||
char * s;
|
||||
} Val;
|
||||
|
||||
typedef struct {
|
||||
Val val;
|
||||
int is_null;
|
||||
Item_result type;
|
||||
unsigned long len;
|
||||
int free;
|
||||
} Value;
|
||||
|
||||
#define value_ptr(value) (value->is_null ? NULL : (char *) &value->val)
|
||||
|
||||
void value_init(Value * value) {
|
||||
value->is_null = 1;
|
||||
value->free = 0;
|
||||
}
|
||||
|
||||
void value_free_val(Value *value) {
|
||||
if (value->free) free(value->val.s);
|
||||
}
|
||||
|
||||
void value_set_null(Value *value) {
|
||||
value_free_val(value);
|
||||
value->is_null = 1;
|
||||
}
|
||||
|
||||
void value_set(Value * value, UDF_ARGS *args, int arg_index, int copy) {
|
||||
char * arg = args->args[arg_index];
|
||||
value->free = 0;
|
||||
|
||||
if (arg != NULL) {
|
||||
value->is_null = 0;
|
||||
value->type = args->arg_type[arg_index];
|
||||
|
||||
switch (value->type) {
|
||||
case INT_RESULT:
|
||||
value->val.i = INT(arg);
|
||||
break;
|
||||
case REAL_RESULT:
|
||||
value->val.d = DOUBLE(arg);
|
||||
break;
|
||||
default:
|
||||
value->free = copy;
|
||||
value->len = args->lengths[arg_index];
|
||||
if (copy) {
|
||||
value->val.s = (char *) malloc(value->len);
|
||||
memcpy(value->val.s, arg, value->len);
|
||||
} else
|
||||
value->val.s = arg;
|
||||
}
|
||||
} else
|
||||
value->is_null = 1;
|
||||
}
|
||||
|
||||
void value_from_arg(Value * value, UDF_ARGS *args, int arg_index) {
|
||||
value_set(value, args, arg_index, 0);
|
||||
}
|
||||
|
||||
void value_copy_arg(Value * value, UDF_ARGS *args, int arg_index) {
|
||||
value_free_val(value);
|
||||
value_set(value, args, arg_index, 1);
|
||||
}
|
||||
|
||||
int value_compare(Value *a, Value *b) {
|
||||
int cmp;
|
||||
double real_cmp;
|
||||
|
||||
if (!a->is_null && !b->is_null && a->type == b->type) {
|
||||
switch (a->type) {
|
||||
case INT_RESULT:
|
||||
cmp = a->val.i - b->val.i;
|
||||
break;
|
||||
case REAL_RESULT: {
|
||||
real_cmp = a->val.d - b->val.d;
|
||||
cmp = real_cmp == 0.0 ? 0 : (real_cmp > 0.0 ? 1 : -1);
|
||||
break;
|
||||
}
|
||||
default: // STRING_RESULT & DECIMAL_RESULT
|
||||
cmp = strncmp(a->val.s, b->val.s, min(a->len, b->len));
|
||||
if (cmp == 0) cmp = a->len - b->len;
|
||||
}
|
||||
} else
|
||||
cmp = b->is_null;
|
||||
|
||||
return cmp;
|
||||
}
|
Reference in New Issue