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
|
*.lo
|
||||||
*.o
|
*.o
|
||||||
*.la
|
*.la
|
||||||
|
config.ini
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I build/m4
|
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`
|
mysql_CFLAGS = `mysql_config --cflags`
|
||||||
|
|
||||||
vn_mysql_libdir = /usr/lib/mysql/plugin
|
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 = \
|
vn_mysql_CFLAGS = \
|
||||||
-Wall -O3 \
|
-Wall -O3 \
|
||||||
$(mysql_CFLAGS)
|
$(mysql_CFLAGS)
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
vn_mysql_LDFLAGS = \
|
vn_mysql_LDFLAGS = \
|
||||||
-no-undefined \
|
-no-undefined \
|
||||||
-module \
|
-module \
|
||||||
-avoid-version \
|
-avoid-version \
|
||||||
-export-dynamic \
|
-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
|
exit 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
$dir/debian/rules clean
|
||||||
rm -rf $dir/build
|
rm -rf $dir/build
|
||||||
rm -rf $dir/configure
|
rm -rf $dir/configure
|
||||||
rm -rf $dir/gtk-doc.make
|
rm -rf $dir/gtk-doc.make
|
||||||
|
|
|
@ -9,14 +9,15 @@ AM_INIT_AUTOMAKE()
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
|
|
||||||
# Check for program dependencies
|
# Check for program dependencies
|
||||||
AC_PROG_CC
|
|
||||||
AC_PROG_CXX
|
AC_PROG_CXX
|
||||||
|
AC_PROG_CC
|
||||||
PKG_CHECK_MODULES([glib], [glib-2.0])
|
PKG_CHECK_MODULES([glib], [glib-2.0])
|
||||||
|
|
||||||
|
AM_CONDITIONAL([MYSQL8], [test ! -z "$MYSQL8"])
|
||||||
|
|
||||||
AC_CONFIG_FILES([
|
AC_CONFIG_FILES([
|
||||||
Makefile
|
Makefile
|
||||||
src/Makefile
|
proxy-auth/Makefile
|
||||||
src/proxy-auth/Makefile
|
udfs/Makefile
|
||||||
src/functions/Makefile
|
|
||||||
])
|
])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
vn-mysql (1.5.0) unstable; urgency=low
|
vn-mysql (1.6.0) unstable; urgency=low
|
||||||
|
|
||||||
* Initial Release.
|
* Initial Release.
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,13 @@ Source: vn-mysql
|
||||||
Section: misc
|
Section: misc
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: Alejandro T. Colombini Gómez <atcolombini@verdnatura.es>
|
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
|
Standards-Version: 3.9.4
|
||||||
Homepage: http://www.verdnatura.es
|
Homepage: http://www.verdnatura.es
|
||||||
|
|
||||||
Package: vn-mysql
|
Package: vn-mysql
|
||||||
Architecture: any
|
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
|
Description: MySQL plugins
|
||||||
This package contains some useful MySQL plugins
|
This package contains some useful MySQL plugins
|
||||||
developed by Verdnatura.
|
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.ini
|
||||||
|
|
||||||
proxy_auth_LTLIBRARIES = proxy_auth.la
|
proxy_auth_LTLIBRARIES = proxy_auth.la
|
||||||
proxy_auth_la_SOURCES = proxy-auth.c
|
proxy_auth_la_SOURCES = proxy-auth.cc
|
||||||
proxy_auth_la_LIBADD = \
|
proxy_auth_la_LIBADD = \
|
||||||
$(glib_LIBS) \
|
$(glib_LIBS) \
|
||||||
$(vn_mysql_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
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* 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,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* 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/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MYSQL_ABI_CHECK
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <glib-unix.h>
|
||||||
|
|
||||||
|
#ifndef MYSQL8
|
||||||
|
#define MYSQL_ABI_CHECK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#include <stdbool.h>
|
||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
#include <mysql/errmsg.h>
|
#include <mysql/errmsg.h>
|
||||||
#include <mysql/plugin_auth.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 CONFIG_FILE _CONFIG_DIR"/proxy-auth.ini"
|
||||||
#define SQL_FILE _SQL_DIR"/proxy-auth.sql"
|
#define SQL_FILE _SQL_DIR"/proxy-auth.sql"
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
gboolean initialized;
|
gboolean initialized;
|
||||||
gchar * socket;
|
gchar * socket;
|
||||||
gchar * host;
|
gchar * host;
|
||||||
|
@ -49,8 +57,7 @@ typedef struct
|
||||||
}
|
}
|
||||||
ProxyAuth;
|
ProxyAuth;
|
||||||
|
|
||||||
typedef struct
|
typedef struct {
|
||||||
{
|
|
||||||
MYSQL * conn;
|
MYSQL * conn;
|
||||||
gchar * user;
|
gchar * user;
|
||||||
gulong user_len;
|
gulong user_len;
|
||||||
|
@ -60,8 +67,7 @@ typedef struct
|
||||||
RegexData;
|
RegexData;
|
||||||
|
|
||||||
ProxyAuth *
|
ProxyAuth *
|
||||||
proxy_auth_new()
|
proxy_auth_new() {
|
||||||
{
|
|
||||||
ProxyAuth * self = g_new(ProxyAuth, 1);
|
ProxyAuth * self = g_new(ProxyAuth, 1);
|
||||||
self->initialized = FALSE;
|
self->initialized = FALSE;
|
||||||
g_mutex_init(&self->mutex);
|
g_mutex_init(&self->mutex);
|
||||||
|
@ -69,8 +75,7 @@ proxy_auth_new()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
proxy_auth_deinit(ProxyAuth * self)
|
proxy_auth_deinit(ProxyAuth * self) {
|
||||||
{
|
|
||||||
if (!self->initialized)
|
if (!self->initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -92,8 +97,7 @@ proxy_auth_deinit(ProxyAuth * self)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
proxy_auth_free(ProxyAuth * self)
|
proxy_auth_free(ProxyAuth * self) {
|
||||||
{
|
|
||||||
g_return_if_fail(self != NULL);
|
g_return_if_fail(self != NULL);
|
||||||
|
|
||||||
proxy_auth_deinit(self);
|
proxy_auth_deinit(self);
|
||||||
|
@ -102,8 +106,7 @@ proxy_auth_free(ProxyAuth * self)
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
proxy_auth_init(ProxyAuth * self)
|
proxy_auth_init(ProxyAuth * self) {
|
||||||
{
|
|
||||||
g_return_val_if_fail(self != NULL, FALSE);
|
g_return_val_if_fail(self != NULL, FALSE);
|
||||||
|
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
|
@ -129,8 +132,7 @@ proxy_auth_init(ProxyAuth * self)
|
||||||
|
|
||||||
GKeyFile * key_file = g_key_file_new();
|
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);
|
g_warning("ProxyAuth: Can't open configuration file: %s", error->message);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -150,8 +152,7 @@ proxy_auth_init(ProxyAuth * self)
|
||||||
|
|
||||||
// Reading the query template
|
// 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);
|
g_warning("ProxyAuth: Can't read the query template: %s", error->message);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -159,10 +160,9 @@ proxy_auth_init(ProxyAuth * self)
|
||||||
// Creates the regular expression
|
// Creates the regular expression
|
||||||
|
|
||||||
self->regex = g_regex_new("#\\w+",
|
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);
|
g_warning("ProxyAuth: Can't create the regex: %s", error->message);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -184,27 +184,22 @@ end:
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
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;
|
RegexData * regex_data = (RegexData *) data;
|
||||||
gchar * match = g_match_info_fetch(info, 0);
|
gchar * match = g_match_info_fetch(info, 0);
|
||||||
|
|
||||||
gchar * str = NULL;
|
gchar * str = NULL;
|
||||||
gulong str_len;
|
gulong str_len;
|
||||||
|
|
||||||
if (!g_strcmp0(match, "#user"))
|
if (!g_strcmp0(match, "#user")) {
|
||||||
{
|
|
||||||
str = regex_data->user;
|
str = regex_data->user;
|
||||||
str_len = regex_data->user_len;
|
str_len = regex_data->user_len;
|
||||||
}
|
} else if (!g_strcmp0(match, "#pass")) {
|
||||||
else if (!g_strcmp0(match, "#pass"))
|
|
||||||
{
|
|
||||||
str = regex_data->pass;
|
str = regex_data->pass;
|
||||||
str_len = regex_data->pass_len;
|
str_len = regex_data->pass_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str)
|
if (str) {
|
||||||
{
|
|
||||||
unsigned long scaped_len;
|
unsigned long scaped_len;
|
||||||
char escaped_str[str_len * 2 + 1];
|
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_len(res, escaped_str,(gssize) scaped_len);
|
||||||
g_string_append_c(res, '\'');
|
g_string_append_c(res, '\'');
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
g_string_append(res, match);
|
g_string_append(res, match);
|
||||||
|
|
||||||
g_free(match);
|
g_free(match);
|
||||||
|
@ -225,8 +219,7 @@ proxy_auth_regex_func(const GMatchInfo * info, GString * res, gpointer data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
proxy_auth_reconnect(ProxyAuth * self, MYSQL * conn)
|
proxy_auth_reconnect(ProxyAuth * self, MYSQL * conn) {
|
||||||
{
|
|
||||||
g_return_val_if_fail(self != NULL, FALSE);
|
g_return_val_if_fail(self != NULL, FALSE);
|
||||||
|
|
||||||
gboolean connected = mysql_real_connect(conn,
|
gboolean connected = mysql_real_connect(conn,
|
||||||
|
@ -243,8 +236,7 @@ proxy_auth_reconnect(ProxyAuth * self, MYSQL * conn)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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);
|
g_return_val_if_fail(self != NULL, CR_ERROR);
|
||||||
|
|
||||||
int res = 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;
|
int user_len = info->user_name_length;
|
||||||
|
|
||||||
if (info->user_name == NULL
|
if (info->user_name == NULL
|
||||||
&&(user_len = vio->read_packet(vio, &pkt)) < 0)
|
&& (user_len = vio->read_packet(vio, &pkt)) < 0)
|
||||||
return CR_ERROR;
|
return CR_ERROR;
|
||||||
|
|
||||||
if (user_len > MYSQL_USERNAME_LENGTH)
|
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)
|
if (pass_len < 0)
|
||||||
return CR_ERROR;
|
return CR_ERROR;
|
||||||
|
|
||||||
if (!pass_len || *pkt == '\0')
|
if (!pass_len || *pkt == '\0') {
|
||||||
{
|
|
||||||
info->password_used = PASSWORD_USED_NO;
|
info->password_used = PASSWORD_USED_NO;
|
||||||
return CR_ERROR;
|
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);
|
MYSQL * conn = (MYSQL *) g_async_queue_try_pop(self->conn_pool);
|
||||||
|
|
||||||
if (!conn)
|
if (!conn) {
|
||||||
{
|
|
||||||
g_mutex_lock(&self->mutex);
|
g_mutex_lock(&self->mutex);
|
||||||
|
|
||||||
if (self->pool_size < self->max_connections)
|
if (self->pool_size < self->max_connections) {
|
||||||
{
|
|
||||||
self->pool_size++;
|
self->pool_size++;
|
||||||
g_mutex_unlock(&self->mutex);
|
g_mutex_unlock(&self->mutex);
|
||||||
|
|
||||||
conn = mysql_init(NULL);
|
conn = mysql_init(NULL);
|
||||||
|
|
||||||
if (!proxy_auth_reconnect(self, conn))
|
if (!proxy_auth_reconnect(self, conn)) {
|
||||||
{
|
|
||||||
g_mutex_lock(&self->mutex);
|
g_mutex_lock(&self->mutex);
|
||||||
self->pool_size--;
|
self->pool_size--;
|
||||||
g_mutex_unlock(&self->mutex);
|
g_mutex_unlock(&self->mutex);
|
||||||
|
@ -307,16 +295,13 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
||||||
conn = NULL;
|
conn = NULL;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
{
|
|
||||||
g_mutex_unlock(&self->mutex);
|
g_mutex_unlock(&self->mutex);
|
||||||
conn = (MYSQL *) g_async_queue_pop(self->conn_pool);
|
conn = (MYSQL *) g_async_queue_pop(self->conn_pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mysql_errno(conn))
|
switch (mysql_errno(conn)) {
|
||||||
{
|
|
||||||
case CR_SERVER_LOST:
|
case CR_SERVER_LOST:
|
||||||
case CR_SERVER_GONE_ERROR:
|
case CR_SERVER_GONE_ERROR:
|
||||||
if (!proxy_auth_reconnect(self, conn))
|
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;
|
regex_data.pass_len = pass_len;
|
||||||
|
|
||||||
query = g_regex_replace_eval(self->regex,
|
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);
|
g_warning("ProxyAuth: Can't evaluate regex: %s", error->message);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -349,16 +333,13 @@ proxy_auth_authenticate(ProxyAuth * self, MYSQL_PLUGIN_VIO * vio, MYSQL_SERVER_A
|
||||||
MYSQL_RES * result;
|
MYSQL_RES * result;
|
||||||
|
|
||||||
if (!mysql_query(conn, query)
|
if (!mysql_query(conn, query)
|
||||||
&&(result = mysql_store_result(conn)))
|
&& (result = mysql_store_result(conn))) {
|
||||||
{
|
|
||||||
MYSQL_ROW row = mysql_fetch_row(result);
|
MYSQL_ROW row = mysql_fetch_row(result);
|
||||||
|
|
||||||
if (row && row[0])
|
if (row && row[0]) {
|
||||||
{
|
|
||||||
unsigned long row_len = mysql_fetch_lengths(result)[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);
|
strcpy(info->external_user, info->user_name);
|
||||||
strncpy(info->authenticated_as, row[0], row_len);
|
strncpy(info->authenticated_as, row[0], row_len);
|
||||||
info->authenticated_as[row_len] = '\0';
|
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);
|
mysql_free_result(result);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
g_warning("ProxyAuth: Error executing query: %s", mysql_error(conn));
|
g_warning("ProxyAuth: Error executing query: %s", mysql_error(conn));
|
||||||
end:
|
end:
|
||||||
if (conn)
|
if (conn)
|
||||||
|
@ -385,21 +365,18 @@ end:
|
||||||
ProxyAuth * pauth = NULL;
|
ProxyAuth * pauth = NULL;
|
||||||
|
|
||||||
static int
|
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);
|
return proxy_auth_authenticate(pauth, vio, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
proxy_auth_plugin_init()
|
proxy_auth_plugin_init(MYSQL_PLUGIN plugin_info) {
|
||||||
{
|
|
||||||
pauth = proxy_auth_new();
|
pauth = proxy_auth_new();
|
||||||
return proxy_auth_init(pauth) ? 0 : 1;
|
return proxy_auth_init(pauth) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
proxy_auth_plugin_deinit()
|
proxy_auth_plugin_deinit(MYSQL_PLUGIN plugin_info) {
|
||||||
{
|
|
||||||
proxy_auth_free(pauth);
|
proxy_auth_free(pauth);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -408,8 +385,7 @@ int
|
||||||
generate_auth_string_hash(
|
generate_auth_string_hash(
|
||||||
char *outbuf, unsigned int *buflen,
|
char *outbuf, unsigned int *buflen,
|
||||||
const char *inbuf,
|
const char *inbuf,
|
||||||
unsigned int inbuflen)
|
unsigned int inbuflen) {
|
||||||
{
|
|
||||||
if (*buflen < inbuflen)
|
if (*buflen < inbuflen)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
@ -421,8 +397,7 @@ generate_auth_string_hash(
|
||||||
int
|
int
|
||||||
validate_auth_string_hash(
|
validate_auth_string_hash(
|
||||||
char* const inbuf __attribute__((unused)),
|
char* const inbuf __attribute__((unused)),
|
||||||
unsigned int buflen __attribute__((unused)))
|
unsigned int buflen __attribute__((unused))) {
|
||||||
{
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,26 +406,26 @@ set_salt(
|
||||||
const char* password __attribute__((unused)),
|
const char* password __attribute__((unused)),
|
||||||
unsigned int password_len __attribute__((unused)),
|
unsigned int password_len __attribute__((unused)),
|
||||||
unsigned char* salt __attribute__((unused)),
|
unsigned char* salt __attribute__((unused)),
|
||||||
unsigned char* salt_len)
|
unsigned char* salt_len) {
|
||||||
{
|
|
||||||
*salt_len = 0;
|
*salt_len = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct st_mysql_auth
|
static struct st_mysql_auth
|
||||||
proxy_auth_handler =
|
proxy_auth_handler = {
|
||||||
{
|
|
||||||
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
|
MYSQL_AUTHENTICATION_INTERFACE_VERSION,
|
||||||
"mysql_clear_password", // Cleartext plugin required in the client
|
"mysql_clear_password", // Cleartext plugin required in the client
|
||||||
proxy_auth_plugin_main,
|
proxy_auth_plugin_main,
|
||||||
generate_auth_string_hash,
|
generate_auth_string_hash,
|
||||||
validate_auth_string_hash,
|
validate_auth_string_hash,
|
||||||
set_salt,
|
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,
|
MYSQL_AUTHENTICATION_PLUGIN,
|
||||||
&proxy_auth_handler,
|
&proxy_auth_handler,
|
||||||
"proxy_auth",
|
"proxy_auth",
|
||||||
|
@ -458,6 +433,9 @@ mysql_declare_plugin(proxy_auth)
|
||||||
"Proxy user authentication server-side plugin",
|
"Proxy user authentication server-side plugin",
|
||||||
PLUGIN_LICENSE_GPL,
|
PLUGIN_LICENSE_GPL,
|
||||||
proxy_auth_plugin_init,
|
proxy_auth_plugin_init,
|
||||||
|
#ifdef MYSQL8
|
||||||
|
NULL,
|
||||||
|
#endif
|
||||||
proxy_auth_plugin_deinit,
|
proxy_auth_plugin_deinit,
|
||||||
0x0100, // version 1.0,
|
0x0100, // version 1.0,
|
||||||
NULL,
|
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
|
#!/bin/bash
|
||||||
|
|
||||||
CONCURRENCY=400
|
CONCURRENCY=50
|
||||||
NATTEMPS=40
|
NATTEMPS=500
|
||||||
|
|
||||||
I=0
|
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
|
||||||
|
|
||||||
minacum_LTLIBRARIES = minacum.la
|
minacum_LTLIBRARIES = minacum.la
|
||||||
minacum_la_SOURCES = minacum.c
|
minacum_la_SOURCES = minacum.cc
|
||||||
minacum_la_LIBADD = $(vn_mysql_LIBS)
|
minacum_la_LIBADD = $(vn_mysql_LIBS)
|
||||||
|
minacum_la_CPPFLAGS = $(vn_mysql_CFLAGS)
|
||||||
minacum_la_CFLAGS = $(vn_mysql_CFLAGS)
|
minacum_la_CFLAGS = $(vn_mysql_CFLAGS)
|
||||||
minacum_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
minacum_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
||||||
minacumdir = $(vn_mysql_libdir)
|
minacumdir = $(vn_mysql_libdir)
|
||||||
|
@ -13,18 +14,20 @@ minacumdir = $(vn_mysql_libdir)
|
||||||
# sql_printf
|
# sql_printf
|
||||||
|
|
||||||
sql_printf_LTLIBRARIES = sql_printf.la
|
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_LIBADD = $(vn_mysql_LIBS)
|
||||||
sql_printf_la_CFLAGS = $(vn_mysql_CFLAGS)
|
sql_printf_la_CFLAGS = $(vn_mysql_CFLAGS)
|
||||||
|
sql_printf_la_CPPFLAGS = $(vn_mysql_CFLAGS)
|
||||||
sql_printf_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
sql_printf_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
||||||
sql_printfdir = $(vn_mysql_libdir)
|
sql_printfdir = $(vn_mysql_libdir)
|
||||||
|
|
||||||
# multimax
|
# multimax
|
||||||
|
|
||||||
multimax_LTLIBRARIES = multimax.la
|
multimax_LTLIBRARIES = multimax.la
|
||||||
multimax_la_SOURCES = multimax.c
|
multimax_la_SOURCES = multimax.cc
|
||||||
multimax_la_LIBADD = $(vn_mysql_LIBS)
|
multimax_la_LIBADD = $(vn_mysql_LIBS)
|
||||||
multimax_la_CFLAGS = $(vn_mysql_CFLAGS)
|
multimax_la_CFLAGS = $(vn_mysql_CFLAGS)
|
||||||
|
multimax_la_CPPFLAGS = $(vn_mysql_CFLAGS)
|
||||||
multimax_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
multimax_la_LDFLAGS = $(vn_mysql_LDFLAGS)
|
||||||
multimaxdir = $(vn_mysql_libdir)
|
multimaxdir = $(vn_mysql_libdir)
|
||||||
|
|
||||||
|
@ -40,4 +43,3 @@ install-data-hook:
|
||||||
|
|
||||||
#$(FILE): $(SRC)
|
#$(FILE): $(SRC)
|
||||||
# gcc -shared -o $@ $< -fPIC
|
# 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