├── uninstalldb.sql ├── installdb.sql ├── deps ├── download-cJSON.sh ├── download-hiredis.sh └── Makefile ├── .gitignore ├── LICENSE ├── Makefile ├── README.hant.md ├── lib_mysqludf_redis.c ├── README.jp.md └── README.md /uninstalldb.sql: -------------------------------------------------------------------------------- 1 | USE `mysql`; 2 | 3 | DROP FUNCTION IF EXISTS `redis`; 4 | -------------------------------------------------------------------------------- /installdb.sql: -------------------------------------------------------------------------------- 1 | USE `mysql`; 2 | 3 | DROP FUNCTION IF EXISTS `redis`; 4 | CREATE FUNCTION `redis` RETURNS STRING SONAME 'lib_mysqludf_redis.so'; 5 | -------------------------------------------------------------------------------- /deps/download-cJSON.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | VER=$1 3 | URL="https://github.com/DaveGamble/cJSON/archive/v${VER}.tar.gz" 4 | MODULE_NAME=cJSON 5 | echo "Downloading $URL" 6 | wget $URL -O /tmp/${MODULE_NAME}.tar.gz 7 | tar zxvf /tmp/${MODULE_NAME}.tar.gz 8 | rm -rf ${MODULE_NAME} 9 | mv ${MODULE_NAME}-${VER} ${MODULE_NAME} 10 | -------------------------------------------------------------------------------- /deps/download-hiredis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | VER=$1 3 | URL="https://github.com/redis/hiredis/archive/v${VER}.tar.gz" 4 | MODULE_NAME=hiredis 5 | echo "Downloading $URL" 6 | wget $URL -O /tmp/${MODULE_NAME}.tar.gz 7 | tar zxvf /tmp/${MODULE_NAME}.tar.gz 8 | rm -rf ${MODULE_NAME} 9 | mv ${MODULE_NAME}-${VER} ${MODULE_NAME} 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /deps/Makefile: -------------------------------------------------------------------------------- 1 | # lib_mysqludf_redis dependency Makefile 2 | 3 | HIREDIS_MODULE_VER ?= 4 | CJSON_MODULE_VER ?= 5 | INSTALL_PATH ?= 6 | INSTALL_OPTIONS= 7 | ifneq ("","$(INSTALL_PATH)") 8 | INSTALL_OPTIONS=PREFIX=$(INSTALL_PATH) 9 | endif 10 | 11 | CCCOLOR ="\033[34m" 12 | LINKCOLOR="\033[34;1m" 13 | SRCCOLOR ="\033[33m" 14 | BINCOLOR ="\033[37;1m" 15 | MAKECOLOR="\033[32;1m" 16 | ENDCOLOR ="\033[0m" 17 | 18 | 19 | 20 | 21 | default: 22 | @echo "Explicit target required" 23 | 24 | .PHONY: default 25 | 26 | 27 | 28 | hiredis: 29 | ifeq ("","$(wildcard hiredis)") 30 | ifeq ("","$(HIREDIS_MODULE_VER)") 31 | $(error required HIREDIS_MODULE_VER) 32 | endif 33 | sh download-hiredis.sh $(HIREDIS_MODULE_VER) 34 | endif 35 | @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 36 | cd hiredis && $(MAKE) 37 | @printf '%b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 38 | cd hiredis && $(MAKE) install $(INSTALL_OPTIONS) 39 | 40 | .PHONY: hiredis 41 | 42 | 43 | 44 | cJSON: 45 | ifeq ("","$(wildcard cJSON)") 46 | ifeq ("","$(CJSON_MODULE_VER)") 47 | $(error required CJSON_MODULE_VER) 48 | endif 49 | sh download-cJSON.sh $(CJSON_MODULE_VER) 50 | endif 51 | @printf '%b %b\n' $(MAKECOLOR)MAKE$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 52 | cd cJSON && $(MAKE) 53 | @printf '%b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 54 | cd cJSON && $(MAKE) install $(INSTALL_OPTIONS) 55 | 56 | .PHONY: cJSON 57 | 58 | 59 | 60 | distclean: 61 | -rm -rf hiredis cJSON 62 | 63 | .PHONY: distclean 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, I. sakaiensis 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # lib_mysqludf_redis Makefile 2 | 3 | PLUGIN_SOURCE = lib_mysqludf_redis.c 4 | PLUGIN_NAME = lib_mysqludf_redis 5 | 6 | 7 | # Environment variants 8 | WITH_COMPILE_HIREDIS ?=1 9 | WITH_COMPILE_CJSON ?=1 10 | HIREDIS_MODULE_VER ?=0.13.3 11 | CJSON_MODULE_VER ?=1.6.0 12 | 13 | INCLUDE_PATH ?= 14 | PLUGIN_PATH ?= 15 | 16 | CURRENT_PATH =$(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 17 | 18 | 19 | 20 | # Constant variants 21 | CC = gcc 22 | CFLAGS := -shared -fPIC 23 | CRPATH = -Wl,-rpath,$(PLUGIN_PATH) 24 | COPTIONS = -I$(INCLUDE_PATH) -I./include $(CRPATH) 25 | 26 | 27 | MAKE_CC=$(QUIET_CC)$(CC) 28 | MAKE_LD=$(QUIET_LINK)$(CC) 29 | MAKE_INSTALL=$(QUIET_INSTALL)$(INSTALL) 30 | 31 | 32 | CCCOLOR ="\033[34m" 33 | LINKCOLOR="\033[34;1m" 34 | SRCCOLOR ="\033[33m" 35 | BINCOLOR ="\033[37;1m" 36 | MAKECOLOR="\033[32;1m" 37 | ENDCOLOR ="\033[0m" 38 | 39 | ifndef V 40 | QUIET_CC = @printf ' %b %b\n' $(CCCOLOR)CC$(ENDCOLOR) $(SRCCOLOR)$@$(ENDCOLOR) 1>&2; 41 | QUIET_LINK = @printf ' %b %b\n' $(LINKCOLOR)LINK$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2; 42 | QUIET_INSTALL = @printf ' %b %b\n' $(LINKCOLOR)INSTALL$(ENDCOLOR) $(BINCOLOR)$@$(ENDCOLOR) 1>&2; 43 | endif 44 | 45 | 46 | DYLIBSUFFIX=so 47 | PLUGIN_LIBNAME=$(PLUGIN_NAME).$(DYLIBSUFFIX) 48 | 49 | 50 | # Initialize variants 51 | ifeq ("","$(INCLUDE_PATH)") 52 | INCLUDE_PATH=$(shell mysql_config --variable=pkgincludedir)/server 53 | endif 54 | ifeq ("","$(PLUGIN_PATH)") 55 | PLUGIN_PATH=$(shell mysql_config --plugindir) 56 | endif 57 | DEP_MODULES:= 58 | DEP_LIBRARY:= 59 | ifeq (1,$(WITH_COMPILE_HIREDIS)) 60 | DEP_MODULES:=$(DEP_MODULES) hiredis 61 | DEP_LIBRARY:=$(DEP_LIBRARY) $(PLUGIN_PATH)/libhiredis.so 62 | endif 63 | ifeq (1,$(WITH_COMPILE_CJSON)) 64 | DEP_MODULES:=$(DEP_MODULES) cJSON 65 | DEP_LIBRARY:=$(DEP_LIBRARY) $(PLUGIN_PATH)/libcjson.so 66 | endif 67 | 68 | 69 | 70 | all: $(PLUGIN_LIBNAME) 71 | 72 | #Deps 73 | $(PLUGIN_LIBNAME): $(DEP_MODULES) 74 | ifeq ("","$(PLUGIN_PATH)") 75 | @echo "" 76 | @echo "Cannot find Mysql/MariaDB plugin_dir. Please specified the PLUGIN_PATH argument and try again." 77 | @echo "" 78 | @false 79 | else 80 | @echo "PLUGIN_PATH=$(PLUGIN_PATH)" > .makeconf 81 | endif 82 | cp -a ./lib/libhiredis.* $(PLUGIN_PATH) 83 | -(restorecon $(PLUGIN_PATH)/libhiredis.*) 84 | cp -a ./lib/libcjson.* $(PLUGIN_PATH) 85 | -(restorecon $(PLUGIN_PATH)/libcjson.*) 86 | $(MAKE_CC) $(PLUGIN_SOURCE) $(DEP_LIBRARY) $(CFLAGS) $(COPTIONS) -o $@ 87 | 88 | hiredis: 89 | @(cd deps && $(MAKE) $@ HIREDIS_MODULE_VER=$(HIREDIS_MODULE_VER) INSTALL_PATH=$(CURRENT_PATH) INCLUDE_PATH=include/hiredis) 90 | 91 | cJSON: 92 | @(cd deps && $(MAKE) $@ CJSON_MODULE_VER=$(CJSON_MODULE_VER) INSTALL_PATH=$(CURRENT_PATH) INCLUDE_PATH=include/cjson) 93 | 94 | .PHONY: all 95 | 96 | 97 | 98 | INSTALL?= cp -a 99 | ifneq ("$(wildcard .makeconf)", "") 100 | PLUGIN_PATH=$(shell grep 'PLUGIN_PATH=' .makeconf | awk -F'=' '{print $$2}') 101 | endif 102 | 103 | 104 | install: 105 | $(INSTALL) $(PLUGIN_LIBNAME) $(PLUGIN_PATH) 106 | -(cd $(PLUGIN_PATH) && restorecon $(PLUGIN_LIBNAME)) 107 | -(setsebool -P mysql_connect_any 1) 108 | @printf "\033[1;33m" 109 | @echo "" 110 | @echo "To register UDF, executing the following command:" 111 | @printf "\033[0m""\033[1m" 112 | @echo "" 113 | @echo "$(MAKE) installdb" 114 | @echo "" 115 | @printf "\033[0m" 116 | .PHONY: install 117 | 118 | 119 | 120 | MYSQL_PORT?=$(shell mysql_config --port) 121 | MYSQL=mysql -P $(MYSQL_PORT) -u root -p 122 | 123 | installdb: 124 | $(MYSQL) < installdb.sql 125 | 126 | .PHONY: installdb 127 | 128 | 129 | 130 | uninstalldb: 131 | $(MYSQL) < uninstalldb.sql 132 | 133 | .PHONY: uninstalldb 134 | 135 | 136 | 137 | clean: 138 | @-(rm -f .makeconf) 139 | -rm -f $(PLUGIN_LIBNAME) 140 | -rm -rf include lib 141 | 142 | .PHONY: clean 143 | 144 | 145 | 146 | distclean: clean 147 | -cd ./deps && $(MAKE) distclean 148 | 149 | .PHONY: reset 150 | -------------------------------------------------------------------------------- /README.hant.md: -------------------------------------------------------------------------------- 1 | lib_mysqludf_redis 2 | ================== 3 | 提供一組 UDF 指令於 Mysql/MariaDB 中存取 Redis。 4 | 5 | [English](README.md) | [繁體中文](README.hant.md) | [日本語](README.jp.md) 6 | 7 | 8 | #### 目錄 9 | * [簡介](#%E7%B0%A1%E4%BB%8B) 10 | * [系統需求](#%E7%B3%BB%E7%B5%B1%E9%9C%80%E6%B1%82) 11 | * [編譯與安裝外掛元件](#%E7%B7%A8%E8%AD%AF%E8%88%87%E5%AE%89%E8%A3%9D%E5%A4%96%E6%8E%9B%E5%85%83%E4%BB%B6) 12 | * [編譯參數](#%E7%B7%A8%E8%AD%AF%E5%8F%83%E6%95%B8) 13 | * [編譯變數](#%E7%B7%A8%E8%AD%AF%E8%AE%8A%E6%95%B8) 14 | * [安裝與卸載 UDF](#%E5%AE%89%E8%A3%9D%E8%88%87%E5%8D%B8%E8%BC%89-udf) 15 | * [使用方式](#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F) 16 | * [待完成事項](#%E5%BE%85%E5%AE%8C%E6%88%90%E4%BA%8B%E9%A0%85) 17 | * [授權條款](#%E6%8E%88%E6%AC%8A%E6%A2%9D%E6%AC%BE) 18 | * [相關連結](#%E7%9B%B8%E9%97%9C%E9%80%A3%E7%B5%90) 19 | 20 | 21 | 簡介 22 | ---- 23 | ![Alt text](https://g.gravizo.com/source/figure01?https%3A%2F%2Fraw.githubusercontent.com%2FIdeonella-sakaiensis%2Flib_mysqludf_redis%2Fmaster%2FREADME.md?3) 24 | 25 | 26 | [回目錄](#%E7%9B%AE%E9%8C%84) 27 | 28 | 29 | 系統需求 30 | -------- 31 | * 架構: Linux 64-bit(x64) 32 | * 編譯器: GCC 4.1.2+ 33 | * MariaDB 5.5+ 34 | * Redis 1.2+ 35 | * 相依套件: 36 | * MariaDB development library 5.5+ 37 | * hiredis 0.13.3+ 38 | * cJSON 1.6+ 39 | 40 | [回目錄](#%E7%9B%AE%E9%8C%84) 41 | 42 | 43 | 編譯與安裝外掛元件 44 | ------------------ 45 | 安裝相依套件 46 | > CentOS 47 | > ```bash 48 | > # 安裝工具 49 | > $ yum install -y make wget gcc git 50 | > 51 | > # 安裝 mariadb development tool 52 | > $ yum install -y mariadb-devel 53 | > ``` 54 | 55 | > Debian 56 | > ```bash 57 | > # 安裝工具 58 | > $ apt-get install -y make wget gcc git 59 | > 60 | > # 安裝 mariadb development tool 61 | > $ apt-get install -y libmariadb-dev 62 | > ``` 63 | 64 | > FreeBSD 65 | > ```bash 66 | > # 安裝工具 67 | > $ pkg install -y gmake wget gcc git-lite 68 | > ``` 69 | 70 | 要編譯外掛元件最簡單的方式就是直接執行 `make` 與 `make install`。或於FreeBSD上使用 `gmake` 與 `gmake install`。 71 | ```bash 72 | $ make 73 | 74 | # 安裝外掛程式庫到目的資料夾 75 | $ make install 76 | 77 | # 安裝 UDF 到 Mysql/MariaDB 伺服器 78 | $ make installdb 79 | ``` 80 | > **附記**:如果使用的 Mysql/MariaDB 是早期版本,或是使用手動編譯方式安裝,預設的 include 路徑可能無法使用;請於編譯時使用 `` make INCLUDE_PATH=`mysql_config --variable=pkgincludedir` `` 指定 `INCLUDE_PATH` 變數進行編譯。 81 | 82 | 83 | #### 編譯參數 84 | * `install` 85 | 86 | 安裝外掛程式庫到指定的 Mysql 外掛資料夾。 87 | 88 | * `installdb` 89 | 90 | 安裝/註冊 UDFs 到 Mysql/MariaDB 伺服器。 91 | 92 | * `uninstalldb` 93 | 94 | 卸載/註銷 UDFs。 95 | 96 | * `clean` 97 | 98 | 清除編譯檔案。 99 | 100 | * `distclean` 101 | 102 | 如同 `clean` 指令,且同時還清理相依套件資源。 103 | 104 | #### 編譯變數 105 | 下面是編譯時的變數,可以被使用在 `make`: 106 | * `HIREDIS_MODULE_VER` 107 | 108 | 要提供給元件編譯的 [hiredis](https://github.com/redis/hiredis) 版本。如果該值為空或未指定,其預設值為 `0.13.3`。 109 | 110 | * `CJSON_MODULE_VER` 111 | 112 | 要提供給元件編譯的 [cJSON](https://github.com/DaveGamble/cJSON) 版本。如果該值為空或未指定,其預設值為 `1.6.0`。 113 | 114 | * `INCLUDE_PATH` 115 | 116 | 指定要被參考的 MariaDB/Mysql C 標頭檔。如果該值為空或未指定,其預設值指定為 Mysql `pkgincludedir` 變數。這個值可以經由下列命令取得: 117 | ``` bash 118 | $ echo `mysql_config --variable=pkgincludedir`/server 119 | ``` 120 | 121 | * `PLUGIN_PATH` 122 | 123 | 指定 MariaDB/Mysql 的外掛元件檔案路徑。這個值可以在 MariaDB/Mysql 中,經由 `SHOW VARIABLES LIKE '%plugin_dir%';` 指令取得。如果該值為空或未指定,其預設值指定為 Mysql `plugindir` 變數。這個值可以經由下列命令取得: 124 | ``` bash 125 | $ mysql_config --plugindir 126 | ``` 127 | 128 | 範例: 129 | ```bash 130 | # 指定 MariaDB/Mysql 的外掛元件檔案路徑為 /opt/mysql/plugin 131 | $ make PLUGIN_PATH=/opt/mysql/plugin 132 | $ make install 133 | ``` 134 | [回目錄](#%E7%9B%AE%E9%8C%84) 135 | 136 | 137 | 安裝與卸載 UDF 138 | -------------- 139 | 使用 `make` 安裝 UDF: 140 | 141 | ```bash 142 | $ make installdb 143 | ``` 144 | 145 | > 或於 Mysql/MariaDB 中,手動執行下列 sql 陳述式: 146 | > 147 | > ```sql 148 | > mysql> CREATE FUNCTION `redis` RETURNS STRING SONAME 'lib_mysqludf_redis.so'; 149 | > ``` 150 | 151 | 要卸載/註銷 UDF,可以使用 `make uninstalldb`;或於 Mysql/MariaDB 中,執行下列 sql 陳述式: 152 | ```sql 153 | mysql> DROP FUNCTION IF EXISTS `redis`; 154 | ``` 155 | 156 | [回目錄](#%E7%9B%AE%E9%8C%84) 157 | 158 | 159 | 使用方式 160 | -------- 161 | ### `redis`(*$connection_string*, *$command*, [*$args...*]) 162 | 163 | 呼叫 Redis 命令,藉由指定 `$connection_string`, `$command` 以及命令參數。 164 | 165 | * **$connection_string** - 表示要連線的 Redis 主機,使用 DSN 連線字串表示,其內容必須是下列形式之一: 166 | - **redis**://:_``_**@**_``_:_``_**/**_``_**/** 167 | - **redis**://:_``_**@**_``_**/**_``_**/** 168 | - **redis**://**@**_``_:_``_**/**_``_**/** 169 | - **redis**://**@**_``_**/**_``_**/** 170 | * **$command**, **$args...** - Redis 命令與其參數。請詳見 Redis 官網 [https://redis.io/commands](https://redis.io/commands)。 171 | 172 | 173 | 函式回傳 JSON 字串指示操作成功或失敗。 174 | > 若成功則輸出: 175 | > ```json 176 | > { 177 | > "out": "OK" 178 | > } 179 | > ``` 180 | 181 | > 若失敗則輸出: 182 | > ```json 183 | > { 184 | > "err": "Connection refused" 185 | > } 186 | > ``` 187 | 188 | 下列範例說明函式的使用方式,並且與 `redis-cli` 命令工具作對照。 189 | ```sql 190 | /* 191 | 下面的陳述式如同: 192 | 193 | $ redis-cli -h 127.0.0.1 -n 8 PING 194 | PONG 195 | */ 196 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'PING')\G 197 | *************************** 1. row *************************** 198 | `redis`('redis://@127.0.0.1/8/', 'PING'): { 199 | "out": "PONG" 200 | } 201 | 1 row in set (0.00 sec) 202 | 203 | 204 | 205 | /* 206 | 下面的陳述式如同: 207 | 208 | $ redis-cli -h 127.0.0.1 -a foobared -n 8 PING 209 | PONG 210 | */ 211 | mysql> SELECT `redis`('redis://:foobared@127.0.0.1/8/', 'PING')\G 212 | *************************** 1. row *************************** 213 | `redis`('redis://:foobared@127.0.0.1/8/', 'PING'): { 214 | "out": "PONG" 215 | } 216 | 1 row in set (0.00 sec) 217 | 218 | 219 | 220 | /* 221 | $ redis-cli -h 127.0.0.1 -p 80 -n 8 PING 222 | Could not connect to Redis at 127.0.0.1:80: Connection refused 223 | */ 224 | mysql> SELECT `redis`('redis://@127.0.0.1:80/8/', 'PING')\G 225 | *************************** 1. row *************************** 226 | `redis`('redis://@127.0.0.1:80/8/', 'PING'): { 227 | "err": "Connection refused" 228 | } 229 | 1 row in set (0.00 sec) 230 | 231 | 232 | 233 | /* 234 | $ redis-cli -h 127.0.0.1 -n 8 HMSET myhash field1 Hello field2 World 235 | OK 236 | */ 237 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'HMSET', 'myhash', 'field1', 'Hello', 'field2', 'World')\G 238 | *************************** 1. row *************************** 239 | `redis`('redis://@127.0.0.1/8/', 'HMSET', 'myhash', 'field1', 'Hello', 'field2', 'World'): { 240 | "out": "OK" 241 | } 242 | 1 row in set (0.00 sec) 243 | 244 | 245 | 246 | /* 247 | $ redis-cli -h 127.0.0.1 -n 8 HGET myhash field1 248 | "Hello" 249 | */ 250 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'HGET', 'myhash', 'field1')\G 251 | *************************** 1. row *************************** 252 | `redis`('redis://@127.0.0.1/8/', 'HGET', 'myhash', 'field1'): { 253 | "out": "Hello" 254 | } 255 | 1 row in set (0.00 sec) 256 | 257 | 258 | 259 | -- redis-cli -h 127.0.0.1 -n 0 SET foo bar 260 | mysql> SELECT `redis`('redis://@127.0.0.1/0/', 'SET', 'foo', 'bar') 261 | 262 | -- redis-cli -h 127.0.0.1 -n 0 SCAN 0 MATCH prefix* 263 | mysql> SELECT `redis`('redis://@127.0.0.1/0/', 'SCAN', '0', 'MATCH', 'prefix*') 264 | ``` 265 | 266 | [回目錄](#%E7%9B%AE%E9%8C%84) 267 | 268 | 269 | 待完成事項 270 | ---------- 271 | - [x] 實作 Redis 連線驗證機制。(2017-12-30) 272 | - [ ] 補充 redis DSN 字串建構函式。 273 | 274 | [回目錄](#%E7%9B%AE%E9%8C%84) 275 | 276 | 277 | 授權條款 278 | -------- 279 | 請參閱 [LICENSE](LICENSE)。 280 | 281 | [回目錄](#%E7%9B%AE%E9%8C%84) 282 | 283 | 284 | 相關連結 285 | -------- 286 | 287 | [回目錄](#%E7%9B%AE%E9%8C%84) 288 | -------------------------------------------------------------------------------- /lib_mysqludf_redis.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #define REDIS_HOST "127.0.0.1" 13 | #define REDIS_PORT 6379 14 | #define ushort unsigned short 15 | #define uint unsigned int 16 | #define TRUE 1 17 | #define FALSE 0 18 | 19 | typedef struct st_foreign_server { 20 | bool parsed; 21 | 22 | char *connection_string; 23 | char *scheme; 24 | char *hostname; 25 | char *username; 26 | char *password; 27 | char *database; 28 | char *table_name; 29 | ushort port; 30 | 31 | uint table_name_length, connect_string_length; 32 | } FOREIGN_SERVER; 33 | 34 | 35 | static void 36 | freeServerShare(FOREIGN_SERVER *share) { 37 | if (share != NULL) { 38 | if (share->connection_string != NULL) { 39 | free(share->connection_string); 40 | } 41 | free(share); 42 | } 43 | } 44 | 45 | 46 | static int 47 | parse_url(FOREIGN_SERVER *share) { 48 | share->port= 0; 49 | 50 | /* 51 | No :// or @ in connection string. Must be a straight connection name of 52 | either "servername" or "servername/tablename" 53 | */ 54 | if ( (!strstr(share->connection_string, "://") && 55 | (!strchr(share->connection_string, '@'))) ) { 56 | goto error; 57 | } else { 58 | share->parsed= TRUE; 59 | // Add a null for later termination of table name 60 | share->connection_string[share->connect_string_length]= 0; 61 | share->scheme= share->connection_string; 62 | 63 | /* 64 | Remove addition of null terminator and store length 65 | for each string in share 66 | */ 67 | if (!(share->username= (char *)strstr(share->scheme, "://"))) 68 | goto error; 69 | share->scheme[share->username - share->scheme]= '\0'; 70 | 71 | if (strcmp(share->scheme, "redis")) 72 | goto error; 73 | 74 | share->username+= 3; 75 | 76 | if (!(share->hostname= (char *)strchr(share->username, '@'))) 77 | goto error; 78 | *share->hostname++= '\0'; 79 | 80 | if ((share->password= (char *)strchr(share->username, ':'))) { 81 | *share->password++= '\0'; 82 | 83 | /* make sure there isn't an extra / or @ */ 84 | if ((strchr(share->password, '/') || strchr(share->hostname, '@'))) 85 | goto error; 86 | /* 87 | Found that if the string is: 88 | user:@hostname:port/db/table 89 | Then password is a null string, so set to NULL 90 | */ 91 | if (share->password[0] == '\0') 92 | share->password= NULL; 93 | } 94 | 95 | /* make sure there isn't an extra / or @ */ 96 | if ((strchr(share->username, '/')) || (strchr(share->hostname, '@'))) 97 | goto error; 98 | 99 | if (!(share->database= (char *)strchr(share->hostname, '/'))) 100 | goto error; 101 | *share->database++= '\0'; 102 | 103 | char* port = NULL; 104 | if ((port= (char *)strchr(share->hostname, ':'))) { 105 | *port++= '\0'; 106 | share->port= atoi(port); 107 | } 108 | 109 | if (!(share->table_name= (char *)strchr(share->database, '/'))) 110 | goto error; 111 | *share->table_name++= '\0'; 112 | 113 | share->table_name_length= strlen(share->table_name); 114 | 115 | /* make sure there's not an extra / */ 116 | if ((strchr(share->table_name, '/'))) 117 | goto error; 118 | 119 | if (share->hostname[0] == '\0') 120 | share->hostname= NULL; 121 | 122 | } 123 | if (!share->port) { 124 | share->port= REDIS_PORT; 125 | } 126 | if (!share->hostname) { 127 | share->hostname= REDIS_HOST; 128 | } 129 | 130 | return 0; 131 | 132 | error: 133 | return -1; 134 | } 135 | 136 | 137 | static cJSON* 138 | getJsonReply(redisReply *reply, cJSON *json) { 139 | cJSON *array = NULL; 140 | if (json == NULL) { 141 | json = cJSON_CreateObject(); 142 | } 143 | 144 | switch (reply->type) { 145 | case REDIS_REPLY_STRING: 146 | cJSON_AddStringToObject(json, "out", reply->str); 147 | break; 148 | 149 | case REDIS_REPLY_ARRAY: 150 | array = cJSON_CreateArray(); 151 | cJSON_AddItemToObject(json, "out", array); 152 | unsigned int i; 153 | for (i = 0; i < reply->elements; i++) { 154 | getJsonReply(reply->element[i], array); 155 | } 156 | break; 157 | 158 | case REDIS_REPLY_INTEGER: 159 | cJSON_AddNumberToObject(json, "out", reply->integer); 160 | break; 161 | 162 | case REDIS_REPLY_NIL: 163 | cJSON_AddNullToObject(json, "out"); 164 | break; 165 | 166 | case REDIS_REPLY_STATUS: 167 | cJSON_AddStringToObject(json, "out", reply->str); 168 | break; 169 | 170 | case REDIS_REPLY_ERROR: 171 | cJSON_AddStringToObject(json, "err", reply->str); 172 | break; 173 | } 174 | 175 | return json; 176 | } 177 | 178 | 179 | static char* 180 | getResultFromRedisReply(redisReply *reply) { 181 | char *result; 182 | cJSON *jsonReply = getJsonReply(reply, NULL); 183 | { 184 | result = cJSON_Print(jsonReply); 185 | } 186 | cJSON_Delete(jsonReply); 187 | return result; 188 | } 189 | 190 | static char* 191 | getErrorResult(char *message) { 192 | char *result; 193 | cJSON *json = cJSON_CreateObject(); 194 | cJSON_AddStringToObject(json, "err", message); 195 | { 196 | result = cJSON_Print(json); 197 | } 198 | cJSON_Delete(json); 199 | return result; 200 | } 201 | 202 | 203 | /********************************** 204 | redis 205 | 206 | redis(server, command, args...); 207 | 208 | RETURN json 209 | */ 210 | 211 | my_bool 212 | redis_init(UDF_INIT *initid, 213 | UDF_ARGS *args, 214 | char *message) 215 | { 216 | if (args->arg_count < 2) { 217 | strcpy(message, "requires at last two arguments."); 218 | return EXIT_FAILURE; 219 | } 220 | if (args->args[0] == NULL || args->args[1] == NULL) { 221 | initid->ptr = NULL; 222 | } else { 223 | if (args->arg_type[0] != STRING_RESULT || 224 | args->arg_type[1] != STRING_RESULT) { 225 | strcpy(message, "invalid arguments."); 226 | return EXIT_FAILURE; 227 | } 228 | } 229 | 230 | initid->maybe_null = 1; 231 | return EXIT_SUCCESS; 232 | } 233 | 234 | 235 | void 236 | redis_deinit(UDF_INIT *initid) 237 | { 238 | if (initid->ptr != NULL) { 239 | free(initid->ptr); 240 | } 241 | } 242 | 243 | 244 | char* 245 | redis(UDF_INIT *initid, 246 | UDF_ARGS *args, 247 | char *result, 248 | unsigned long *length, 249 | char *is_null, 250 | char *error) 251 | { 252 | // check arguments 253 | if (args->args[0] == NULL || args->args[1] == NULL) { 254 | *is_null = 1; 255 | return NULL; 256 | } else { 257 | if (args->arg_type[0] != STRING_RESULT || 258 | args->arg_type[1] != STRING_RESULT) { 259 | // invalid arguments 260 | *error = 1; 261 | return NULL; 262 | } 263 | } 264 | 265 | FOREIGN_SERVER *server = NULL; 266 | redisContext *ctx = NULL; 267 | redisReply *reply = NULL; 268 | 269 | server = malloc(sizeof(FOREIGN_SERVER)); 270 | if (server == NULL) { 271 | // out of memory 272 | *error = 1; 273 | goto final; 274 | } 275 | 276 | // import argument server 277 | server->connection_string = strdup(args->args[0]); 278 | server->connect_string_length = (unsigned short)args->lengths[0]; 279 | 280 | 281 | if (parse_url(server) != 0) { 282 | result = getErrorResult("invalid connection string"); 283 | goto final; 284 | } 285 | 286 | // connection to redis 287 | ctx = redisConnect(server->hostname, server->port); 288 | if (ctx != NULL && ctx->err) { 289 | result = getErrorResult(ctx->errstr); 290 | goto final; 291 | } 292 | // send AUTH command to redis 293 | if (server->password != NULL) { 294 | reply = redisCommand(ctx, "AUTH %s", server->password); 295 | if (reply != NULL) { 296 | if (reply->type == REDIS_REPLY_ERROR) { 297 | result = getResultFromRedisReply(reply); 298 | goto final; 299 | } 300 | freeReplyObject(reply); 301 | } 302 | } 303 | // send SELECT dbnum to redis 304 | if (server->database != 0) { 305 | reply = redisCommand(ctx, "SELECT %s", server->database); 306 | if (reply != NULL) { 307 | if (reply->type == REDIS_REPLY_ERROR) { 308 | result = getResultFromRedisReply(reply); 309 | goto final; 310 | } 311 | freeReplyObject(reply); 312 | } 313 | } 314 | 315 | int argc = args->arg_count - 1; 316 | char **argv = ++args->args; 317 | size_t *argvlen = ++args->lengths; 318 | reply = redisCommandArgv(ctx, argc, (const char**)argv, (const size_t*)argvlen); 319 | result = getResultFromRedisReply(reply); 320 | 321 | final: 322 | if (reply != NULL) freeReplyObject(reply); 323 | if (ctx != NULL) redisFree(ctx); 324 | if (server != NULL) freeServerShare(server); 325 | 326 | if (result != NULL) { 327 | *length = strlen(result); 328 | initid->max_length = *length; 329 | initid->ptr = result; 330 | } else { 331 | *is_null = 1; 332 | } 333 | return result; 334 | } 335 | -------------------------------------------------------------------------------- /README.jp.md: -------------------------------------------------------------------------------- 1 | lib_mysqludf_redis 2 | ================== 3 | Mysql/MariaDBのRedisにアクセスするための一連のUDF命令を提供する。 4 | 5 | [English](README.md) | [繁體中文](README.hant.md) | [日本語](README.jp.md) 6 | 7 | 8 | #### ディレクトリ 9 | * [はじめに](#%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB) 10 | * [システム要件](#%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0%E8%A6%81%E4%BB%B6) 11 | * [プラグインコンポーネントのコンパイルとインストール](#%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%81%A8%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) 12 | * [コンパイルのパラメータ](#%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF) 13 | * [コンパイルの変數](#%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%AB%E3%81%AE%E5%A4%89%E6%95%B8) 14 | * [UDF インストールとアンインストール](#udf-%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%A8%E3%82%A2%E3%83%B3%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB) 15 | * [使用方式](#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F) 16 | * [完成するために](#%E5%AE%8C%E6%88%90%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AB) 17 | * [ライセンス条項](#%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E6%9D%A1%E9%A0%85) 18 | * [関連リンク](#%E9%96%A2%E9%80%A3%E3%83%AA%E3%83%B3%E3%82%AF) 19 | 20 | 21 | はじめに 22 | -------- 23 | ![Alt text](https://g.gravizo.com/source/figure01?https%3A%2F%2Fraw.githubusercontent.com%2FIdeonella-sakaiensis%2Flib_mysqludf_redis%2Fmaster%2FREADME.md?3) 24 | 25 | [ディレクトリへ](#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA) 26 | 27 | 28 | システム要件 29 | ------------ 30 | * オペレーティングシステム: Linux 64-bit(x64) 31 | * コンパイラ: GCC 4.1.2+ 32 | * MariaDB 5.5+ 33 | * Redis 1.2+ 34 | * 依存キット: 35 | * MariaDB development library 5.5+ 36 | * hiredis 0.13.3+ 37 | * cJSON 1.6+ 38 | 39 | [ディレクトリへ](#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA) 40 | 41 | 42 | プラグインコンポーネントのコンパイルとインストール 43 | -------------------------------------------------- 44 | 依存関係キットをインストールする 45 | > CentOS 46 | > ```bash 47 | > # ツールをインストールする 48 | > $ yum install -y make wget gcc git 49 | > 50 | > # mariadb development tool をインストールする 51 | > $ yum install -y mariadb-devel 52 | > ``` 53 | 54 | > Debian 55 | > ```bash 56 | > # ツールをインストールする 57 | > $ apt-get install -y make wget gcc git 58 | > 59 | > # mariadb development tool をインストールする 60 | > $ apt-get install -y libmariadb-dev 61 | > ``` 62 | 63 | > FreeBSD 64 | > ```bash 65 | > # ツールをインストールする 66 | > $ pkg install -y gmake wget gcc git-lite 67 | > ``` 68 | 69 | プラグインコンポーネントをコンパイルする最も簡単な方法は、プラグインコンポーネント `make` と `make install` を直接実行することです。あるいは `gmake`と` gmake install`をFreeBSDにインストールします。 70 | ```bash 71 | $ make 72 | 73 | # プラグインライブラリをインストール先フォルダにインストールする 74 | $ make install 75 | 76 | # Mysql/MariaDB サーバーに UDF をインストールする 77 | $ make installdb 78 | ``` 79 | > **注**:以前のバージョンの Mysql/MariaDB を使用している場合、または手動コンパイルを使用している場合は、デフォルトのインクルードパスが使用できない場合があります;コンパイル時に `INCLUDE_PATH` 変数を指定するには `` make INCLUDE_PATH=`mysql_config --variable=pkgincludedir` `` を使用してください。 80 | 81 | 82 | #### コンパイルのパラメータ 83 | * `install` 84 | 85 | 指定したMysqlプラグインフォルダにプラグインライブラリをインストールします。 86 | 87 | * `installdb` 88 | 89 | Mysql/MariaDB サーバーにUDFsをインストール/登録します。 90 | 91 | * `uninstalldb` 92 | 93 | UDFsのアンロード/登録解除。 94 | 95 | * `clean` 96 | 97 | コンパイルされたファイルをクリアします。 98 | 99 | * `distclean` 100 | 101 | `clean` 指示文と同様に、同時に依存関係を取り除きます。 102 | 103 | #### コンパイルの変數 104 | 以下は、`make` で使用できるコンパイル時の変数です: 105 | * `HIREDIS_MODULE_VER` 106 | 107 | コンポーネントのコンパイルのために提供される [hiredis](https://github.com/redis/hiredis) バージョン。値が空であるか、または指定されていない場合、デフォルトは `0.13.3`です。 108 | 109 | * `CJSON_MODULE_VER` 110 | 111 | コンポーネントのコンパイルのために提供される [cJSON](https://github.com/DaveGamble/cJSON) バージョン。値が空であるか、または指定されていない場合、デフォルトは `1.6.0`です。 112 | 113 | * `INCLUDE_PATH` 114 | 115 | 参照する MariaDB/Mysql C ヘッダを指定します。 値が空白または指定されていない場合、デフォルトは `pkgincludedir` です。この値は次のコマンドで取得できます: 116 | ``` bash 117 | $ echo `mysql_config --variable=pkgincludedir`/server 118 | ``` 119 | 120 | * `PLUGIN_PATH` 121 | 122 | MariaDB/Mysql プラグインファイルのパスを指定する。この値はMariaDB/Mysqlのなかに,`SHOW VARIABLES LIKE '%plugin_dir%';`コマンドで取得できます。値が空であるか、または指定されていない場合、 デフォルトは Mysqlの `plugindir` 変數です。この値は次のコマンドで取得できます: 123 | ``` bash 124 | $ mysql_config --plugindir 125 | ``` 126 | 127 | 例: 128 | ```bash 129 | # MariaDB/Mysql を指定するプラグインのファイルパスは /opt/mysql/plugin です。 130 | $ make PLUGIN_PATH=/opt/mysql/plugin 131 | $ make install 132 | ``` 133 | [ディレクトリへ](#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA) 134 | 135 | 136 | UDF インストールとアンインストール 137 | -------------------- 138 | `make`を使ってUDFをインストールしてください: 139 | ```bash 140 | $ make installdb 141 | ``` 142 | 143 | > または Mysql/MariaDB で、次のSQL文を手動で実行します: 144 | > 145 | > ```sql 146 | > mysql> CREATE FUNCTION `redis` RETURNS STRING SONAME 'lib_mysqludf_redis.so'; 147 | > ``` 148 | 149 | UDF をアンインストール/アン登録するには、`make uninstalldb` を使います;または Mysql/MariaDB で、次のSQL文を手動で実行します: 150 | ```sql 151 | mysql> DROP FUNCTION IF EXISTS `redis`; 152 | ``` 153 | 154 | [ディレクトリへ](#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA) 155 | 156 | 157 | 使用方式 158 | -------- 159 | ### `redis`(*$connection_string*, *$command*, [*$args...*]) 160 | 161 | Redisコマンドを使用するため,`$ connection_string`、` $ command`とコマンドパラメータを指定すること。 162 | 163 | * **$connection_string** - 接続するRedisホストを示します,DSN接続文字列表現を使用する,その内容は次のいずれかでなければなりません: 164 | - **redis**://:_``_**@**_``_:_``_**/**_``_**/** 165 | - **redis**://:_``_**@**_``_**/**_``_**/** 166 | - **redis**://**@**_``_:_``_**/**_``_**/** 167 | - **redis**://**@**_``_**/**_``_**/** 168 | * **$command**, **$args...** - Redisコマンドとそのパラメータ。Redis公式サイトをご覧ください [https://redis.io/commands](https://redis.io/commands)。 169 | 170 | 171 | この関数は、操作が成功したか失敗したかを示すJSON文字列を返します。 172 | > 成功した場合: 173 | > ```json 174 | > { 175 | > "out": "OK" 176 | > } 177 | > ``` 178 | 179 | > 失敗した場合: 180 | > ```json 181 | > { 182 | > "err": "Connection refused" 183 | > } 184 | > ``` 185 | 186 | 次の例では、関数の使用方法と `redis-cli`コマンドツールとの比較を示します。 187 | ```sql 188 | /* 189 | 次のステートメントは同じです: 190 | 191 | $ redis-cli -h 127.0.0.1 -n 8 PING 192 | PONG 193 | */ 194 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'PING')\G 195 | *************************** 1. row *************************** 196 | `redis`('redis://@127.0.0.1/8/', 'PING'): { 197 | "out": "PONG" 198 | } 199 | 1 row in set (0.00 sec) 200 | 201 | 202 | 203 | /* 204 | 次のステートメントは同じです: 205 | 206 | $ redis-cli -h 127.0.0.1 -a foobared -n 8 PING 207 | PONG 208 | */ 209 | mysql> SELECT `redis`('redis://:foobared@127.0.0.1/8/', 'PING')\G 210 | *************************** 1. row *************************** 211 | `redis`('redis://:foobared@127.0.0.1/8/', 'PING'): { 212 | "out": "PONG" 213 | } 214 | 1 row in set (0.00 sec) 215 | 216 | 217 | 218 | /* 219 | $ redis-cli -h 127.0.0.1 -p 80 -n 8 PING 220 | Could not connect to Redis at 127.0.0.1:80: Connection refused 221 | */ 222 | mysql> SELECT `redis`('redis://@127.0.0.1:80/8/', 'PING')\G 223 | *************************** 1. row *************************** 224 | `redis`('redis://@127.0.0.1:80/8/', 'PING'): { 225 | "err": "Connection refused" 226 | } 227 | 1 row in set (0.00 sec) 228 | 229 | 230 | 231 | /* 232 | $ redis-cli -h 127.0.0.1 -n 8 HMSET myhash field1 Hello field2 World 233 | OK 234 | */ 235 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'HMSET', 'myhash', 'field1', 'Hello', 'field2', 'World')\G 236 | *************************** 1. row *************************** 237 | `redis`('redis://@127.0.0.1/8/', 'HMSET', 'myhash', 'field1', 'Hello', 'field2', 'World'): { 238 | "out": "OK" 239 | } 240 | 1 row in set (0.00 sec) 241 | 242 | 243 | 244 | /* 245 | $ redis-cli -h 127.0.0.1 -n 8 HGET myhash field1 246 | "Hello" 247 | */ 248 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'HGET', 'myhash', 'field1')\G 249 | *************************** 1. row *************************** 250 | `redis`('redis://@127.0.0.1/8/', 'HGET', 'myhash', 'field1'): { 251 | "out": "Hello" 252 | } 253 | 1 row in set (0.00 sec) 254 | 255 | 256 | 257 | -- redis-cli -h 127.0.0.1 -n 0 SET foo bar 258 | mysql> SELECT `redis`('redis://@127.0.0.1/0/', 'SET', 'foo', 'bar') 259 | 260 | -- redis-cli -h 127.0.0.1 -n 0 SCAN 0 MATCH prefix* 261 | mysql> SELECT `redis`('redis://@127.0.0.1/0/', 'SCAN', '0', 'MATCH', 'prefix*') 262 | ``` 263 | 264 | [ディレクトリへ](#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA) 265 | 266 | 267 | 完成するために 268 | -------------- 269 | - [x] Redis 接続検証機構の実現。 270 | - [ ] redis DSN文字列コンストラクタを補足する。 271 | 272 | [ディレクトリへ](#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA) 273 | 274 | 275 | ライセンス条項 276 | -------------- 277 | [LICENSE](LICENSE) を参照してください。 278 | 279 | [ディレクトリへ](#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA) 280 | 281 | 282 | 関連リンク 283 | ---------- 284 | 285 | [ディレクトリへ](#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA) 286 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lib_mysqludf_redis 2 | ================== 3 | Provides UDF commands to access Redis from Mysql/MariaDB. 4 | 5 | [English](README.md) | [繁體中文](README.hant.md) | [日本語](README.jp.md) 6 | 7 | 8 | #### Table of Contents 9 | * [Synopsis](#synopsis) 10 | * [System Requirements](#system-requirements) 11 | * [Compilation and Install Plugin Library](#compilation-and-install-plugin-library) 12 | * [Compilation Argumnets](#compilation-argumnets) 13 | * [Compilation Variable](#compilation-variable) 14 | * [Install and Uninstall UDF](#install-and-uninstall-udf) 15 | * [Usage](#usage) 16 | * [TODO](#todo) 17 | * [Copyright and License](#copyright-and-license) 18 | * [See Also](#see-also) 19 | 20 | 21 | Synopsis 22 | -------- 23 | ![Alt text](https://g.gravizo.com/source/figure01?https%3A%2F%2Fraw.githubusercontent.com%2FIdeonella-sakaiensis%2Flib_mysqludf_redis%2Fmaster%2FREADME.md?3) 24 |
25 | 26 | figure01 27 | digraph G { 28 | 29 | rankdir = "LR"; 30 | size ="8,8"; 31 | edge [ 32 | fontname = "Consolas" 33 | fontsize = 10 34 | ]; 35 | MariaDB [ 36 | label = "MariaDB\n(presistence)" 37 | shape = "box" 38 | ]; 39 | Redis [ 40 | label = "Redis\n(cached)" 41 | shape = "box" 42 | ]; 43 | edge [ 44 | fontcolor = "blue" 45 | color = "blue" 46 | ]; 47 | writer; 48 | writer:e -> MariaDB [ 49 | label="INSERT\nUPDATE\nDELETE" 50 | ]; 51 | MariaDB -> Redis [ 52 | label = "SET" 53 | ]; 54 | edge [ 55 | fontcolor = "red" 56 | color = "red" 57 | ]; 58 | reader; 59 | reader:e -> MariaDB [ 60 | label="SELECT" 61 | ]; 62 | MariaDB -> Redis [ 63 | label = "GET" 64 | ]; 65 | edge [ 66 | fontcolor = "default" 67 | color = "default" 68 | dir ="none" 69 | arrowhead="none" 70 | arrowtail="none" 71 | penwidth = 0.5 72 | style="dashed" 73 | ]; 74 | node [ 75 | fontname = "Consolas" 76 | fontsize = 10 77 | penwidth = 0.5 78 | color = "gray" 79 | shape = "record" 80 | style = "rounded" 81 | ]; 82 | MariaDB_Data [ 83 | label = <
MariaDB data
itemqty
shoes35
books158
> 84 | ]; 85 | { 86 | rank = "same"; 87 | MariaDB:n -> MariaDB_Data:s; 88 | } 89 | Redis_Data [ 90 | label = <
Redis data
itemqty
shoes35
books158
> 91 | ]; 92 | { 93 | rank = "same"; 94 | Redis:n -> Redis_Data:s; 95 | } 96 | } 97 | figure01 98 |
99 | 100 | 101 | [Back to TOC](#table-of-contents) 102 | 103 | 104 | System Requirements 105 | ------------------- 106 | * Architectures: Linux 64-bit(x64) 107 | * Compilers: GCC 4.1.2+ 108 | * MariaDB 5.5+ 109 | * Redis 1.2+ 110 | * Dependencies: 111 | * MariaDB development library 5.5+ 112 | * hiredis 0.13.3+ 113 | * cJSON 1.6+ 114 | 115 | [Back to TOC](#table-of-contents) 116 | 117 | 118 | Compilation and Install Plugin Library 119 | -------------------------------------- 120 | Installing compilation tools 121 | > CentOS 122 | > ```bash 123 | > # install tools 124 | > $ yum install -y make wget gcc git 125 | > 126 | > # install mariadb development tool 127 | > $ yum install -y mariadb-devel 128 | > ``` 129 | 130 | > Debian 131 | > ```bash 132 | > # install tools 133 | > $ apt-get install -y make wget gcc git 134 | > 135 | > # install mariadb development tool 136 | > $ apt-get install -y libmariadb-dev 137 | > ``` 138 | 139 | > FreeBSD 140 | > ```bash 141 | > # install tools 142 | > $ pkg install -y gmake wget gcc git-lite 143 | > ``` 144 | 145 | To compile the plugin library just simply type `make` and `make install`. -or- `gmake` and `gmake install` on FreeBSD. 146 | ```bash 147 | $ make 148 | 149 | # install plugin library to plugin directory 150 | $ make install 151 | 152 | # install UDF to Mysql/MariaDB server 153 | $ make installdb 154 | ``` 155 | > **NOTE**: If the Mysql/MariaDB is an earlier version or installed from source code, the default include path might be invalid; use `` make INCLUDE_PATH=`mysql_config --variable=pkgincludedir` `` to assign `INCLUDE_PATH` variable for compilation. 156 | 157 | 158 | #### Compilation Argumnets 159 | * `install` 160 | 161 | Install the plugin library to Mysql plugin directory. 162 | 163 | * `installdb` 164 | 165 | Install UDFs to Mysql/MariaDB server. 166 | 167 | * `uninstalldb` 168 | 169 | Uninstall UDFs from Mysql/MariaDB server. 170 | 171 | * `clean` 172 | 173 | Clear the compiled files and resources. 174 | 175 | * `distclean` 176 | 177 | Like the `clean` and also remove the dependencies resources. 178 | 179 | #### Compilation Variable 180 | The compilation variable can be use in `make`: 181 | * `HIREDIS_MODULE_VER` 182 | 183 | The [hiredis](https://github.com/redis/hiredis) version to be compiled. If it is not specified, the default value is `0.13.3`. 184 | 185 | * `CJSON_MODULE_VER` 186 | 187 | The [cJSON](https://github.com/DaveGamble/cJSON) version to be compiled. If it is not specified, the default value is `1.6.0` 188 | 189 | * `INCLUDE_PATH` 190 | 191 | The MariaDB or Mysql C header path. If it is not specified, the default will be the Mysql variable `pkgincludedir`. The value can be displayed by executing the following command: 192 | ``` bash 193 | $ echo `mysql_config --variable=pkgincludedir`/server 194 | ``` 195 | 196 | * `PLUGIN_PATH` 197 | 198 | The MariaDB or Mysql plugin path. The value can be obtained via running the sql statement `SHOW VARIABLES LIKE '%plugin_dir%';` in MariaDB/Mysql server. If it is not specified, the default will be Mysql variable `plugindir`. The value can be displayed by executing the following command: 199 | ``` bash 200 | $ mysql_config --plugindir 201 | ``` 202 | 203 | example: 204 | ```bash 205 | # specify the plugin install path with /opt/mysql/plugin 206 | $ make PLUGIN_PATH=/opt/mysql/plugin 207 | $ make install 208 | ``` 209 | [Back to TOC](#table-of-contents) 210 | 211 | 212 | Install and Uninstall UDF 213 | ------------------------- 214 | To install UDF from `make`: 215 | 216 | ```bash 217 | $ make installdb 218 | ``` 219 | 220 | > or executing the following sql statement on Mysql/MariaDB server: 221 | > 222 | > ```sql 223 | > mysql> CREATE FUNCTION `redis` RETURNS STRING SONAME 'lib_mysqludf_redis.so'; 224 | > ``` 225 | 226 | To uninstall UDF with `make uninstalldb` -or- executing the following sql statement on Mysql/MariaDB server: 227 | 228 | ```sql 229 | mysql> DROP FUNCTION IF EXISTS `redis`; 230 | ``` 231 | 232 | [Back to TOC](#table-of-contents) 233 | 234 | 235 | Usage 236 | ----- 237 | ### `redis`(*$connection_string*, *$command*, [*$args...*]) 238 | 239 | Call a Redis command by specified `$connection_string`, `$command`, and individual arguments. 240 | 241 | * **$connection_string** - represent the Redis server to be connected, the value is a DSN connection string, must be one of following type: 242 | - **redis**://:_``_**@**_``_:_``_**/**_``_**/** 243 | - **redis**://:_``_**@**_``_**/**_``_**/** 244 | - **redis**://**@**_``_:_``_**/**_``_**/** 245 | - **redis**://**@**_``_**/**_``_**/** 246 | * **$command**, **$args...** - the Redis command and arguments. See also [https://redis.io/commands](https://redis.io/commands) for further details. 247 | 248 | 249 | The function returns a JSON string indicating success or failure of the operation. 250 | > the success output: 251 | > ```json 252 | > { 253 | > "out": "OK" 254 | > } 255 | > ``` 256 | 257 | > the failure output: 258 | > ```json 259 | > { 260 | > "err": "Connection refused" 261 | > } 262 | > ``` 263 | 264 | The following examples illustrate how to use the function contrast with `redis-cli` utility. 265 | ```sql 266 | /* 267 | the following statement likes: 268 | 269 | $ redis-cli -h 127.0.0.1 -n 8 PING 270 | PONG 271 | */ 272 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'PING')\G 273 | *************************** 1. row *************************** 274 | `redis`('redis://@127.0.0.1/8/', 'PING'): { 275 | "out": "PONG" 276 | } 277 | 1 row in set (0.00 sec) 278 | 279 | 280 | 281 | /* 282 | the following statement likes: 283 | 284 | $ redis-cli -h 127.0.0.1 -a foobared -n 8 PING 285 | PONG 286 | */ 287 | mysql> SELECT `redis`('redis://:foobared@127.0.0.1/8/', 'PING')\G 288 | *************************** 1. row *************************** 289 | `redis`('redis://:foobared@127.0.0.1/8/', 'PING'): { 290 | "out": "PONG" 291 | } 292 | 1 row in set (0.00 sec) 293 | 294 | 295 | 296 | /* 297 | $ redis-cli -h 127.0.0.1 -p 80 -n 8 PING 298 | Could not connect to Redis at 127.0.0.1:80: Connection refused 299 | */ 300 | mysql> SELECT `redis`('redis://@127.0.0.1:80/8/', 'PING')\G 301 | *************************** 1. row *************************** 302 | `redis`('redis://@127.0.0.1:80/8/', 'PING'): { 303 | "err": "Connection refused" 304 | } 305 | 1 row in set (0.00 sec) 306 | 307 | 308 | 309 | /* 310 | $ redis-cli -h 127.0.0.1 -n 8 HMSET myhash field1 Hello field2 World 311 | OK 312 | */ 313 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'HMSET', 'myhash', 'field1', 'Hello', 'field2', 'World')\G 314 | *************************** 1. row *************************** 315 | `redis`('redis://@127.0.0.1/8/', 'HMSET', 'myhash', 'field1', 'Hello', 'field2', 'World'): { 316 | "out": "OK" 317 | } 318 | 1 row in set (0.00 sec) 319 | 320 | 321 | 322 | /* 323 | $ redis-cli -h 127.0.0.1 -n 8 HGET myhash field1 324 | "Hello" 325 | */ 326 | mysql> SELECT `redis`('redis://@127.0.0.1/8/', 'HGET', 'myhash', 'field1')\G 327 | *************************** 1. row *************************** 328 | `redis`('redis://@127.0.0.1/8/', 'HGET', 'myhash', 'field1'): { 329 | "out": "Hello" 330 | } 331 | 1 row in set (0.00 sec) 332 | 333 | 334 | 335 | -- redis-cli -h 127.0.0.1 -n 0 SET foo bar 336 | mysql> SELECT `redis`('redis://@127.0.0.1/0/', 'SET', 'foo', 'bar') 337 | 338 | -- redis-cli -h 127.0.0.1 -n 0 SCAN 0 MATCH prefix* 339 | mysql> SELECT `redis`('redis://@127.0.0.1/0/', 'SCAN', '0', 'MATCH', 'prefix*') 340 | ``` 341 | 342 | [Back to TOC](#table-of-contents) 343 | 344 | 345 | TODO 346 | ---- 347 | - [x] implement Redis Authentication (2017-12-30) 348 | - [ ] add redis DSN string builder function 349 | 350 | [Back to TOC](#table-of-contents) 351 | 352 | 353 | Copyright and License 354 | --------------------- 355 | See [LICENSE](LICENSE) for further details. 356 | 357 | [Back to TOC](#table-of-contents) 358 | 359 | 360 | See Also 361 | --------- 362 | 363 | [Back to TOC](#table-of-contents) 364 | --------------------------------------------------------------------------------