Merge branch '10.1' into 10.2

This commit is contained in:
Sergei Golubchik 2017-11-21 19:47:46 +01:00
commit 7f1900705b
1859 changed files with 171405 additions and 108428 deletions

View File

@ -2952,10 +2952,11 @@ int main(int argc, char** argv)
if (!argc || opt_version)
{
if (!argc)
usage();
if (!opt_version)
{
usage();
retval= ERROR_STOP;
}
goto err;
}

View File

@ -26,7 +26,7 @@ ENDIF()
OPTION(WITH_WSREP "WSREP replication API (to use, e.g. Galera Replication library)" ${with_wsrep_default})
# Set the patch version
SET(WSREP_PATCH_VERSION "20")
SET(WSREP_PATCH_VERSION "21")
# Obtain wsrep API version
FILE(STRINGS "${MySQL_SOURCE_DIR}/wsrep/wsrep_api.h" WSREP_API_VERSION

View File

@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "write_filt.h"
#include "fil_cur.h"
#include "xtrabackup.h"
#include <os0proc.h>
/************************************************************************
Write-through page write filter. */
@ -67,19 +68,22 @@ wf_incremental_init(xb_write_filt_ctxt_t *ctxt, char *dst_name,
xb_fil_cur_t *cursor)
{
char meta_name[FN_REFLEN];
ulint buf_size;
xb_wf_incremental_ctxt_t *cp =
&(ctxt->u.wf_incremental_ctxt);
ctxt->cursor = cursor;
/* allocate buffer for incremental backup (4096 pages) */
buf_size = (cursor->page_size.physical() / 4 + 1)
* cursor->page_size.physical();
cp->delta_buf_base = static_cast<byte *>(malloc(buf_size));
memset(cp->delta_buf_base, 0, buf_size);
cp->delta_buf = static_cast<byte *>
(ut_align(cp->delta_buf_base, cursor->page_size.physical()));
cp->delta_buf_size = (cursor->page_size.physical() / 4)
* cursor->page_size.physical();
cp->delta_buf = (unsigned char *)os_mem_alloc_large(&cp->delta_buf_size);
if (!cp->delta_buf) {
msg("[%02u] mariabackup: Error: "
"cannot allocate %zu bytes\n",
cursor->thread_n, (size_t) cp->delta_buf_size);
return (FALSE);
}
/* write delta meta info */
snprintf(meta_name, sizeof(meta_name), "%s%s", dst_name,
@ -183,8 +187,7 @@ static void
wf_incremental_deinit(xb_write_filt_ctxt_t *ctxt)
{
xb_wf_incremental_ctxt_t *cp = &(ctxt->u.wf_incremental_ctxt);
free(cp->delta_buf_base);
os_mem_free_large(cp->delta_buf, cp->delta_buf_size);
}
/************************************************************************

View File

@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
/* Incremental page filter context */
typedef struct {
byte *delta_buf_base;
ulint delta_buf_size;
byte *delta_buf;
ulint npages;
} xb_wf_incremental_ctxt_t;

View File

@ -2,8 +2,3 @@
# suite.pm will make sure that all tests including this file
# will be skipped unless this is a debug build.
#
# The test below is redundant
if (`select version() not like '%debug%'`) {
--skip Needs a debug build
}

View File

@ -1,14 +1,4 @@
#
# Check if server has support for loading plugins
# suite.pm will make sure that all tests including this file
# will be skipped unless dynamic ha_example plugin is available
#
if (`SELECT @@have_dynamic_loading != 'YES'`) {
--skip Example plugin requires dynamic loading
}
#
# Check if the variable EXAMPLE_PLUGIN is set
#
if (!$HA_EXAMPLE_SO) {
--skip Need example plugin
}

View File

@ -2,9 +2,3 @@
# suite.pm will make sure that all tests including this file
# will be skipped unless innodb or xtradb is enabled
#
# The test below is redundant
if (`SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.ENGINES WHERE engine = 'innodb' AND support IN ('YES', 'DEFAULT', 'ENABLED')`)
{
--skip Test requires InnoDB.
}

View File

@ -2,10 +2,3 @@
# suite.pm will make sure that all tests including this file
# will be skipped unless xtradb is enabled
#
# The test below is redundant
if (!`SELECT count(*) FROM information_schema.plugins WHERE
plugin_name = 'innodb' AND plugin_status = 'active' AND
plugin_description LIKE '%xtradb%'`){
skip Needs XtraDB engine;
}

View File

@ -2,9 +2,3 @@
# suite.pm will make sure that all tests including this file
# will be skipped unless this is an embedded test run
#
# The test below is redundant
if (`select version() like '%embedded%'`) {
This should never happen;
}

View File

@ -1,4 +1,4 @@
--require r/not_windows.require
disable_query_log;
select convert(@@version_compile_os using latin1) NOT IN ("Win32","Win64","Windows") as "TRUE";
enable_query_log;
#
# suite.pm will make sure that all tests including this file
# will be skipped unless this is on Windows
#

View File

@ -0,0 +1,15 @@
# ==== Purpose ====
#
# Extract Gtid_list info from SHOW BINLOG EVENTS output masking
# non-deterministic fields.
#
# ==== Usage ====
#
# [--let $binlog_file=filename
#
if ($binlog_file)
{
--let $_in_binlog_file=in '$binlog_file'
}
--replace_column 2 # 5 #
--eval show binlog events $_in_binlog_file limit 1,1

View File

@ -1258,3 +1258,4 @@ DELIMITER ;
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
mysqlbinlog Ver VER for OS at ARCH

View File

@ -1,2 +0,0 @@
TRUE
1

View File

@ -8115,6 +8115,18 @@ CALL p();
drop procedure p;
drop view v;
drop table t, tmp_t;
#
# MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
#
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(i) FROM v1 );
REPLACE INTO v1 VALUES (f1());
ERROR HY000: The target table v1 of the INSERT is not insertable-into
SET @aux = f1();
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
#End of 10.1 tests
#
# MDEV-11081: CURSOR for query with GROUP BY

View File

@ -2329,6 +2329,23 @@ DROP TRIGGER t1_bi;
DROP TABLE t1;
SET TIMESTAMP=DEFAULT;
set time_zone= @@global.time_zone;
#
# MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
#
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
CREATE TABLE t2 (a int);
CREATE TABLE t3 (a int);
create trigger trg after insert on t2 for each row
INSERT INTO t3 SELECT MAX(i) FROM v1 UNION SELECT MAX(i) FROM v1;
drop table t1;
insert into t2 value (2);
ERROR 42S02: Table 'test.t1' doesn't exist
CREATE TABLE t1 (i INT);
insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
End of 10.1 tests.
create table t1 (i int);
create trigger tr1 after insert on t1 for each row set @a=@a+1;
create trigger tr2 after insert on t1 for each row set @a=@a+1;

View File

@ -0,0 +1,78 @@
RESET MASTER;
FLUSH BINARY LOGS DELETE_DOMAIN_ID = ();
and the command execution is effective thence rotates binlog as usual
show binary logs;
Log_name File_size
master-bin.000001 #
master-bin.000002 #
Non-existed domain is warned, the command completes without rotation
but with a warning
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (99);
Warnings:
Warning 1076 The gtid domain being deleted ('99') is not in the current binlog state
show binary logs;
Log_name File_size
master-bin.000001 #
master-bin.000002 #
SET @@SESSION.gtid_domain_id=1;
SET @@SESSION.server_id=1;
CREATE TABLE t (a int);
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
ERROR HY000: Could not delete gtid domain. Reason: binlog files may contain gtids from the domain ('1') being deleted. Make sure to first purge those files.
FLUSH BINARY LOGS;
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
ERROR HY000: Could not delete gtid domain. Reason: binlog files may contain gtids from the domain ('1') being deleted. Make sure to first purge those files.
PURGE BINARY LOGS TO 'master-bin.000003';;
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
Gtid_list of the current binlog does not contain '1':
show binlog events in 'master-bin.000004' limit 1,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000004 # Gtid_list 1 # []
But the previous log's Gtid_list may have it which explains a warning from the following command
show binlog events in 'master-bin.000003' limit 1,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000003 # Gtid_list 1 # [1-1-1]
Already deleted domain in Gtid_list of the earliest log is benign
but may cause a warning
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
Warnings:
Warning 1076 The current gtid binlog state is incompatible with a former one missing gtids from the '1-1' domain-server pair which is referred to in the gtid list describing an earlier state. Ignore if the domain ('1') was already explicitly deleted.
Warning 1076 The gtid domain being deleted ('1') is not in the current binlog state
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0);
ERROR HY000: Could not delete gtid domain. Reason: binlog files may contain gtids from the domain ('1') being deleted. Make sure to first purge those files.
FLUSH BINARY LOGS;
PURGE BINARY LOGS TO 'master-bin.000005';
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0);
Warnings:
Warning 1076 The gtid domain being deleted ('0') is not in the current binlog state
Gtid_list of the current binlog does not contain 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0:
show binlog events in 'master-bin.000006' limit 1,1;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000006 # Gtid_list 1 # []
SET @@SESSION.gtid_domain_id=1;;
SET @@SESSION.server_id=1;
SET @@SESSION.gtid_seq_no=1;
INSERT INTO t SET a=1;
SET @@SESSION.server_id=2;
SET @@SESSION.gtid_seq_no=2;
INSERT INTO t SET a=2;
SET @@SESSION.gtid_domain_id=11;
SET @@SESSION.server_id=11;
SET @@SESSION.gtid_seq_no=11;
INSERT INTO t SET a=11;
SET @gtid_binlog_state_saved=@@GLOBAL.gtid_binlog_state;
FLUSH BINARY LOGS;
SET @@SESSION.gtid_domain_id=11;
SET @@SESSION.server_id=11;
SET @@SESSION.gtid_seq_no=1;
INSERT INTO t SET a=1;
SELECT @gtid_binlog_state_saved "as original state", @@GLOBAL.gtid_binlog_state as "out of order for 11 domain state";
as original state out of order for 11 domain state
1-1-1,1-2-2,11-11-11 1-1-1,1-2-2,11-11-1
PURGE BINARY LOGS TO 'master-bin.000007';
the following command succeeds with warnings
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
Warnings:
Warning 1076 The current gtid binlog state is incompatible with a former one having a gtid '11-11-1' which is less than the '11-11-11' of the gtid list describing an earlier state. The state may have been affected by manually injecting a lower sequence number gtid or via replication.
DROP TABLE t;
RESET MASTER;

View File

@ -0,0 +1,6 @@
SET @@SESSION.debug_dbug='+d,inject_binlog_delete_domain_init_error';
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (99);
ERROR HY000: Could not delete gtid domain. Reason: injected error.
SHOW WARNINGS;
Level Code Message
Error 1076 Could not delete gtid domain. Reason: injected error.

View File

@ -0,0 +1,137 @@
# Prove basic properties of
#
# FLUSH BINARY LOGS DELETE_DOMAIN_ID = (...)
#
# The command removes the supplied list of domains from the current
# @@global.gtid_binlog_state provided the binlog files do not contain
# events from such domains.
# The test is not format specific. One format is chosen to run it.
--source include/have_binlog_format_mixed.inc
# Reset binlog state
RESET MASTER;
# Empty list is accepted
FLUSH BINARY LOGS DELETE_DOMAIN_ID = ();
--echo and the command execution is effective thence rotates binlog as usual
--source include/show_binary_logs.inc
--echo Non-existed domain is warned, the command completes without rotation
--echo but with a warning
--let $binlog_pre_flush=query_get_value(SHOW MASTER STATUS, Position, 1)
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (99);
--let $binlog_start=$binlog_pre_flush
--source include/show_binary_logs.inc
# Log one event in a specified domain and try to delete the domain
SET @@SESSION.gtid_domain_id=1;
SET @@SESSION.server_id=1;
CREATE TABLE t (a int);
--error ER_BINLOG_CANT_DELETE_GTID_DOMAIN
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
# the same error after log rotation
FLUSH BINARY LOGS;
--error ER_BINLOG_CANT_DELETE_GTID_DOMAIN
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
# the latest binlog does not really contain any events incl ones from 1-domain
--let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1)
--eval PURGE BINARY LOGS TO '$purge_to_binlog';
# So now it's safe to delete
--error 0
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
--echo Gtid_list of the current binlog does not contain '1':
--let $binlog_file=query_get_value(SHOW MASTER STATUS, File, 1)
--source include/show_gtid_list.inc
--echo But the previous log's Gtid_list may have it which explains a warning from the following command
--let $binlog_file=$purge_to_binlog
--source include/show_gtid_list.inc
--echo Already deleted domain in Gtid_list of the earliest log is benign
--echo but may cause a warning
--error 0
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (1);
# Few domains delete. The chosen number verifies among others how
# expected overrun of the static buffers of underlying dynamic arrays is doing.
--let $domain_cnt=17
--let $server_in_domain_cnt=3
--let $domain_list=
--disable_query_log
while ($domain_cnt)
{
--let servers=$server_in_domain_cnt
--eval SET @@SESSION.gtid_domain_id=$domain_cnt
while ($servers)
{
--eval SET @@SESSION.server_id=10*$domain_cnt + $servers
--eval INSERT INTO t SET a=@@SESSION.server_id
--dec $servers
}
--let $domain_list= $domain_cnt, $domain_list
--dec $domain_cnt
}
--enable_query_log
--let $zero=0
--let $domain_list= $domain_list$zero
--error ER_BINLOG_CANT_DELETE_GTID_DOMAIN
--eval FLUSH BINARY LOGS DELETE_DOMAIN_ID = ($domain_list)
# Now satisfy the safety condtion to purge log files containing $domain list
FLUSH BINARY LOGS;
--let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1)
--eval PURGE BINARY LOGS TO '$purge_to_binlog'
--error 0
--eval FLUSH BINARY LOGS DELETE_DOMAIN_ID = ($domain_list)
--echo Gtid_list of the current binlog does not contain $domain_list:
--let $binlog_file=query_get_value(SHOW MASTER STATUS, File, 1)
--source include/show_gtid_list.inc
# Show reaction on @@global.gtid_binlog_state not succeeding
# earlier state as described by the 1st binlog' Gtid_list.
# Now let it be out-order gtid logged to a domain unrelated to deletion.
--let $del_d_id=1
--eval SET @@SESSION.gtid_domain_id=$del_d_id;
SET @@SESSION.server_id=1;
SET @@SESSION.gtid_seq_no=1;
INSERT INTO t SET a=1;
SET @@SESSION.server_id=2;
SET @@SESSION.gtid_seq_no=2;
INSERT INTO t SET a=2;
SET @@SESSION.gtid_domain_id=11;
SET @@SESSION.server_id=11;
SET @@SESSION.gtid_seq_no=11;
INSERT INTO t SET a=11;
SET @gtid_binlog_state_saved=@@GLOBAL.gtid_binlog_state;
FLUSH BINARY LOGS;
# Inject out of order for domain '11' before
SET @@SESSION.gtid_domain_id=11;
SET @@SESSION.server_id=11;
SET @@SESSION.gtid_seq_no=1;
INSERT INTO t SET a=1;
SELECT @gtid_binlog_state_saved "as original state", @@GLOBAL.gtid_binlog_state as "out of order for 11 domain state";
# to delete '1', first to purge logs containing its events
--let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1)
--eval PURGE BINARY LOGS TO '$purge_to_binlog'
--echo the following command succeeds with warnings
--eval FLUSH BINARY LOGS DELETE_DOMAIN_ID = ($del_d_id)
#
# Cleanup
#
DROP TABLE t;
RESET MASTER;

View File

@ -0,0 +1,11 @@
# Check "internal" error branches of
# FLUSH BINARY LOGS DELETE_DOMAIN_ID = (...)
# handler.
--source include/have_debug.inc
--source include/have_binlog_format_mixed.inc
SET @@SESSION.debug_dbug='+d,inject_binlog_delete_domain_init_error';
--error ER_BINLOG_CANT_DELETE_GTID_DOMAIN
FLUSH BINARY LOGS DELETE_DOMAIN_ID = (99);
SHOW WARNINGS;

View File

@ -0,0 +1,46 @@
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) Engine=InnoDB;
CREATE PROCEDURE insert_proc ()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO;
END;
INSERT INTO t1 VALUES (1, 'node 1'),(2, 'node 1');
INSERT INTO t1 VALUES (3, 'node 1');
END|
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
Warnings:
Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
INSERT INTO t1 VALUES (1, 'node 2');;
SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached";
SET SESSION wsrep_sync_wait = 0;
SET SESSION DEBUG_SYNC = 'wsrep_after_replication SIGNAL wsrep_after_replication_reached WAIT_FOR wsrep_after_replication_continue';
CALL insert_proc ();;
SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_after_replication_reached";
SET GLOBAL DEBUG = "";
Warnings:
Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
SET DEBUG_SYNC = "now SIGNAL wsrep_after_replication_continue";
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
SELECT @errno = 1213;
@errno = 1213
1
SELECT * FROM t1;
f1 f2
1 node 2
3 node 1
SELECT * FROM t1;
f1 f2
1 node 2
3 node 1
SET GLOBAL wsrep_slave_threads = DEFAULT;
DROP TABLE t1;
DROP PROCEDURE insert_proc;
SET GLOBAL debug = NULL;
Warnings:
Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead
SET debug_sync='RESET';
SELECT @@debug_sync;
@@debug_sync
ON - current signal: ''

View File

@ -7,6 +7,7 @@ INSERT INTO t1 VALUES (1);
# Disable binary logging for current session
SET SQL_LOG_BIN=OFF;
INSERT INTO t1 VALUES (2);
FLUSH BINARY LOGS;
CREATE TABLE t2(c1 INT PRIMARY KEY) ENGINE=INNODB;
INSERT INTO t2 VALUES (1);
CREATE TABLE test.t3 AS SELECT * from t1;

View File

@ -0,0 +1,76 @@
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/have_debug.inc
--source include/have_debug_sync.inc
--connection node_1
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(255)) Engine=InnoDB;
DELIMITER |;
CREATE PROCEDURE insert_proc ()
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS CONDITION 1 @errno = MYSQL_ERRNO;
END;
INSERT INTO t1 VALUES (1, 'node 1'),(2, 'node 1');
INSERT INTO t1 VALUES (3, 'node 1');
END|
DELIMITER ;|
# We need two slave threads here to guarantee progress.
# If we use only one thread the following could happen
# in node_1:
# We block the only slave thread in wsrep_apply_cb and we
# issue an INSERT (by calling the stored procedure) that will
# try to acquire galera's local monitor in pre_commit().
# This usually works fine, except for when a commit cut event
# sneaks in the slave queue and gets a local seqno smaller than
# that of the INSERT. Because there is only one slave thread,
# commit cut is not processed and therefore does not advance
# local monitor, and our INSERT remains stuck there.
SET GLOBAL wsrep_slave_threads = 2;
SET GLOBAL DEBUG = "d,sync.wsrep_apply_cb";
--connection node_2
--send INSERT INTO t1 VALUES (1, 'node 2');
--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
--connection node_1a
SET SESSION DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached";
--connection node_1
SET SESSION wsrep_sync_wait = 0;
SET SESSION DEBUG_SYNC = 'wsrep_after_replication SIGNAL wsrep_after_replication_reached WAIT_FOR wsrep_after_replication_continue';
--send CALL insert_proc ();
--connection node_1a
SET SESSION DEBUG_SYNC = "now WAIT_FOR wsrep_after_replication_reached";
SET GLOBAL DEBUG = "";
SET DEBUG_SYNC = "now SIGNAL wsrep_after_replication_continue";
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
--connection node_2
--reap
--connection node_1
# We expect no errors here, because the handler in insert_proc() caught the deadlock error
--reap
SELECT @errno = 1213;
SELECT * FROM t1;
--connection node_2
SELECT * FROM t1;
--connection node_1
SET GLOBAL wsrep_slave_threads = DEFAULT;
DROP TABLE t1;
DROP PROCEDURE insert_proc;
SET GLOBAL debug = NULL;
SET debug_sync='RESET';
# Make sure no pending signals are leftover to surprise subsequent tests.
SELECT @@debug_sync;

View File

@ -29,12 +29,11 @@ SELECT * FROM t1;
UNLOCK TABLES;
SHOW TABLES;
SELECT COUNT(*) = 1 FROM t1;
--disable_query_log
--eval SET GLOBAL wsrep_provider_options = "$wsrep_provider_options_orig";
--enable_query_log
DROP TABLE t1;
SHOW TABLES;
SELECT COUNT(*) = 1 FROM t1;
DROP TABLE t1;

View File

@ -25,7 +25,7 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
my $pid_filename = $ENV{'NODE_2_PIDFILE'};
my $mysqld_pid = `cat $pid_filename`;
chomp($mysqld_pid);
system("kill -19 $mysqld_pid");
system("kill -SIGSTOP $mysqld_pid");
exit(0);
EOF
@ -37,7 +37,7 @@ INSERT INTO t1 VALUES (1);
my $pid_filename = $ENV{'NODE_2_PIDFILE'};
my $mysqld_pid = `cat $pid_filename`;
chomp($mysqld_pid);
system("kill -18 $mysqld_pid");
system("kill -SIGCONT $mysqld_pid");
exit(0);
EOF

View File

@ -1,5 +1,13 @@
# Test to check the behavior of galera cluster with sql_log_bin=ON|OFF & binary
# logging is disabled. sql_bin_log should not affect galera replication.
#
# The following bugfixes are tested:
#
# MDEV-9510: Segmentation fault in binlog thread.
# A scenario otherwise causing a similar segfault is replayed.
# The test must pass having no crashes.
# The sequence of sql statements is provided by original
# sql_log_bin.test augmented with a FLUSH BINLOG LOGS, below.
--source include/galera_cluster.inc
--source include/have_innodb.inc
@ -15,6 +23,10 @@ INSERT INTO t1 VALUES (1);
--echo # Disable binary logging for current session
SET SQL_LOG_BIN=OFF;
INSERT INTO t1 VALUES (2);
# MDEV-9510: the following binlog rotation due to FLUSH segfaults wo/ the fixes
FLUSH BINARY LOGS;
CREATE TABLE t2(c1 INT PRIMARY KEY) ENGINE=INNODB;
INSERT INTO t2 VALUES (1);
CREATE TABLE test.t3 AS SELECT * from t1;

View File

@ -0,0 +1,13 @@
#
# Bug#17604730 ASSERTION: *CURSOR->INDEX->NAME == TEMP_INDEX_PREFIX
#
create table t1 (f1 int primary key, f2 int, f3 int, unique key k1(f2),
key k2(f3)) engine=innodb;
insert into t1 values (14, 24, 34);
set @@debug_dbug = '+d,row_ins_sec_index_entry_timeout';
replace into t1 values (14, 25, 34);
select * from t1;
f1 f2 f3
14 25 34
drop table t1;
set @@debug_dbug = '-d,row_ins_sec_index_entry_timeout';

View File

@ -0,0 +1,15 @@
--source include/have_innodb.inc
--source include/have_debug.inc
--echo #
--echo # Bug#17604730 ASSERTION: *CURSOR->INDEX->NAME == TEMP_INDEX_PREFIX
--echo #
create table t1 (f1 int primary key, f2 int, f3 int, unique key k1(f2),
key k2(f3)) engine=innodb;
insert into t1 values (14, 24, 34);
set @@debug_dbug = '+d,row_ins_sec_index_entry_timeout';
replace into t1 values (14, 25, 34);
select * from t1;
drop table t1;
set @@debug_dbug = '-d,row_ins_sec_index_entry_timeout';

View File

@ -0,0 +1,43 @@
include/master-slave.inc
[connection master]
connection master;
SET @@SESSION.gtid_domain_id=0;
CREATE TABLE t (a INT);
connection slave;
connection slave;
call mtr.add_suppression("connecting slave requested to start from.*which is not in the master's binlog");
include/stop_slave.inc
CHANGE MASTER TO master_use_gtid=slave_pos;
connection master;
SET @@SESSION.gtid_domain_id=11;
SET @@SESSION.server_id=111;
SET @@SESSION.gtid_seq_no=1;
INSERT INTO t SET a=1;
connection slave;
SET @save.gtid_slave_pos=@@global.gtid_slave_pos;
SET @@global.gtid_slave_pos=concat(@@global.gtid_slave_pos, ",", 11, "-", 111, "-", 1 + 1);
Warnings:
Warning 1947 Specified GTID 0-1-1 conflicts with the binary log which contains a more recent GTID 0-2-2. If MASTER_GTID_POS=CURRENT_POS is used, the binlog position will override the new value of @@gtid_slave_pos
START SLAVE IO_THREAD;
include/wait_for_slave_io_error.inc [errno=1236]
connection master;
FLUSH BINARY LOGS;
PURGE BINARY LOGS TO 'master-bin.000002';;
FLUSH BINARY LOGS DELETE_DOMAIN_ID=(11);
connection slave;
include/start_slave.inc
connection master;
INSERT INTO t SET a=1;
connection slave;
include/wait_for_slave_io_error.inc [errno=1236]
connection master;
FLUSH BINARY LOGS;
PURGE BINARY LOGS TO 'master-bin.000004';;
FLUSH BINARY LOGS DELETE_DOMAIN_ID=(11);
connection slave;
include/start_slave.inc
connection master;
SET @@SESSION.gtid_domain_id=0;
DROP TABLE t;
connection slave;
include/rpl_end.inc

View File

@ -0,0 +1,95 @@
# In case master's gtid binlog state is divergent from the slave's gtid_slave_pos
# slave may not be able to connect.
# For instance when slave is more updated in some of domains, see
# MDEV-12012 as example, the master's state may require adjustment.
# In a specific case of an "old" divergent domain, that is there
# won't be no more event groups from it generated, the states can be
# made compatible with wiping the problematic domain away. After that slave
# becomes connectable.
#
# Notice that the slave applied gtid state is not really required to
# be similarly cleaned in order for replication to flow.
# However this could lead to an expected error when the master
# resumes binlogging of such domain which the test demonstrate.
--source include/master-slave.inc
--connection master
# enforce the default domain_id binlogging explicitly
SET @@SESSION.gtid_domain_id=0;
CREATE TABLE t (a INT);
--sync_slave_with_master
--connection slave
call mtr.add_suppression("connecting slave requested to start from.*which is not in the master's binlog");
--source include/stop_slave.inc
CHANGE MASTER TO master_use_gtid=slave_pos;
--connection master
# create extra gtid domains for binlog state
--let $extra_domain_id=11
--let $extra_domain_server_id=111
--let $extra_gtid_seq_no=1
--eval SET @@SESSION.gtid_domain_id=$extra_domain_id
--eval SET @@SESSION.server_id=$extra_domain_server_id
--eval SET @@SESSION.gtid_seq_no=$extra_gtid_seq_no
INSERT INTO t SET a=1;
#
# Set up the slave replication state as if slave knows more events from the extra
# domain.
#
--connection slave
SET @save.gtid_slave_pos=@@global.gtid_slave_pos;
--eval SET @@global.gtid_slave_pos=concat(@@global.gtid_slave_pos, ",", $extra_domain_id, "-", $extra_domain_server_id, "-", $extra_gtid_seq_no + 1)
# unsuccessful attempt to start slave
START SLAVE IO_THREAD;
--let $slave_io_errno=1236
--source include/wait_for_slave_io_error.inc
--connection master
# adjust the master binlog state
FLUSH BINARY LOGS;
--let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1)
--eval PURGE BINARY LOGS TO '$purge_to_binlog';
# with final removal of the extra domain
--eval FLUSH BINARY LOGS DELETE_DOMAIN_ID=($extra_domain_id)
--connection slave
# start the slave sucessfully
--source include/start_slave.inc
--connection master
# but the following gtid from the *extra* domain will break replication
INSERT INTO t SET a=1;
# take note of the slave io thread error due to being dismissed
# extra domain at connection to master which tried becoming active;
# slave is to stop.
--connection slave
--let $errno=1236
--source include/wait_for_slave_io_error.inc
# let's apply the very same medicine
--connection master
FLUSH BINARY LOGS;
--let $purge_to_binlog= query_get_value(SHOW MASTER STATUS, File, 1)
--eval PURGE BINARY LOGS TO '$purge_to_binlog';
# with final removal of the extra domain
--eval FLUSH BINARY LOGS DELETE_DOMAIN_ID=($extra_domain_id)
--connection slave
--source include/start_slave.inc
#
# cleanup
#
--connection master
SET @@SESSION.gtid_domain_id=0;
DROP TABLE t;
sync_slave_with_master;
--source include/rpl_end.inc

View File

@ -589,3 +589,9 @@ eval SET GLOBAL SERVER_ID = $old_server_id;
--exec $MYSQL_BINLOG --hexdump std_data/mdev-4645-binlog_group_id.binlog
--exec $MYSQL_BINLOG --hexdump std_data/mdev-4645-binlog_group_id_checksum.binlog
--exec $MYSQL_BINLOG --hexdump std_data/mdev-4645-binlog_none.binlog
#
# MDEV-12372 mysqlbinlog --version output is the same on 10.x as on 5.5.x, and contains not only version
#
replace_regex /.*mysqlbinlog(\.exe)? Ver .* for .* at [-_a-zA-Z0-9]+/mysqlbinlog Ver VER for OS at ARCH/;
exec $MYSQL_BINLOG --version;

View File

@ -9581,6 +9581,23 @@ drop procedure p;
drop view v;
drop table t, tmp_t;
--echo #
--echo # MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
--echo #
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
CREATE FUNCTION f1() RETURNS INT RETURN ( SELECT MAX(i) FROM v1 );
--error ER_NON_INSERTABLE_TABLE
REPLACE INTO v1 VALUES (f1());
SET @aux = f1();
# Cleanup
DROP FUNCTION f1;
DROP VIEW v1;
DROP TABLE t1;
--echo #End of 10.1 tests
--echo #

View File

@ -2643,8 +2643,33 @@ DROP TABLE t1;
SET TIMESTAMP=DEFAULT;
set time_zone= @@global.time_zone;
--echo #
--echo # MDEV-13936: Server crashes in Time_and_counter_tracker::incr_loops
--echo #
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1 WHERE RAND() > 0.5;
CREATE TABLE t2 (a int);
CREATE TABLE t3 (a int);
create trigger trg after insert on t2 for each row
INSERT INTO t3 SELECT MAX(i) FROM v1 UNION SELECT MAX(i) FROM v1;
drop table t1;
--error ER_NO_SUCH_TABLE
insert into t2 value (2);
CREATE TABLE t1 (i INT);
insert into t2 value (2);
DROP VIEW v1;
DROP TABLE t1,t2,t3;
--echo End of 10.1 tests.
#
# MDEV-10915 Count number of exceuted triggers
# MDEV-10915 Count number of executed triggers
#
create table t1 (i int);

View File

@ -266,18 +266,18 @@ parse_cnf()
# finally get the variable value (if variables has been specified multiple time use the last value only)
# look in group+suffix
if [[ -n $WSREP_SST_OPT_CONF_SUFFIX ]]; then
if [ -n $WSREP_SST_OPT_CONF_SUFFIX ]; then
reval=$($MY_PRINT_DEFAULTS "${group}${WSREP_SST_OPT_CONF_SUFFIX}" | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2- | tail -1)
fi
# look in group
if [[ -z $reval ]]; then
if [ -z $reval ]; then
reval=$($MY_PRINT_DEFAULTS $group | awk -F= '{if ($1 ~ /_/) { gsub(/_/,"-",$1); print $1"="$2 } else { print $0 }}' | grep -- "--$var=" | cut -d= -f2- | tail -1)
fi
# use default if we haven't found a value
if [[ -z $reval ]]; then
[[ -n $3 ]] && reval=$3
if [ -z $reval ]; then
[ -n $3 ] && reval=$3
fi
echo $reval
}

View File

@ -5503,7 +5503,7 @@ void Regexp_processor_pcre::pcre_exec_warn(int rc) const
switch (rc)
{
case PCRE_ERROR_NULL:
errmsg= "pcre_exec: null arguement passed";
errmsg= "pcre_exec: null argument passed";
break;
case PCRE_ERROR_BADOPTION:
errmsg= "pcre_exec: bad option";

View File

@ -179,6 +179,7 @@ static SYMBOL symbols[] = {
{ "DELAYED", SYM(DELAYED_SYM)},
{ "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM)},
{ "DELETE", SYM(DELETE_SYM)},
{ "DELETE_DOMAIN_ID", SYM(DELETE_DOMAIN_ID_SYM)},
{ "DESC", SYM(DESC)},
{ "DESCRIBE", SYM(DESCRIBE)},
{ "DES_KEY_FILE", SYM(DES_KEY_FILE)},

View File

@ -6618,6 +6618,120 @@ void MYSQL_BIN_LOG::checkpoint_and_purge(ulong binlog_id)
purge();
}
/**
Searches for the first (oldest) binlog file name in in the binlog index.
@param[in,out] buf_arg pointer to a buffer to hold found
the first binary log file name
@return NULL on success, otherwise error message
*/
static const char* get_first_binlog(char* buf_arg)
{
IO_CACHE *index_file;
size_t length;
char fname[FN_REFLEN];
const char* errmsg= NULL;
DBUG_ENTER("get_first_binlog");
DBUG_ASSERT(mysql_bin_log.is_open());
mysql_bin_log.lock_index();
index_file=mysql_bin_log.get_index_file();
if (reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 0))
{
errmsg= "failed to create a cache on binlog index";
goto end;
}
/* The file ends with EOF or empty line */
if ((length=my_b_gets(index_file, fname, sizeof(fname))) <= 1)
{
errmsg= "empty binlog index";
goto end;
}
else
{
fname[length-1]= 0; // Remove end \n
}
if (normalize_binlog_name(buf_arg, fname, false))
{
errmsg= "cound not normalize the first file name in the binlog index";
goto end;
}
end:
mysql_bin_log.unlock_index();
DBUG_RETURN(errmsg);
}
/**
Check weather the gtid binlog state can safely remove gtid
domains passed as the argument. A safety condition is satisfied when
there are no events from the being deleted domains in the currently existing
binlog files. Upon successful check the supplied domains are removed
from @@gtid_binlog_state. The caller is supposed to rotate binlog so that
the active latest file won't have the deleted domains in its Gtid_list header.
@param domain_drop_lex gtid domain id sequence from lex.
Passed as a pointer to dynamic array must be not empty
unless pointer value NULL.
@retval zero on success
@retval > 0 ineffective call none from the *non* empty
gtid domain sequence is deleted
@retval < 0 on error
*/
static int do_delete_gtid_domain(DYNAMIC_ARRAY *domain_drop_lex)
{
int rc= 0;
Gtid_list_log_event *glev= NULL;
char buf[FN_REFLEN];
File file;
IO_CACHE cache;
const char* errmsg= NULL;
char errbuf[MYSQL_ERRMSG_SIZE]= {0};
if (!domain_drop_lex)
return 0; // still "effective" having empty domain sequence to delete
DBUG_ASSERT(domain_drop_lex->elements > 0);
mysql_mutex_assert_owner(mysql_bin_log.get_log_lock());
if ((errmsg= get_first_binlog(buf)) != NULL)
goto end;
bzero((char*) &cache, sizeof(cache));
if ((file= open_binlog(&cache, buf, &errmsg)) == (File) -1)
goto end;
errmsg= get_gtid_list_event(&cache, &glev);
end_io_cache(&cache);
mysql_file_close(file, MYF(MY_WME));
DBUG_EXECUTE_IF("inject_binlog_delete_domain_init_error",
errmsg= "injected error";);
if (errmsg)
goto end;
errmsg= rpl_global_gtid_binlog_state.drop_domain(domain_drop_lex,
glev, errbuf);
end:
if (errmsg)
{
if (strlen(errmsg) > 0)
{
my_error(ER_BINLOG_CANT_DELETE_GTID_DOMAIN, MYF(0), errmsg);
rc= -1;
}
else
{
rc= 1;
}
}
delete glev;
return rc;
}
/**
The method is a shortcut of @c rotate() and @c purge().
LOCK_log is acquired prior to rotate and is released after it.
@ -6627,16 +6741,24 @@ void MYSQL_BIN_LOG::checkpoint_and_purge(ulong binlog_id)
@retval
nonzero - error in rotating routine.
*/
int MYSQL_BIN_LOG::rotate_and_purge(bool force_rotate)
int MYSQL_BIN_LOG::rotate_and_purge(bool force_rotate,
DYNAMIC_ARRAY *domain_drop_lex)
{
int error= 0;
int err_gtid=0, error= 0;
ulong prev_binlog_id;
DBUG_ENTER("MYSQL_BIN_LOG::rotate_and_purge");
bool check_purge= false;
mysql_mutex_lock(&LOCK_log);
prev_binlog_id= current_binlog_id;
if ((error= rotate(force_rotate, &check_purge)))
if ((err_gtid= do_delete_gtid_domain(domain_drop_lex)))
{
// inffective attempt to delete merely skips rotate and purge
if (err_gtid < 0)
error= 1; // otherwise error is propagated the user
}
else if ((error= rotate(force_rotate, &check_purge)))
check_purge= false;
/*
NOTE: Run purge_logs wo/ holding LOCK_log because it does not need
@ -7038,8 +7160,15 @@ MYSQL_BIN_LOG::write_transaction_to_binlog(THD *thd,
mode. Also, do not write the cached updates to binlog if binary logging is
disabled (log-bin/sql_log_bin).
*/
if (wsrep_emulate_bin_log || !(thd->variables.option_bits & OPTION_BIN_LOG))
if (wsrep_emulate_bin_log)
{
DBUG_RETURN(0);
}
else if (!(thd->variables.option_bits & OPTION_BIN_LOG))
{
cache_mngr->need_unlog= false;
DBUG_RETURN(0);
}
entry.thd= thd;
entry.cache_mngr= cache_mngr;
@ -9362,11 +9491,19 @@ TC_LOG_BINLOG::log_and_order(THD *thd, my_xid xid, bool all,
if (err)
DBUG_RETURN(0);
bool need_unlog= cache_mngr->need_unlog;
/*
The transaction won't need the flag anymore.
Todo/fixme: consider to move the statement into cache_mngr->reset()
relocated to the current or later point.
*/
cache_mngr->need_unlog= false;
/*
If using explicit user XA, we will not have XID. We must still return a
non-zero cookie (as zero cookie signals error).
*/
if (!xid || !cache_mngr->need_unlog)
if (!xid || !need_unlog)
DBUG_RETURN(BINLOG_COOKIE_DUMMY(cache_mngr->delayed_error));
else
DBUG_RETURN(BINLOG_COOKIE_MAKE(cache_mngr->binlog_id,
@ -9439,6 +9576,9 @@ TC_LOG_BINLOG::mark_xid_done(ulong binlog_id, bool write_checkpoint)
if (b->binlog_id == binlog_id)
{
--b->xid_count;
DBUG_ASSERT(b->xid_count >= 0); // catch unmatched (++) decrement
break;
}
first= false;
@ -10212,6 +10352,73 @@ TC_LOG_BINLOG::set_status_variables(THD *thd)
}
}
/*
Find the Gtid_list_log_event at the start of a binlog.
NULL for ok, non-NULL error message for error.
If ok, then the event is returned in *out_gtid_list. This can be NULL if we
get back to binlogs written by old server version without GTID support. If
so, it means we have reached the point to start from, as no GTID events can
exist in earlier binlogs.
*/
const char *
get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list)
{
Format_description_log_event init_fdle(BINLOG_VERSION);
Format_description_log_event *fdle;
Log_event *ev;
const char *errormsg = NULL;
*out_gtid_list= NULL;
if (!(ev= Log_event::read_log_event(cache, 0, &init_fdle,
opt_master_verify_checksum)) ||
ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
{
if (ev)
delete ev;
return "Could not read format description log event while looking for "
"GTID position in binlog";
}
fdle= static_cast<Format_description_log_event *>(ev);
for (;;)
{
Log_event_type typ;
ev= Log_event::read_log_event(cache, 0, fdle, opt_master_verify_checksum);
if (!ev)
{
errormsg= "Could not read GTID list event while looking for GTID "
"position in binlog";
break;
}
typ= ev->get_type_code();
if (typ == GTID_LIST_EVENT)
break; /* Done, found it */
if (typ == START_ENCRYPTION_EVENT)
{
if (fdle->start_decryption((Start_encryption_log_event*) ev))
errormsg= "Could not set up decryption for binlog.";
}
delete ev;
if (typ == ROTATE_EVENT || typ == STOP_EVENT ||
typ == FORMAT_DESCRIPTION_EVENT || typ == START_ENCRYPTION_EVENT)
continue; /* Continue looking */
/* We did not find any Gtid_list_log_event, must be old binlog. */
ev= NULL;
break;
}
delete fdle;
*out_gtid_list= static_cast<Gtid_list_log_event *>(ev);
return errormsg;
}
struct st_mysql_storage_engine binlog_storage_engine=
{ MYSQL_HANDLERTON_INTERFACE_VERSION };

View File

@ -758,7 +758,7 @@ public:
int update_log_index(LOG_INFO* linfo, bool need_update_threads);
int rotate(bool force_rotate, bool* check_purge);
void checkpoint_and_purge(ulong binlog_id);
int rotate_and_purge(bool force_rotate);
int rotate_and_purge(bool force_rotate, DYNAMIC_ARRAY* drop_gtid_domain= NULL);
/**
Flush binlog cache and synchronize to disk.
@ -1167,4 +1167,9 @@ static inline TC_LOG *get_tc_log_implementation()
return &tc_log_mmap;
}
class Gtid_list_log_event;
const char *
get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list);
#endif /* LOG_H */

View File

@ -5875,9 +5875,6 @@ int mysqld_main(int argc, char **argv)
#ifdef __WIN__
if (!opt_console)
{
if (reopen_fstreams(log_error_file, stdout, stderr))
unireg_abort(1);
setbuf(stderr, NULL);
FreeConsole(); // Remove window
}

View File

@ -26,7 +26,7 @@
#include "key.h"
#include "rpl_gtid.h"
#include "rpl_rli.h"
#include "log_event.h"
const LEX_STRING rpl_gtid_slave_state_table_name=
{ C_STRING_WITH_LEN("gtid_slave_pos") };
@ -1727,6 +1727,155 @@ end:
return res;
}
/**
Remove domains supplied by the first argument from binlog state.
Removal is done for any domain whose last gtids (from all its servers) match
ones in Gtid list event of the 2nd argument.
@param ids gtid domain id sequence, may contain dups
@param glev pointer to Gtid list event describing
the match condition
@param errbuf [out] pointer to possible error message array
@retval NULL as success when at least one domain is removed
@retval "" empty string to indicate ineffective call
when no domains removed
@retval NOT EMPTY string otherwise an error message
*/
const char*
rpl_binlog_state::drop_domain(DYNAMIC_ARRAY *ids,
Gtid_list_log_event *glev,
char* errbuf)
{
DYNAMIC_ARRAY domain_unique; // sequece (unsorted) of unique element*:s
rpl_binlog_state::element* domain_unique_buffer[16];
ulong k, l;
const char* errmsg= NULL;
DBUG_ENTER("rpl_binlog_state::drop_domain");
my_init_dynamic_array2(&domain_unique,
sizeof(element*), domain_unique_buffer,
sizeof(domain_unique_buffer) / sizeof(element*), 4, 0);
mysql_mutex_lock(&LOCK_binlog_state);
/*
Gtid list is supposed to come from a binlog's Gtid_list event and
therefore should be a subset of the current binlog state. That is
for every domain in the list the binlog state contains a gtid with
sequence number not less than that of the list.
Exceptions of this inclusion rule are:
A. the list may still refer to gtids from already deleted domains.
Files containing them must have been purged whereas the file
with the list is not yet.
B. out of order groups were injected
C. manually build list of binlog files violating the inclusion
constraint.
While A is a normal case (not necessarily distinguishable from C though),
B and C may require the user's attention so any (incl the A's suspected)
inconsistency is diagnosed and *warned*.
*/
for (l= 0, errbuf[0]= 0; l < glev->count; l++, errbuf[0]= 0)
{
rpl_gtid* rb_state_gtid= find_nolock(glev->list[l].domain_id,
glev->list[l].server_id);
if (!rb_state_gtid)
sprintf(errbuf,
"missing gtids from the '%u-%u' domain-server pair which is "
"referred to in the gtid list describing an earlier state. Ignore "
"if the domain ('%u') was already explicitly deleted",
glev->list[l].domain_id, glev->list[l].server_id,
glev->list[l].domain_id);
else if (rb_state_gtid->seq_no < glev->list[l].seq_no)
sprintf(errbuf,
"having a gtid '%u-%u-%llu' which is less than "
"the '%u-%u-%llu' of the gtid list describing an earlier state. "
"The state may have been affected by manually injecting "
"a lower sequence number gtid or via replication",
rb_state_gtid->domain_id, rb_state_gtid->server_id,
rb_state_gtid->seq_no, glev->list[l].domain_id,
glev->list[l].server_id, glev->list[l].seq_no);
if (strlen(errbuf)) // use strlen() as cheap flag
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
ER_BINLOG_CANT_DELETE_GTID_DOMAIN,
"The current gtid binlog state is incompatible with "
"a former one %s.", errbuf);
}
/*
For each domain_id from ids
when no such domain in binlog state
warn && continue
For each domain.server's last gtid
when not locate the last gtid in glev.list
error out binlog state can't change
otherwise continue
*/
for (ulong i= 0; i < ids->elements; i++)
{
rpl_binlog_state::element *elem= NULL;
ulong *ptr_domain_id;
bool not_match;
ptr_domain_id= (ulong*) dynamic_array_ptr(ids, i);
elem= (rpl_binlog_state::element *)
my_hash_search(&hash, (const uchar *) ptr_domain_id, 0);
if (!elem)
{
push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
ER_BINLOG_CANT_DELETE_GTID_DOMAIN,
"The gtid domain being deleted ('%lu') is not in "
"the current binlog state", *ptr_domain_id);
continue;
}
for (not_match= true, k= 0; k < elem->hash.records; k++)
{
rpl_gtid *d_gtid= (rpl_gtid *)my_hash_element(&elem->hash, k);
for (ulong l= 0; l < glev->count && not_match; l++)
not_match= !(*d_gtid == glev->list[l]);
}
if (not_match)
{
sprintf(errbuf, "binlog files may contain gtids from the domain ('%lu') "
"being deleted. Make sure to first purge those files",
*ptr_domain_id);
errmsg= errbuf;
goto end;
}
// compose a sequence of unique pointers to domain object
for (k= 0; k < domain_unique.elements; k++)
{
if ((rpl_binlog_state::element*) dynamic_array_ptr(&domain_unique, k)
== elem)
break; // domain_id's elem has been already in
}
if (k == domain_unique.elements) // proven not to have duplicates
insert_dynamic(&domain_unique, (uchar*) &elem);
}
// Domain removal from binlog state
for (k= 0; k < domain_unique.elements; k++)
{
rpl_binlog_state::element *elem= *(rpl_binlog_state::element**)
dynamic_array_ptr(&domain_unique, k);
my_hash_free(&elem->hash);
my_hash_delete(&hash, (uchar*) elem);
}
DBUG_ASSERT(strlen(errbuf) == 0);
if (domain_unique.elements == 0)
errmsg= "";
end:
mysql_mutex_unlock(&LOCK_binlog_state);
delete_dynamic(&domain_unique);
DBUG_RETURN(errmsg);
}
slave_connection_state::slave_connection_state()
{

View File

@ -34,6 +34,13 @@ struct rpl_gtid
uint64 seq_no;
};
inline bool operator==(const rpl_gtid& lhs, const rpl_gtid& rhs)
{
return
lhs.domain_id == rhs.domain_id &&
lhs.server_id == rhs.server_id &&
lhs.seq_no == rhs.seq_no;
};
enum enum_gtid_skip_type {
GTID_SKIP_NOT, GTID_SKIP_STANDALONE, GTID_SKIP_TRANSACTION
@ -93,6 +100,7 @@ struct gtid_waiting {
class Relay_log_info;
struct rpl_group_info;
class Gtid_list_log_event;
/*
Replication slave state.
@ -257,6 +265,7 @@ struct rpl_binlog_state
rpl_gtid *find_nolock(uint32 domain_id, uint32 server_id);
rpl_gtid *find(uint32 domain_id, uint32 server_id);
rpl_gtid *find_most_recent(uint32 domain_id);
const char* drop_domain(DYNAMIC_ARRAY *ids, Gtid_list_log_event *glev, char*);
};

View File

@ -1801,8 +1801,8 @@ ER_WRONG_AUTO_KEY 42000 S1009
spa "Puede ser solamente un campo automatico y este debe ser definido como una clave"
swe "Det får finnas endast ett AUTO_INCREMENT-fält och detta måste vara en nyckel"
ukr "Невірне визначення таблиці; Може бути лише один автоматичний стовбець, що повинен бути визначений як ключ"
ER_UNUSED_9
eng "You should never see it"
ER_BINLOG_CANT_DELETE_GTID_DOMAIN
eng "Could not delete gtid domain. Reason: %s."
ER_NORMAL_SHUTDOWN
cze "%s (%s): normální ukončení\n"
dan "%s (%s): Normal nedlukning\n"
@ -7330,7 +7330,7 @@ ER_SUBQUERIES_NOT_SUPPORTED 42000
eng "%s does not support subqueries or stored functions"
ER_SET_STATEMENT_NOT_SUPPORTED 42000
eng "The system variable %.200s cannot be set in SET STATEMENT."
ER_UNUSED_17
ER_UNUSED_9
eng "You should never see it"
ER_USER_CREATE_EXISTS
eng "Can't create user '%-.64s'@'%-.64s'; it already exists"

View File

@ -1144,6 +1144,19 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
if (check_stack_overrun(thd, 7 * STACK_MIN_SIZE, (uchar*)&old_packet))
DBUG_RETURN(TRUE);
/*
Normally the counter is not reset between parsing and first execution,
but it is possible in case of error to have parsing on one CALL and
first execution (where VIEW will be parsed and added). So we store the
counter after parsing and restore it before execution just to avoid
repeating SELECT numbers.
Other problem is that it can be more SELECTs parsed in case of fixing
error causes previous interruption of the SP. So it is save not just
assign old value but add it.
*/
thd->select_number+= m_select_number;
/* init per-instruction memroot */
init_sql_alloc(&execute_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
@ -1477,6 +1490,16 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
m_recursion_level + 1));
m_first_instance->m_first_free_instance= this;
/*
This execution of the SP was aborted with an error (e.g. "Table not
found"). However it might still have consumed some numbers from the
thd->select_number counter. The next sp->exec() call must not use the
consumed numbers, so we remember the first free number (We know that
nobody will use it as this execution has stopped with an error).
*/
if (err_status)
set_select_number(thd->select_number);
DBUG_RETURN(err_status);
}
@ -2109,26 +2132,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
if (!err_status)
{
/*
Normally the counter is not reset between parsing and first execution,
but it is possible in case of error to have parsing on one CALL and
first execution (where VIEW will be parsed and added). So we store the
counter after parsing and restore it before execution just to avoid
repeating SELECT numbers.
*/
thd->select_number= m_select_number;
err_status= execute(thd, TRUE);
DBUG_PRINT("info", ("execute returned %d", (int) err_status));
/*
This execution of the SP was aborted with an error (e.g. "Table not
found"). However it might still have consumed some numbers from the
thd->select_number counter. The next sp->exec() call must not use the
consumed numbers, so we remember the first free number (We know that
nobody will use it as this execution has stopped with an error).
*/
if (err_status)
set_select_number(thd->select_number);
}
if (save_log_general)

View File

@ -4852,17 +4852,14 @@ extern "C" int thd_non_transactional_update(const MYSQL_THD thd)
extern "C" int thd_binlog_format(const MYSQL_THD thd)
{
#ifdef WITH_WSREP
if (WSREP(thd))
{
/* for wsrep binlog format is meaningful also when binlogging is off */
return (int) WSREP_BINLOG_FORMAT(thd->variables.binlog_format);
return (int) thd->wsrep_binlog_format();
}
#endif /* WITH_WSREP */
if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
return (int) thd->variables.binlog_format;
else
return BINLOG_FORMAT_UNSPEC;
return BINLOG_FORMAT_UNSPEC;
}
extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all)

View File

@ -808,6 +808,7 @@ void lex_end_stage2(LEX *lex)
/* Reset LEX_MASTER_INFO */
lex->mi.reset(lex->sql_command == SQLCOM_CHANGE_MASTER);
delete_dynamic(&lex->delete_gtid_domain);
DBUG_VOID_RETURN;
}
@ -2933,6 +2934,10 @@ LEX::LEX()
INITIAL_LEX_PLUGIN_LIST_SIZE, 0);
reset_query_tables_list(TRUE);
mi.init();
init_dynamic_array2(&delete_gtid_domain, sizeof(ulong*),
gtid_domain_static_buffer,
initial_gtid_domain_buffer_size,
initial_gtid_domain_buffer_size, 0);
}

View File

@ -2834,6 +2834,13 @@ public:
*/
Item *limit_rows_examined;
ulonglong limit_rows_examined_cnt;
/**
Holds a set of domain_ids for deletion at FLUSH..DELETE_DOMAIN_ID
*/
DYNAMIC_ARRAY delete_gtid_domain;
static const ulong initial_gtid_domain_buffer_size= 16;
ulong gtid_domain_static_buffer[initial_gtid_domain_buffer_size];
inline void set_limit_rows_examined()
{
if (limit_rows_examined)

View File

@ -6236,6 +6236,24 @@ finish:
}
if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR))
trans_rollback_stmt(thd);
#ifdef WITH_WSREP
else if (thd->spcont &&
(thd->wsrep_conflict_state == MUST_ABORT ||
thd->wsrep_conflict_state == CERT_FAILURE))
{
/*
The error was cleared, but THD was aborted by wsrep and
wsrep_conflict_state is still set accordingly. This
situation is expected if we are running a stored procedure
that declares a handler that catches ER_LOCK_DEADLOCK error.
In which case the error may have been cleared in method
sp_rcontext::handle_sql_condition().
*/
trans_rollback_stmt(thd);
thd->wsrep_conflict_state= NO_CONFLICT;
thd->killed= NOT_KILLED;
}
#endif /* WITH_WSREP */
else
{
/* If commit fails, we should be able to reset the OK status. */

View File

@ -153,7 +153,10 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
tmp_write_to_binlog= 0;
if (mysql_bin_log.is_open())
{
if (mysql_bin_log.rotate_and_purge(true))
DYNAMIC_ARRAY *drop_gtid_domain=
(thd && (thd->lex->delete_gtid_domain.elements > 0)) ?
&thd->lex->delete_gtid_domain : NULL;
if (mysql_bin_log.rotate_and_purge(true, drop_gtid_domain))
*write_to_binlog= -1;
if (WSREP_ON)

View File

@ -30,7 +30,7 @@
#include <my_dir.h>
#include "rpl_handler.h"
#include "debug_sync.h"
#include "log.h" // get_gtid_list_event
enum enum_gtid_until_state {
GTID_UNTIL_NOT_DONE,
@ -876,72 +876,6 @@ get_binlog_list(MEM_ROOT *memroot)
DBUG_RETURN(current_list);
}
/*
Find the Gtid_list_log_event at the start of a binlog.
NULL for ok, non-NULL error message for error.
If ok, then the event is returned in *out_gtid_list. This can be NULL if we
get back to binlogs written by old server version without GTID support. If
so, it means we have reached the point to start from, as no GTID events can
exist in earlier binlogs.
*/
static const char *
get_gtid_list_event(IO_CACHE *cache, Gtid_list_log_event **out_gtid_list)
{
Format_description_log_event init_fdle(BINLOG_VERSION);
Format_description_log_event *fdle;
Log_event *ev;
const char *errormsg = NULL;
*out_gtid_list= NULL;
if (!(ev= Log_event::read_log_event(cache, 0, &init_fdle,
opt_master_verify_checksum)) ||
ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
{
if (ev)
delete ev;
return "Could not read format description log event while looking for "
"GTID position in binlog";
}
fdle= static_cast<Format_description_log_event *>(ev);
for (;;)
{
Log_event_type typ;
ev= Log_event::read_log_event(cache, 0, fdle, opt_master_verify_checksum);
if (!ev)
{
errormsg= "Could not read GTID list event while looking for GTID "
"position in binlog";
break;
}
typ= ev->get_type_code();
if (typ == GTID_LIST_EVENT)
break; /* Done, found it */
if (typ == START_ENCRYPTION_EVENT)
{
if (fdle->start_decryption((Start_encryption_log_event*) ev))
errormsg= "Could not set up decryption for binlog.";
}
delete ev;
if (typ == ROTATE_EVENT || typ == STOP_EVENT ||
typ == FORMAT_DESCRIPTION_EVENT || typ == START_ENCRYPTION_EVENT)
continue; /* Continue looking */
/* We did not find any Gtid_list_log_event, must be old binlog. */
ev= NULL;
break;
}
delete fdle;
*out_gtid_list= static_cast<Gtid_list_log_event *>(ev);
return errormsg;
}
/*
Check if every GTID requested by the slave is contained in this (or a later)

View File

@ -81,7 +81,6 @@ int rpl_append_gtid_state(String *dest, bool use_binlog);
int rpl_load_gtid_state(slave_connection_state *state, bool use_binlog);
bool rpl_gtid_pos_check(THD *thd, char *str, size_t len);
bool rpl_gtid_pos_update(THD *thd, char *str, size_t len);
#else
struct LOAD_FILE_IO_CACHE : public IO_CACHE { };

View File

@ -1178,6 +1178,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token DEFINER_SYM
%token DELAYED_SYM
%token DELAY_KEY_WRITE_SYM
%token DELETE_DOMAIN_ID_SYM
%token DELETE_SYM /* SQL-2003-R */
%token DENSE_RANK_SYM
%token DESC /* SQL-2003-N */
@ -1995,6 +1996,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
vcol_opt_attribute_list vcol_attribute
opt_serial_attribute opt_serial_attribute_list serial_attribute
explainable_command
opt_delete_gtid_domain
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
@ -13319,7 +13321,7 @@ flush_option:
{ Lex->type|= REFRESH_GENERAL_LOG; }
| SLOW LOGS_SYM
{ Lex->type|= REFRESH_SLOW_LOG; }
| BINARY LOGS_SYM
| BINARY LOGS_SYM opt_delete_gtid_domain
{ Lex->type|= REFRESH_BINARY_LOG; }
| RELAY LOGS_SYM optional_connection_name
{
@ -13376,6 +13378,24 @@ opt_table_list:
| table_list {}
;
opt_delete_gtid_domain:
/* empty */ {}
| DELETE_DOMAIN_ID_SYM '=' '(' delete_domain_id_list ')'
{}
;
delete_domain_id_list:
/* Empty */
| delete_domain_id
| delete_domain_id_list ',' delete_domain_id
;
delete_domain_id:
ulong_num
{
insert_dynamic(&Lex->delete_gtid_domain, (uchar*) &($1));
}
;
optional_flush_tables_arguments:
/* empty */ {$$= 0;}
| AND_SYM DISABLE_SYM CHECKPOINT_SYM {$$= REFRESH_CHECKPOINT; }

View File

@ -507,6 +507,9 @@ wsrep_run_wsrep_commit(THD *thd, bool all)
}
mysql_mutex_lock(&thd->LOCK_wsrep_thd);
DEBUG_SYNC(thd, "wsrep_after_replication");
switch(rcode) {
case 0:
/*

View File

@ -2021,7 +2021,7 @@ static bool abort_replicated(THD *thd)
bool ret_code= false;
if (thd->wsrep_query_state== QUERY_COMMITTING)
{
WSREP_DEBUG("aborting replicated trx: %lu", thd->real_id);
WSREP_DEBUG("aborting replicated trx: %llu", (ulonglong)(thd->real_id));
(void)wsrep_abort_thd(thd, thd, TRUE);
ret_code= true;

View File

@ -327,8 +327,9 @@ bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type)
if (wsrep_inited == 1)
wsrep_deinit(false);
char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider
char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider
//when fails
if (wsrep_init())
{
my_error(ER_CANT_OPEN_LIBRARY, MYF(0), tmp);

View File

@ -547,14 +547,12 @@ PTABDEF OEMDEF::GetXdef(PGLOBAL g)
} // endif dladdr
#endif // 0
// Is the library already loaded?
if (!Hdll && !(Hdll = dlopen(soname, RTLD_NOLOAD)))
// Load the desired shared library
if (!(Hdll = dlopen(soname, RTLD_LAZY))) {
error = dlerror();
sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error));
return NULL;
} // endif Hdll
// Load the desired shared library
if (!Hdll && !(Hdll = dlopen(soname, RTLD_LAZY))) {
error = dlerror();
sprintf(g->Message, MSG(SHARED_LIB_ERR), soname, SVP(error));
return NULL;
} // endif Hdll
// The exported name is always in uppercase
for (int i = 0; ; i++) {

View File

@ -1438,11 +1438,11 @@ row_ins_foreign_check_on_constraint(
#ifdef WITH_WSREP
err = wsrep_append_foreign_key(
thr_get_trx(thr),
foreign,
clust_rec,
clust_index,
FALSE, FALSE);
thr_get_trx(thr),
foreign,
clust_rec,
clust_index,
FALSE, FALSE);
if (err != DB_SUCCESS) {
fprintf(stderr,
"WSREP: foreign key append failed: %d\n", err);

View File

@ -15,7 +15,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
cmake_minimum_required(VERSION 2.6)
project(mroonga)
@ -51,6 +51,14 @@ if(MSVC)
endif()
endif()
if(MRN_BUNDLED)
if(WITHOUT_MROONGA OR
WITHOUT_MROONGA_STORAGE_ENGINE OR
"${PLUGIN_MROONGA}" STREQUAL "NO")
return()
endif()
endif()
set(MRN_BUNDLED_GROONGA_RELATIVE_DIR "vendor/groonga")
set(MRN_BUNDLED_GROONGA_DIR
"${CMAKE_CURRENT_SOURCE_DIR}/${MRN_BUNDLED_GROONGA_RELATIVE_DIR}")
@ -79,6 +87,58 @@ file(READ ${MRN_SOURCE_DIR}/version_micro MRN_VERSION_MICRO)
file(READ ${MRN_SOURCE_DIR}/version_in_hex MRN_VERSION_IN_HEX)
file(READ ${MRN_SOURCE_DIR}/plugin_version MRN_PLUGIN_VERSION)
if(MRN_GROONGA_BUNDLED)
option(MRN_GROONGA_EMBED
"Embed libgroonga"
ON)
if(MRN_GROONGA_EMBED)
set(GRN_EMBED ON)
endif()
set(MRN_BUNDLED_GROONGA_NORMALIZER_MYSQL_DIR
"${MRN_BUNDLED_GROONGA_DIR}/vendor/plugins/groonga-normalizer-mysql")
option(MRN_GROONGA_NORMALIZER_MYSQL_EMBED
"Embed groonga-normalizer-mysql Groonga plugin"
ON)
if(EXISTS ${MRN_BUNDLED_GROONGA_NORMALIZER_MYSQL_DIR})
set(GROONGA_NORMALIZER_MYSQL_FOUND ON)
else()
set(GROONGA_NORMALIZER_MYSQL_FOUND OFF)
set(MRN_GROONGA_NORMALIZER_MYSQL_EMBED OFF)
endif()
if(MRN_GROONGA_NORMALIZER_MYSQL_EMBED)
set(GROONGA_NORMALIZER_MYSQL_EMBED ON)
endif()
file(READ "${MRN_BUNDLED_GROONGA_DIR}/bundled_lz4_version"
MRN_BUNDLED_LZ4_VERSION)
string(STRIP
"${MRN_BUNDLED_LZ4_VERSION}"
MRN_BUNDLED_LZ4_VERSION)
set(MRN_BUNDLED_LZ4_DIR
"${MRN_BUNDLED_GROONGA_DIR}/vendor/lz4-${MRN_BUNDLED_LZ4_VERSION}")
if(EXISTS ${MRN_BUNDLED_LZ4_DIR})
set(GRN_WITH_BUNDLED_LZ4 ON)
set(GRN_WITH_LZ4 "yes")
else()
set(GRN_WITH_LZ4 "no")
endif()
add_subdirectory("${MRN_BUNDLED_GROONGA_RELATIVE_DIR}")
else()
set(MRN_GROONGA_EMBED OFF)
file(READ ${MRN_SOURCE_DIR}/required_groonga_version REQUIRED_GROONGA_VERSION)
string(STRIP "${REQUIRED_GROONGA_VERSION}" REQUIRED_GROONGA_VERSION)
file(READ
${MRN_SOURCE_DIR}/required_groonga_normalizer_mysql_version
REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION)
string(STRIP
"${REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION}"
REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION)
endif()
set(MRN_PACKAGE_STRING "${PROJECT_NAME} ${MRN_VERSION}")
include(CheckCCompilerFlag)
@ -107,18 +167,7 @@ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/udf/sources.am MRN_UDF_SOURCES)
string(REGEX REPLACE "([^;]+)" "${MRN_RELATIVE_DIR_PREFIX}udf/\\1"
MRN_UDF_SOURCES "${MRN_UDF_SOURCES}")
set(MRN_ALL_SOURCES
${MRN_SOURCES}
${MRN_UDF_SOURCES}
${LIBMRN_NO_MYSQL_SOURCES}
${LIBMRN_NEED_MYSQL_SOURCES})
if(MRN_BUNDLED)
mysql_add_plugin(mroonga ${MRN_ALL_SOURCES} STORAGE_ENGINE MODULE_ONLY)
if(NOT TARGET mroonga)
return()
endif()
set(MYSQL_SOURCE_DIR ${CMAKE_SOURCE_DIR})
set(MYSQL_BUILD_DIR ${MYSQL_SOURCE_DIR})
set(MYSQL_CONFIG ${CMAKE_SOURCE_DIR}/scripts/mysql_config)
@ -134,44 +183,6 @@ else()
endif()
find_path(MYSQL_CONFIG "${MYSQL_CONFIG}")
if(MRN_GROONGA_BUNDLED)
option(MRN_GROONGA_EMBED
"Embed libgroonga"
ON)
if(MRN_GROONGA_EMBED)
set(GRN_EMBED ON)
endif()
set(MRN_BUNDLED_GROONGA_NORMALIZER_MYSQL_DIR
"${MRN_BUNDLED_GROONGA_DIR}/vendor/plugins/groonga-normalizer-mysql")
option(MRN_GROONGA_NORMALIZER_MYSQL_EMBED
"Embed groonga-normalizer-mysql Groonga plugin"
ON)
if(EXISTS ${MRN_BUNDLED_GROONGA_NORMALIZER_MYSQL_DIR})
set(GROONGA_NORMALIZER_MYSQL_FOUND ON)
else()
set(GROONGA_NORMALIZER_MYSQL_FOUND OFF)
set(MRN_GROONGA_NORMALIZER_MYSQL_EMBED OFF)
endif()
if(MRN_GROONGA_NORMALIZER_MYSQL_EMBED)
set(GROONGA_NORMALIZER_MYSQL_EMBED ON)
endif()
add_subdirectory("${MRN_BUNDLED_GROONGA_RELATIVE_DIR}")
else()
set(MRN_GROONGA_EMBED OFF)
file(READ ${MRN_SOURCE_DIR}/required_groonga_version REQUIRED_GROONGA_VERSION)
string(STRIP "${REQUIRED_GROONGA_VERSION}" REQUIRED_GROONGA_VERSION)
file(READ
${MRN_SOURCE_DIR}/required_groonga_normalizer_mysql_version
REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION)
string(STRIP
"${REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION}"
REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION)
endif()
if(EXISTS "${MYSQL_SOURCE_DIR}/storage/maria")
set(MYSQL_VARIANT "MariaDB")
else()
@ -194,6 +205,7 @@ if(EXISTS "${MYSQL_SOURCE_DIR}/libbinlogevents")
set(MYSQL_LIBBINLOGEVENTS_EXPORT_DIR
"${MYSQL_SOURCE_DIR}/libbinlogevents/export")
set(MYSQL_LIBBINLOGEVENTS_INCLUDE_DIR
"${MYSQL_BUILD_DIR}/libbinlogevents/include"
"${MYSQL_SOURCE_DIR}/libbinlogevents/include")
else()
set(MYSQL_LIBBINLOGEVENTS_EXPORT_DIR)
@ -270,6 +282,7 @@ else()
set(MRN_LIBRARY_DIRS
${MRN_LIBRARY_DIRS}
${GROONGA_LIBRARY_DIRS})
set(MRN_LIBRARIES ${GROONGA_LIBRARIES})
endif()
include_directories(
@ -291,11 +304,17 @@ link_directories(
${MRN_LIBRARY_DIRS}
${MYSQL_LIBRARY_DIRS})
set(MRN_ALL_SOURCES
${MRN_SOURCES}
${MRN_UDF_SOURCES}
${LIBMRN_NO_MYSQL_SOURCES}
${LIBMRN_NEED_MYSQL_SOURCES})
if(MRN_BUNDLED)
target_link_libraries(mroonga ${MRN_LIBRARIES})
if(NOT TARGET mroonga)
return()
endif()
mysql_add_plugin(mroonga
${MRN_ALL_SOURCES}
STORAGE_ENGINE MODULE_ONLY
LINK_LIBRARIES ${MRN_LIBRARIES})
else()
add_library(mroonga MODULE ${MRN_ALL_SOURCES})
@ -340,8 +359,12 @@ else()
MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-strict-aliasing")
MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-deprecated")
MY_CHECK_AND_SET_COMPILER_FLAG("-fno-implicit-templates")
MY_CHECK_AND_SET_COMPILER_FLAG("-fno-exceptions")
MY_CHECK_AND_SET_COMPILER_FLAG("-fno-rtti")
if(("${MYSQL_VARIANT}" STREQUAL "MariaDB") OR
("${MYSQL_VARIANT}" STREQUAL "MySQL" AND
${MYSQL_VERSION} VERSION_LESS "5.7.0"))
MY_CHECK_AND_SET_COMPILER_FLAG("-fno-exceptions")
MY_CHECK_AND_SET_COMPILER_FLAG("-fno-rtti")
endif()
MY_CHECK_AND_SET_COMPILER_FLAG("-felide-constructors")
MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-implicit-fallthrough")
endif()
@ -362,10 +385,20 @@ else()
install(TARGETS mroonga DESTINATION "${MYSQL_PLUGIN_DIR}")
endif()
option(MRN_BUILD_FOR_EMBEDDED_SERVER
"Whether to build Mroonga for embedded server or not. You can't use Mroonga built for embedded server with non embedded server."
OFF)
if(MRN_BUILD_FOR_EMBEDDED_SERVER)
set_property(TARGET mroonga APPEND PROPERTY
COMPILE_DEFINITIONS "EMBEDDED_LIBRARY")
endif()
if(GROONGA_NORMALIZER_MYSQL_FOUND)
add_definitions("-DWITH_GROONGA_NORMALIZER_MYSQL=1")
set_property(TARGET mroonga APPEND PROPERTY
COMPILE_DEFINITIONS "WITH_GROONGA_NORMALIZER_MYSQL=1")
if(MRN_GROONGA_NORMALIZER_MYSQL_EMBED)
add_definitions("-DMRN_GROONGA_NORMALIZER_MYSQL_EMBEDDED")
set_property(TARGET mroonga APPEND PROPERTY
COMPILE_DEFINITIONS "MRN_GROONGA_NORMALIZER_MYSQL_EMBEDDED")
else()
set_property(TARGET mroonga APPEND PROPERTY
COMPILE_DEFINITIONS "GROONGA_NORMALIZER_MYSQL_PLUGIN_NAME=\"normalizers/mysql\"")
@ -373,7 +406,8 @@ if(GROONGA_NORMALIZER_MYSQL_FOUND)
endif()
if(MRN_GROONGA_EMBED)
add_definitions("-DMRN_GROONGA_EMBEDDED")
set_property(TARGET mroonga APPEND PROPERTY
COMPILE_DEFINITIONS "MRN_GROONGA_EMBEDDED")
endif()
set(MRN_DEFAULT_PARSER "" CACHE STRING
@ -419,6 +453,8 @@ else()
set(MRN_DATA_DIR "share/${PROJECT_NAME}")
endif()
install(FILES
"${PROJECT_SOURCE_DIR}/AUTHORS"
"${PROJECT_SOURCE_DIR}/COPYING"
"${PROJECT_BINARY_DIR}/data/install.sql"
"${PROJECT_SOURCE_DIR}/data/uninstall.sql"
DESTINATION "${MRN_DATA_DIR}/")

View File

@ -1,9 +1,9 @@
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_ARGS}
AUTOMAKE_OPTIONS = 1.9.7
LOCALES = ja
AM_CPPFLAGS = $(MYSQL_INCLUDES) $(GROONGA_CFLAGS) -I$(top_srcdir)/lib
ACLOCAL_AMFLAGS = $$ACLOCAL_ARGS
include sources.am
@ -49,7 +49,13 @@ tag:
cd $(top_srcdir) && \
git tag v$(VERSION) -a -m 'Mroonga $(VERSION)!!!'
update-latest-release: misc
ensure-cutter-source-path:
@if test -z "$(CUTTER_SOURCE_PATH)"; then \
echo "\$$(CUTTER_SOURCE_PATH) is missing"; \
exit 1; \
fi
update-latest-release: ensure-cutter-source-path
@if test -z "$(OLD_RELEASE)"; then \
echo "\$$(OLD_RELEASE) is missing"; \
exit 1; \
@ -63,17 +69,40 @@ update-latest-release: misc
exit 1; \
fi
cd $(top_srcdir) && \
misc/update-latest-release.rb \
"$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
$(PACKAGE) $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
$(VERSION) $(NEW_RELEASE_DATE) \
packages/rpm/centos/mariadb-mroonga.spec.in \
packages/rpm/centos/mariadb-10.1-mroonga.spec.in \
packages/rpm/centos/mariadb-10.2-mroonga.spec.in \
packages/rpm/centos/mysql55-mroonga.spec.in \
packages/rpm/centos/mysql56-community-mroonga.spec.in \
packages/debian/changelog \
packages/rpm/centos/mysql57-community-mroonga.spec.in \
packages/rpm/centos/percona-server-56-mroonga.spec.in \
packages/rpm/centos/percona-server-57-mroonga.spec.in \
doc/source/install/*.rst \
doc/locale/*/LC_MESSAGES/install.po \
$(MROONGA_GITHUB_COM_PATH)/index.html \
$(MROONGA_GITHUB_COM_PATH)/ja/index.html
$(MROONGA_GITHUB_COM_PATH)/_config.yml
cd $(top_srcdir) && \
"$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
$(PACKAGE)-5.5 $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
$(VERSION) $(NEW_RELEASE_DATE) \
packages/debian-5.5/changelog
cd $(top_srcdir) && \
"$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
$(PACKAGE)-5.6 $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
$(VERSION) $(NEW_RELEASE_DATE) \
packages/debian-5.6/changelog
cd $(top_srcdir) && \
"$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
$(PACKAGE)-5.7 $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
$(VERSION) $(NEW_RELEASE_DATE) \
packages/debian-5.7/changelog
cd $(top_srcdir) && \
"$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
$(PACKAGE)-mariadb-10.0 $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
$(VERSION) $(NEW_RELEASE_DATE) \
packages/debian-mariadb-10.0/changelog
update-po:
@for lang in $(LOCALES); do \
@ -144,10 +173,3 @@ upload-to-github:
echo-cutter:
echo $(CUTTER)
misc:
@if test -z "$(CUTTER_SOURCE_PATH)"; then \
echo "\$$(CUTTER_SOURCE_PATH) is missing"; \
exit 1; \
fi
ln -s "$(CUTTER_SOURCE_PATH)/misc" misc

View File

@ -1,54 +1,63 @@
version: "{build}"
clone_depth: 10
environment:
global:
MARIADB_VERSION: 10.1.26
matrix:
- CMAKE_GENERATOR_NAME: "Visual Studio 14 2015"
- CMAKE_GENERATOR_NAME: "Visual Studio 14 2015 Win64"
install:
- cd ..
- choco install -y curl 7zip.commandline
- curl -O http://mirror.jmu.edu/pub/mariadb/mariadb-10.0.20/source/mariadb-10.0.20.tar.gz
- 7z x mariadb-10.0.20.tar.gz
- 7z x mariadb-10.0.20.tar > nul
- cd mariadb-10.0.20
- curl -O http://mirror.jmu.edu/pub/mariadb/mariadb-%MARIADB_VERSION%/source/mariadb-%MARIADB_VERSION%.tar.gz
- 7z x mariadb-%MARIADB_VERSION%.tar.gz
- 7z x mariadb-%MARIADB_VERSION%.tar > nul
- cd mariadb-%MARIADB_VERSION%
- rmdir /S /Q storage\mroonga\
- move ..\mroonga storage\mroonga
- git clone --quiet --depth 1 https://github.com/groonga/groonga.git ..\groonga
- cd ..\groonga
- git submodule update --init
- cd ..\mariadb-10.0.20
- git clone --quiet --depth 1 --recursive https://github.com/groonga/groonga.git ..\groonga
- rmdir /S /Q ..\groonga\test\
- cd ..\groonga\vendor
- c:\Ruby22-x64\bin\ruby -v download_lz4.rb
- c:\Ruby22-x64\bin\ruby -v download_mecab.rb
- cd ..\..\mariadb-%MARIADB_VERSION%
- mkdir storage\mroonga\vendor
- move ..\groonga storage\mroonga\vendor\groonga
- git clone --quiet --depth 1 https://github.com/groonga/groonga-normalizer-mysql.git storage\mroonga\vendor\groonga\vendor\plugins\groonga-normalizer-mysql
build_script:
- "echo # > win\\packaging\\CMakeLists.txt"
- cmake . -G "Visual Studio 12 Win64"
- cmake . -G "%CMAKE_GENERATOR_NAME%"
-DCMAKE_BUILD_TYPE=Debug
-DWITHOUT_ARCHIVE=ON
-DWITHOUT_BLACKHOLE=ON
-DWITHOUT_CASSANDRA=ON
-DWITHOUT_CONNECT=ON
-DWITHOUT_CSV=ON
-DWITHOUT_EXAMPLE=ON
-DWITHOUT_FEDERATED=ON
-DWITHOUT_FEDERATEDX=ON
-DWITHOUT_HEAP=ON
-DWITHOUT_INNOBASE=ON
-DWITHOUT_MYISAM=ON
-DWITHOUT_MYISAMMRG=ON
-DWITHOUT_OQGRAPH=ON
-DWITHOUT_PERFSCHEMA=OFF
-DWITHOUT_SEQUENCE=ON
-DWITHOUT_SPHINX=ON
-DWITHOUT_SPIDER=ON
-DWITHOUT_TEST_SQL_DISCOVERY=ON
-DWITHOUT_TOKUDB=ON
-DWITHOUT_XTRADB=ON
-DPLUGIN_ARCHIVE=NO
-DPLUGIN_BLACKHOLE=NO
-DPLUGIN_CASSANDRA=NO
-DPLUGIN_CONNECT=NO
-DPLUGIN_CSV=NO
-DPLUGIN_EXAMPLE=NO
-DPLUGIN_FEDERATED=NO
-DPLUGIN_FEDERATEDX=NO
-DPLUGIN_HEAP=NO
-DPLUGIN_INNOBASE=NO
-DPLUGIN_MYISAM=NO
-DPLUGIN_MYISAMMRG=NO
-DPLUGIN_OQGRAPH=NO
-DPLUGIN_PERFSCHEMA=NO
-DPLUGIN_SEQUENCE=NO
-DPLUGIN_SPHINX=NO
-DPLUGIN_SPIDER=NO
-DPLUGIN_TEST_SQL_DISCOVERY=NO
-DPLUGIN_TOKUDB=NO
-DPLUGIN_XTRADB=NO
-DWITH_UNIT_TESTS=OFF
-DWITH_MARIABACKUP=OFF
-DGRN_WITH_BUNDLED_MECAB=ON
- cmake --build . --config Debug
notifications:
- provider: Email
to:
- groonga-mysql-commit@lists.sourceforge.jp
- kou@clear-code.com
on_build_status_changed: true
test: off

View File

@ -1,116 +1,11 @@
#!/bin/sh
warn() {
echo " WARNING: $@" 1>&2
}
# init
LIBTOOLIZE=libtoolize
ACLOCAL=aclocal
AUTOCONF=autoconf
AUTOHEADER=autoheader
AUTOMAKE=automake
case `uname -s` in
Darwin)
LIBTOOLIZE=glibtoolize
;;
case $(uname -s) in
FreeBSD)
ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal/"
;;
ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal/"
;;
esac
mkdir -p m4
# libtoolize
echo "Searching libtoolize..."
if [ `which $LIBTOOLIZE` ] ; then
echo " FOUND: libtoolize -> $LIBTOOLIZE"
else
warn "Cannot Found libtoolize... input libtool command"
read LIBTOOLIZE
LIBTOOLIZE=`which $LIBTOOLIZE`
if [ `which $LIBTOOLIZE` ] ; then
echo " SET: libtoolize -> $LIBTOOLIZE"
else
warn "$LIBTOOLIZE: Command not found."
exit 1;
fi
fi
# aclocal
echo "Searching aclocal..."
if [ `which $ACLOCAL` ] ; then
echo " FOUND: aclocal -> $ACLOCAL"
else
warn "Cannot Found aclocal... input aclocal command"
read ACLOCAL
ACLOCAL=`which $ACLOCAL`
if [ `which $ACLOCAL` ] ; then
echo " SET: aclocal -> $ACLOCAL"
else
warn "$ACLOCAL: Command not found."
exit 1;
fi
fi
# automake
echo "Searching automake..."
if [ `which $AUTOMAKE` ] ; then
echo " FOUND: automake -> $AUTOMAKE"
else
warn "Cannot Found automake... input automake command"
read AUTOMAKE
ACLOCAL=`which $AUTOMAKE`
if [ `which $AUTOMAKE` ] ; then
echo " SET: automake -> $AUTOMAKE"
else
warn "$AUTOMAKE: Command not found."
exit 1;
fi
fi
# autoheader
echo "Searching autoheader..."
if [ `which $AUTOHEADER` ] ; then
echo " FOUND: autoheader -> $AUTOHEADER"
else
warn "Cannot Found autoheader... input autoheader command"
read AUTOHEADER
ACLOCAL=`which $AUTOHEADER`
if [ `which $AUTOHEADER` ] ; then
echo " SET: autoheader -> $AUTOHEADER"
else
warn "$AUTOHEADER: Command not found."
exit 1;
fi
fi
# autoconf
echo "Searching autoconf..."
if [ `which $AUTOCONF` ] ; then
echo " FOUND: autoconf -> $AUTOCONF"
else
warn "Cannot Found autoconf... input autoconf command"
read AUTOCONF
ACLOCAL=`which $AUTOCONF`
if [ `which $AUTOCONF` ] ; then
echo " SET: autoconf -> $AUTOCONF"
else
warn "$AUTOCONF: Command not found."
exit 1;
fi
fi
set -e
echo "Running libtoolize ..."
$LIBTOOLIZE --force --copy
echo "Running aclocal ..."
$ACLOCAL ${ACLOCAL_ARGS}
echo "Running autoheader..."
$AUTOHEADER
echo "Running automake ..."
$AUTOMAKE --add-missing --copy
echo "Running autoconf ..."
$AUTOCONF
${AUTORECONF:-autoreconf} --force --install "$@"

View File

@ -10,10 +10,8 @@ PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = $(PAPEROPT_$(PAPER)) -E $(SPHINXOPTS) $(SOURCE_DIR)
SPHINX_DIR = $(abs_top_builddir)/doc/sphinx
SPHINX_BUILD_COMMAND = \
DOCUMENT_VERSION="$(DOCUMENT_VERSION)" \
DOCUMENT_VERSION_FULL="$(DOCUMENT_VERSION_FULL)" \
LOCALE="$(LOCALE)" \
PYTHONPATH="$(SPHINX_DIR):$$PYTHONPATH" \
$(SPHINX_BUILD)

View File

@ -12,7 +12,7 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
MYSQL_SOURCE_DIR="@MYSQL_SOURCE_DIR@"
MYSQL_BUILD_DIR="@MYSQL_BUILD_DIR@"

View File

@ -8,6 +8,7 @@ m4_define([mrn_version_in_hex], m4_include(version_in_hex))
m4_define([mrn_plugin_version], m4_include(plugin_version))
AC_INIT([mroonga], [mrn_version], [groonga-talk@lists.sourceforge.net])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([tar-pax foreign subdir-objects])
@ -173,18 +174,27 @@ AC_DEFUN([CONFIG_OPTION_MYSQL],[
MYSQL_INCLUDES=""
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_build_dir/include"
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/sql"
if test -d "$ac_mysql_source_dir/sql/auth"; then
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/sql/auth"
fi
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/include"
if test -d "$ac_mysql_source_dir/extra/rapidjson"; then
mysql_rapidjson_include_dir="$ac_mysql_source_dir/extra/rapidjson/include"
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$mysql_rapidjson_include_dir"
fi
if test -d "$ac_mysql_source_dir/pcre"; then
mysql_regex_include_dir="$ac_mysql_source_dir/pcre"
if test -d "$ac_mysql_source_dir/extra/regex"; then
mysql_regex_include_dir="$ac_mysql_source_dir/extra/regex"
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$mysql_regex_include_dir"
else
mysql_regex_include_dir="$ac_mysql_source_dir/regex"
if test -d "$ac_mysql_source_dir/pcre"; then
mysql_regex_include_dir="$ac_mysql_source_dir/pcre"
else
mysql_regex_include_dir="$ac_mysql_source_dir/regex"
fi
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$mysql_regex_include_dir"
fi
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$mysql_regex_include_dir"
if test -d "$ac_mysql_source_dir/libbinlogevents"; then
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_build_dir/libbinlogevents/include"
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/libbinlogevents/export"
MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/libbinlogevents/include"
fi
@ -199,7 +209,7 @@ AC_DEFUN([CONFIG_OPTION_MYSQL],[
MYSQL_CXXFLAGS="-fno-implicit-templates -felide-constructors"
case "$MYSQL_MAJOR_MINOR_VERSION" in
5.7)
5.7|8.*)
:
;;
*)
@ -381,6 +391,13 @@ AC_ARG_WITH(rsync-path,
[RSYNC_PATH="packages@packages.groonga.org:public"])
AC_SUBST(RSYNC_PATH)
AC_ARG_WITH(launchpad-ppa,
[AS_HELP_STRING([--with-launchpad-ppa=PPA],
[specify Launchpad Personal Package Archive. [default=groonga-ppa]])],
[LAUNCHPAD_PPA="$withval"],
[LAUNCHPAD_PPA="groonga-ppa"])
AC_SUBST(LAUNCHPAD_PPA)
AC_ARG_WITH(launchpad-uploader-pgp-key,
[AS_HELP_STRING([--with-launchpad-uploader-pgp-key=KEY],
[specify PGP key UID to upload Groonga packages to Launchpad.])],
@ -429,7 +446,7 @@ if test x"$enable_document" != x"no"; then
AC_PATH_PROG(SPHINX_BUILD, sphinx-build, [])
if test -n "$SPHINX_BUILD"; then
sphinx_build_version=`"$SPHINX_BUILD" --version`
if ! echo "$sphinx_build_version" | grep -q ' 1\.[[23]]'; then
if ! echo "$sphinx_build_version" | grep -q ' 1\.[[2-6]]'; then
AC_MSG_ERROR([
sphinx-build is old: $sphinx_build_version
Sphinx 1.2 or later is required.])
@ -509,12 +526,19 @@ AC_OUTPUT([
mrn_version.h
mysql-test/mroonga/storage/information_schema/r/plugins.result
mysql-test/mroonga/storage/variable/r/version.result
packages/debian/control
packages/debian-5.5/control
packages/debian-5.6/control
packages/debian-5.7/control
packages/debian-mariadb-10.0/control
packages/apt/env.sh
packages/rpm/centos/mysql55-mroonga.spec
packages/rpm/centos/mysql56-community-mroonga.spec
packages/rpm/centos/mysql57-community-mroonga.spec
packages/rpm/centos/mariadb-mroonga.spec
packages/rpm/centos/mariadb-10.1-mroonga.spec
packages/rpm/centos/mariadb-10.2-mroonga.spec
packages/rpm/centos/percona-server-56-mroonga.spec
packages/rpm/centos/percona-server-57-mroonga.spec
packages/yum/env.sh
data/install.sql
])

View File

@ -17,3 +17,19 @@ CREATE FUNCTION mroonga_command RETURNS STRING
DROP FUNCTION IF EXISTS mroonga_escape;
CREATE FUNCTION mroonga_escape RETURNS STRING
SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
DROP FUNCTION IF EXISTS mroonga_snippet_html;
CREATE FUNCTION mroonga_snippet_html RETURNS STRING
SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
DROP FUNCTION IF EXISTS mroonga_normalize;
CREATE FUNCTION mroonga_normalize RETURNS STRING
SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
DROP FUNCTION IF EXISTS mroonga_highlight_html;
CREATE FUNCTION mroonga_highlight_html RETURNS STRING
SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
DROP FUNCTION IF EXISTS mroonga_query_expand;
CREATE FUNCTION mroonga_query_expand RETURNS STRING
SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';

View File

@ -2,6 +2,10 @@ DROP FUNCTION IF EXISTS last_insert_grn_id;
DROP FUNCTION IF EXISTS mroonga_snippet;
DROP FUNCTION IF EXISTS mroonga_command;
DROP FUNCTION IF EXISTS mroonga_escape;
DROP FUNCTION IF EXISTS mroonga_snippet_html;
DROP FUNCTION IF EXISTS mroonga_normalize;
DROP FUNCTION IF EXISTS mroonga_highlight_html;
DROP FUNCTION IF EXISTS mroonga_query_expand;
UNINSTALL PLUGIN Mroonga;

File diff suppressed because it is too large Load Diff

View File

@ -13,3 +13,6 @@ EXPORTS
mroonga_escape
mroonga_escape_init
mroonga_escape_deinit
mroonga_normalize
mroonga_normalize_init
mroonga_normalize_deinit

View File

@ -32,6 +32,14 @@ extern "C" {
#include <groonga.h>
#include "mrn_mysql_compat.h"
#include <mrn_operations.hpp>
#include <mrn_database.hpp>
#if __cplusplus >= 201402
# define mrn_override override
#else
# define mrn_override
#endif
#if (MYSQL_VERSION_ID >= 50514 && MYSQL_VERSION_ID < 50600)
# define MRN_HANDLER_HAVE_FINAL_ADD_INDEX 1
@ -102,6 +110,13 @@ extern "C" {
# define MRN_HAVE_HA_EXTRA_PREPARE_FOR_FORCED_CLOSE
#endif
#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
#define MRN_HAVE_HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW
#define MRN_HAVE_HA_EXTRA_BEGIN_ALTER_COPY
#define MRN_HAVE_HA_EXTRA_END_ALTER_COPY
#define MRN_HAVE_HA_EXTRA_NO_AUTOINC_LOCKING
#endif
#if MYSQL_VERSION_ID >= 50607 && \
(!defined(MRN_MARIADB_P) || MYSQL_VERSION_ID < 100008)
# define MRN_HAVE_HA_EXTRA_EXPORT
@ -196,6 +211,10 @@ extern "C" {
# define MRN_FOREIGN_KEY_USE_CONST_STRING
#endif
#if MYSQL_VERSION_ID >= 100203 && defined(MRN_MARIADB_P)
# define MRN_FOREIGN_KEY_USE_METHOD_ENUM
#endif
#if MYSQL_VERSION_ID < 50706 || defined(MRN_MARIADB_P)
# define MRN_HANDLER_IS_FATAL_ERROR_HAVE_FLAGS
#endif
@ -204,6 +223,45 @@ extern "C" {
# define MRN_HANDLER_HAVE_RESET_AUTO_INCREMENT
#endif
#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 50709) || \
(defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 100203)
# define MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_TYPE \
Alter_inplace_info::ALTER_STORED_COLUMN_TYPE
# define MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_ORDER \
Alter_inplace_info::ALTER_STORED_COLUMN_ORDER
#else
# define MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_TYPE \
Alter_inplace_info::ALTER_COLUMN_TYPE
# define MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_ORDER \
Alter_inplace_info::ALTER_COLUMN_ORDER
#endif
#if MYSQL_VERSION_ID >= 50700 && !defined(MRN_MARIADB_P)
# define MRN_HANDLER_RECORDS_RETURN_ERROR
#endif
#if MYSQL_VERSION_ID < 80002 || defined(MRN_MARIADB_P)
# define MRN_HANDLER_HAVE_KEYS_TO_USE_FOR_SCANNING
#endif
#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
# define MRN_ST_MYSQL_PLUGIN_HAVE_CHECK_UNINSTALL
#endif
#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
# define MRN_HANDLER_OPEN_HAVE_TABLE_DEFINITION
# define MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
#endif
#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
# define MRN_HANDLERTON_CREATE_HAVE_PARTITIONED
#endif
#if defined(HAVE_PSI_INTERFACE) && \
(MYSQL_VERSION_ID < 80002 || defined(MRN_MARIADB_P))
# define MRN_HAVE_PSI_SERVER
#endif
class ha_mroonga;
/* structs */
@ -347,6 +405,8 @@ private:
// for ft in where clause test
Item_func_match *current_ft_item;
mrn::Operations *operations_;
public:
ha_mroonga(handlerton *hton, TABLE_SHARE *share_arg);
~ha_mroonga();
@ -357,8 +417,20 @@ public:
ulonglong table_flags() const; // required
ulong index_flags(uint idx, uint part, bool all_parts) const; // required
int create(const char *name, TABLE *form, HA_CREATE_INFO *info); // required
int open(const char *name, int mode, uint test_if_locked); // required
// required
int create(const char *name, TABLE *form, HA_CREATE_INFO *info
#ifdef MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
,
dd::Table *table_def
#endif
) mrn_override;
// required
int open(const char *name, int mode, uint open_options
#ifdef MRN_HANDLER_OPEN_HAVE_TABLE_DEFINITION
,
const dd::Table *table_def
#endif
) mrn_override;
#ifndef MRN_HANDLER_HAVE_HA_CLOSE
int close(); // required
#endif
@ -419,11 +491,6 @@ public:
#endif
int index_next_same(uchar *buf, const uchar *key, uint keylen);
int read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_range, bool sorted);
int read_range_next();
int ft_init();
FT_INFO *ft_init_ext(uint flags, uint inx, String *key);
int ft_read(uchar *buf);
@ -469,7 +536,9 @@ public:
int truncate();
double scan_time();
double read_time(uint index, uint ranges, ha_rows rows);
#ifdef MRN_HANDLER_HAVE_KEYS_TO_USE_FOR_SCANNING
const key_map *keys_to_use_for_scanning();
#endif
ha_rows estimate_rows_upper_bound();
void update_create_info(HA_CREATE_INFO* create_info);
int rename_table(const char *from, const char *to);
@ -518,6 +587,11 @@ public:
int start_stmt(THD *thd, thr_lock_type lock_type);
protected:
#ifdef MRN_HANDLER_RECORDS_RETURN_ERROR
int records(ha_rows *num_rows);
#else
ha_rows records();
#endif
#ifdef MRN_HANDLER_HAVE_HA_RND_NEXT
int rnd_next(uchar *buf);
#endif
@ -580,6 +654,9 @@ private:
bool have_unique_index();
bool is_foreign_key_field(const char *table_name,
const char *field_name);
void push_warning_unsupported_spatial_index_search(enum ha_rkey_function flag);
void clear_cursor();
void clear_cursor_geo();
@ -592,7 +669,8 @@ private:
void remove_grn_obj_force(const char *name);
int drop_index(MRN_SHARE *target_share, uint key_index);
int drop_indexes_normal(const char *table_name, grn_obj *table);
int drop_indexes_multiple(const char *table_name, grn_obj *table);
int drop_indexes_multiple(const char *table_name, grn_obj *table,
const char *index_table_name_separator);
int drop_indexes(const char *table_name);
bool find_column_flags(Field *field, MRN_SHARE *mrn_share, int i,
grn_obj_flags *column_flags);
@ -600,9 +678,10 @@ private:
int error_code);
grn_obj *find_tokenizer(KEY *key, MRN_SHARE *mrn_share, int i);
grn_obj *find_tokenizer(const char *name, int name_length);
bool have_custom_normalizer(KEY *key) const;
grn_obj *find_normalizer(KEY *key);
grn_obj *find_normalizer(KEY *key, const char *name);
bool find_index_column_flags(KEY *key, grn_obj_flags *index_column_flags);
bool find_index_column_flags(KEY *key, grn_column_flags *index_column_flags);
bool find_token_filters(KEY *key, grn_obj *token_filters);
bool find_token_filters_put(grn_obj *token_filters,
const char *token_filter_name,
@ -622,9 +701,7 @@ private:
bool is_dry_write();
bool is_enable_optimization();
bool should_normalize(Field *field) const;
bool is_temporary_table_name(const char *name) const;
void check_count_skip(key_part_map start_key_part_map,
key_part_map end_key_part_map, bool fulltext);
void check_count_skip(key_part_map target_key_part_map);
bool is_grn_zero_column_value(grn_obj *column, grn_obj *value);
bool is_primary_key_field(Field *field) const;
void check_fast_order_limit(grn_table_sort_key **sort_keys, int *n_sort_keys,
@ -652,6 +729,9 @@ private:
int generic_store_bulk_new_decimal(Field *field, grn_obj *buf);
int generic_store_bulk_blob(Field *field, grn_obj *buf);
int generic_store_bulk_geometry(Field *field, grn_obj *buf);
#ifdef MRN_HAVE_MYSQL_TYPE_JSON
int generic_store_bulk_json(Field *field, grn_obj *buf);
#endif
int generic_store_bulk(Field *field, grn_obj *buf);
void storage_store_field_string(Field *field,
@ -687,6 +767,10 @@ private:
const char *value, uint value_length);
void storage_store_field_geometry(Field *field,
const char *value, uint value_length);
#ifdef MRN_HAVE_MYSQL_TYPE_JSON
void storage_store_field_json(Field *field,
const char *value, uint value_length);
#endif
void storage_store_field(Field *field, const char *value, uint value_length);
void storage_store_field_column(Field *field, bool is_primary_key,
int nth_column, grn_id record_id);
@ -731,6 +815,15 @@ private:
int storage_encode_multiple_column_key(KEY *key_info,
const uchar *key, uint key_length,
uchar *buffer, uint *encoded_length);
int storage_encode_multiple_column_key_range(KEY *key_info,
const uchar *start,
uint start_size,
const uchar *end,
uint end_size,
uchar *min_buffer,
uint *min_encoded_size,
uchar *max_buffer,
uint *max_encoded_size);
int storage_encode_multiple_column_key_range(KEY *key_info,
const key_range *start,
const key_range *end,
@ -758,9 +851,7 @@ private:
grn_obj **index_tables,
grn_obj **index_columns,
MRN_SHARE *tmp_share);
int wrapper_create_index(const char *name, TABLE *table,
HA_CREATE_INFO *info, MRN_SHARE *tmp_share,
const char *grn_table_name);
int wrapper_create_index(const char *name, TABLE *table, MRN_SHARE *tmp_share);
int storage_create_validate_pseudo_column(TABLE *table);
#ifdef MRN_SUPPORT_FOREIGN_KEYS
bool storage_create_foreign_key(TABLE *table, const char *grn_table_name,
@ -778,16 +869,18 @@ private:
int storage_create_indexes(TABLE *table, const char *grn_table_name,
grn_obj *grn_table, MRN_SHARE *tmp_share);
int close_databases();
int ensure_database_open(const char *name);
int ensure_database_open(const char *name, mrn::Database **db=NULL);
int ensure_database_remove(const char *name);
int wrapper_delete_table(const char *name, handlerton *wrap_handlerton,
const char *table_name);
int generic_delete_table(const char *name, const char *table_name);
int wrapper_open(const char *name, int mode, uint test_if_locked);
int wrapper_open(const char *name, int mode, uint open_options);
int wrapper_open_indexes(const char *name);
int storage_open(const char *name, int mode, uint test_if_locked);
int storage_reindex();
int storage_open(const char *name, int mode, uint open_options);
int open_table(const char *name);
int storage_open_columns(void);
void storage_close_columns(void);
int storage_open_indexes(const char *name);
void wrapper_overwrite_index_bits();
int wrapper_close();
@ -872,6 +965,13 @@ private:
void storage_info_variable();
void storage_info_variable_records();
void storage_info_variable_data_file_length();
#ifdef MRN_HANDLER_RECORDS_RETURN_ERROR
int wrapper_records(ha_rows *num_rows);
int storage_records(ha_rows *num_rows);
#else
ha_rows wrapper_records();
ha_rows storage_records();
#endif
int wrapper_rnd_init(bool scan);
int storage_rnd_init(bool scan);
int wrapper_rnd_end();
@ -914,14 +1014,6 @@ private:
int storage_index_last(uchar *buf);
int wrapper_index_next_same(uchar *buf, const uchar *key, uint keylen);
int storage_index_next_same(uchar *buf, const uchar *key, uint keylen);
int wrapper_read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_range, bool sorted);
int storage_read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_range, bool sorted);
int wrapper_read_range_next();
int storage_read_range_next();
int generic_ft_init();
int wrapper_ft_init();
int storage_ft_init();
@ -929,41 +1021,18 @@ private:
FT_INFO *storage_ft_init_ext(uint flags, uint key_nr, String *key);
void generic_ft_init_ext_add_conditions_fast_order_limit(
struct st_mrn_ft_info *info, grn_obj *expression);
bool generic_ft_init_ext_parse_pragma_d(struct st_mrn_ft_info *info,
const char *keyword,
uint keyword_length,
grn_operator *default_operator,
uint *consumed_keyword_length);
void generic_ft_init_ext_parse_pragma_w_append_section(
struct st_mrn_ft_info *info,
grn_obj *index_column,
grn_obj *match_columns,
uint section,
grn_obj *section_value_buffer,
int weight,
uint n_weights);
bool generic_ft_init_ext_parse_pragma_w(struct st_mrn_ft_info *info,
const char *keyword,
uint keyword_length,
grn_obj *index_column,
grn_obj *match_columns,
uint *consumed_keyword_length,
grn_obj *tmp_objects);
grn_expr_flags expr_flags_in_boolean_mode();
grn_rc generic_ft_init_ext_prepare_expression_in_boolean_mode(
struct st_mrn_ft_info *info,
String *key,
grn_obj *index_column,
grn_obj *match_columns,
grn_obj *expression,
grn_obj *tmp_objects);
grn_obj *expression);
grn_rc generic_ft_init_ext_prepare_expression_in_normal_mode(
struct st_mrn_ft_info *info,
String *key,
grn_obj *index_column,
grn_obj *match_columns,
grn_obj *expression,
grn_obj *tmp_objects);
grn_obj *expression);
struct st_mrn_ft_info *generic_ft_init_ext_select(uint flags,
uint key_nr,
String *key);
@ -1041,8 +1110,10 @@ private:
double storage_scan_time();
double wrapper_read_time(uint index, uint ranges, ha_rows rows);
double storage_read_time(uint index, uint ranges, ha_rows rows);
#ifdef MRN_HANDLER_HAVE_KEYS_TO_USE_FOR_SCANNING
const key_map *wrapper_keys_to_use_for_scanning();
const key_map *storage_keys_to_use_for_scanning();
#endif
ha_rows wrapper_estimate_rows_upper_bound();
ha_rows storage_estimate_rows_upper_bound();
void wrapper_update_create_info(HA_CREATE_INFO* create_info);
@ -1069,8 +1140,10 @@ private:
bool wrapper_auto_repair(int error) const;
bool storage_auto_repair(int error) const;
int generic_disable_index(int i, KEY *key_info);
int wrapper_disable_indexes_mroonga(uint mode);
int wrapper_disable_indexes(uint mode);
int storage_disable_indexes(uint mode);
int wrapper_enable_indexes_mroonga(uint mode);
int wrapper_enable_indexes(uint mode);
int storage_enable_indexes(uint mode);
int wrapper_check(THD* thd, HA_CHECK_OPT* check_opt);
@ -1111,8 +1184,10 @@ private:
Alter_inplace_info *ha_alter_info);
bool wrapper_inplace_alter_table(TABLE *altered_table,
Alter_inplace_info *ha_alter_info);
bool storage_inplace_alter_table_index(TABLE *altered_table,
Alter_inplace_info *ha_alter_info);
bool storage_inplace_alter_table_add_index(TABLE *altered_table,
Alter_inplace_info *ha_alter_info);
bool storage_inplace_alter_table_drop_index(TABLE *altered_table,
Alter_inplace_info *ha_alter_info);
bool storage_inplace_alter_table_add_column(TABLE *altered_table,
Alter_inplace_info *ha_alter_info);
bool storage_inplace_alter_table_drop_column(TABLE *altered_table,
@ -1208,7 +1283,9 @@ private:
void storage_free_foreign_key_create_info(char* str);
void wrapper_set_keys_in_use();
void storage_set_keys_in_use();
#ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
bool check_written_by_row_based_binlog();
#endif
#ifdef MRN_HAVE_HA_REBIND_PSI
void wrapper_unbind_psi();
void storage_unbind_psi();

View File

@ -28,4 +28,23 @@ libmrn_need_mysql_la_SOURCES = \
mrn_value_decoder.cpp \
mrn_value_decoder.hpp \
mrn_database_repairer.cpp \
mrn_database_repairer.hpp
mrn_database_repairer.hpp \
mrn_context_pool.cpp \
mrn_context_pool.hpp \
mrn_operations.cpp \
mrn_operations.hpp \
mrn_operation.cpp \
mrn_operation.hpp \
mrn_database.cpp \
mrn_database.hpp \
mrn_column_name.cpp \
mrn_column_name.hpp \
mrn_count_skip_checker.cpp \
mrn_count_skip_checker.hpp \
mrn_query_parser.cpp \
mrn_query_parser.hpp \
mrn_current_thread.hpp \
mrn_smart_bitmap.cpp \
mrn_smart_bitmap.hpp \
mrn_table_fields_offset_mover.cpp \
mrn_table_fields_offset_mover.hpp

View File

@ -0,0 +1,63 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2016 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <mrn_mysql.h>
#include <mrn_mysql_compat.h>
#include "mrn_column_name.hpp"
#include <strfunc.h>
#include <string.h>
// for debug
#define MRN_CLASS_NAME "mrn::ColumnName"
namespace mrn {
ColumnName::ColumnName(const char *mysql_name)
: mysql_name_(mysql_name) {
encode();
}
const char *ColumnName::mysql_name() {
return mysql_name_;
}
const char *ColumnName::c_str() {
return name_;
}
size_t ColumnName::length() {
return length_;
}
void ColumnName::encode() {
MRN_DBUG_ENTER_METHOD();
uint errors;
length_ = mrn_strconvert(system_charset_info,
mysql_name_,
strlen(mysql_name_),
&my_charset_filename,
name_,
MRN_MAX_PATH_SIZE,
&errors);
name_[length_] = '\0';
DBUG_VOID_RETURN;
}
}

View File

@ -0,0 +1,38 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2016 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <mrn_constants.hpp>
namespace mrn {
class ColumnName {
public:
ColumnName(const char *mysql_name);
const char *mysql_name();
const char *c_str();
size_t length();
private:
const char *mysql_name_;
char name_[MRN_MAX_PATH_SIZE];
size_t length_;
void encode();
};
}

View File

@ -1,6 +1,6 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2013-2014 Kouhei Sutou <kou@clear-code.com>
Copyright(C) 2013-2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -175,7 +175,7 @@ namespace mrn {
bool convertable = false;
enum_field_types field_type = field_item->field_type();
enum_field_types field_type = field_item->field->real_type();
NormalizedType normalized_type = normalize_field_type(field_type);
switch (normalized_type) {
case STRING_TYPE:
@ -185,7 +185,12 @@ namespace mrn {
}
break;
case INT_TYPE:
convertable = value_item->type() == Item::INT_ITEM;
if (field_type == MYSQL_TYPE_ENUM) {
convertable = (value_item->type() == Item::STRING_ITEM ||
value_item->type() == Item::INT_ITEM);
} else {
convertable = value_item->type() == Item::INT_ITEM;
}
break;
case TIME_TYPE:
if (is_valid_time_value(field_item, value_item)) {
@ -206,7 +211,7 @@ namespace mrn {
bool convertable = false;
enum_field_types field_type = field_item->field_type();
enum_field_types field_type = field_item->field->type();
NormalizedType normalized_type = normalize_field_type(field_type);
switch (normalized_type) {
case STRING_TYPE:
@ -251,7 +256,7 @@ namespace mrn {
bool error;
Item *real_value_item = value_item->real_item();
switch (field_item->field_type()) {
switch (field_item->field->type()) {
case MYSQL_TYPE_TIME:
error = real_value_item->get_time(mysql_time);
break;
@ -352,6 +357,11 @@ namespace mrn {
case MYSQL_TYPE_GEOMETRY:
type = UNSUPPORTED_TYPE;
break;
#ifdef MRN_HAVE_MYSQL_TYPE_JSON
case MYSQL_TYPE_JSON:
type = STRING_TYPE;
break;
#endif
}
DBUG_RETURN(type);
@ -404,11 +414,11 @@ namespace mrn {
DBUG_RETURN(have);
}
const Item_func *ConditionConverter::find_match_against(const Item *item) {
unsigned int ConditionConverter::count_match_against(const Item *item) {
MRN_DBUG_ENTER_METHOD();
if (!item) {
DBUG_RETURN(NULL);
DBUG_RETURN(0);
}
switch (item->type()) {
@ -416,14 +426,13 @@ namespace mrn {
if (is_storage_mode_) {
Item_cond *cond_item = (Item_cond *)item;
if (cond_item->functype() == Item_func::COND_AND_FUNC) {
unsigned int n_match_againsts = 0;
List_iterator<Item> iterator(*((cond_item)->argument_list()));
const Item *sub_item;
while ((sub_item = iterator++)) {
const Item_func *match_against = find_match_against(sub_item);
if (match_against) {
DBUG_RETURN(match_against);
}
n_match_againsts += count_match_against(sub_item);
}
DBUG_RETURN(n_match_againsts);
}
}
break;
@ -432,7 +441,7 @@ namespace mrn {
const Item_func *func_item = (const Item_func *)item;
switch (func_item->functype()) {
case Item_func::FT_FUNC:
DBUG_RETURN(func_item);
DBUG_RETURN(1);
break;
default:
break;
@ -443,7 +452,7 @@ namespace mrn {
break;
}
DBUG_RETURN(NULL);
DBUG_RETURN(0);
}
void ConditionConverter::convert(const Item *where, grn_obj *expression) {
@ -560,7 +569,7 @@ namespace mrn {
grn_obj *expression) {
MRN_DBUG_ENTER_METHOD();
enum_field_types field_type = field_item->field_type();
enum_field_types field_type = field_item->field->real_type();
NormalizedType normalized_type = normalize_field_type(field_type);
switch (normalized_type) {
@ -574,7 +583,21 @@ namespace mrn {
break;
case INT_TYPE:
grn_obj_reinit(ctx_, &value_, GRN_DB_INT64, 0);
GRN_INT64_SET(ctx_, &value_, const_item->val_int());
if (field_type == MYSQL_TYPE_ENUM) {
if (const_item->type() == Item::STRING_ITEM) {
String *string;
string = const_item->val_str(NULL);
Field_enum *enum_field = static_cast<Field_enum *>(field_item->field);
int enum_value = find_type(string->c_ptr(),
enum_field->typelib,
FIND_TYPE_BASIC);
GRN_INT64_SET(ctx_, &value_, enum_value);
} else {
GRN_INT64_SET(ctx_, &value_, const_item->val_int());
}
} else {
GRN_INT64_SET(ctx_, &value_, const_item->val_int());
}
break;
case TIME_TYPE:
grn_obj_reinit(ctx_, &value_, GRN_DB_TIME, 0);

View File

@ -33,7 +33,7 @@ namespace mrn {
~ConditionConverter();
bool is_convertable(const Item *item);
const Item_func *find_match_against(const Item *item);
unsigned int count_match_against(const Item *item);
// caller must check "where" can be convertable by
// is_convertable(). This method doesn't validate "where".
void convert(const Item *where, grn_obj *expression);

View File

@ -0,0 +1,120 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mrn_context_pool.hpp"
#include "mrn_lock.hpp"
#include <time.h>
namespace mrn {
// for debug
#define MRN_CLASS_NAME "mrn::ContextPool::Impl"
class ContextPool::Impl {
public:
Impl(mysql_mutex_t *mutex)
: mutex_(mutex),
pool_(NULL),
last_pull_time_(0) {
}
~Impl(void) {
clear();
}
grn_ctx *pull(void) {
MRN_DBUG_ENTER_METHOD();
grn_ctx *ctx = NULL;
{
time_t now;
time(&now);
mrn::Lock lock(mutex_);
if (pool_) {
ctx = static_cast<grn_ctx *>(pool_->data);
list_pop(pool_);
if ((now - last_pull_time_) >= CLEAR_THREATHOLD_IN_SECONDS) {
clear();
}
}
last_pull_time_ = now;
}
if (!ctx) {
ctx = grn_ctx_open(0);
}
DBUG_RETURN(ctx);
}
void release(grn_ctx *ctx) {
MRN_DBUG_ENTER_METHOD();
{
mrn::Lock lock(mutex_);
list_push(pool_, ctx);
grn_ctx_use(ctx, NULL);
}
DBUG_VOID_RETURN;
}
private:
static const unsigned int CLEAR_THREATHOLD_IN_SECONDS = 60 * 5;
mysql_mutex_t *mutex_;
LIST *pool_;
time_t last_pull_time_;
void clear(void) {
MRN_DBUG_ENTER_METHOD();
while (pool_) {
grn_ctx *ctx = static_cast<grn_ctx *>(pool_->data);
grn_ctx_close(ctx);
list_pop(pool_);
}
DBUG_VOID_RETURN;
}
};
// For debug
#undef MRN_CLASS_NAME
#define MRN_CLASS_NAME "mrn::ContextPool"
ContextPool::ContextPool(mysql_mutex_t *mutex)
: impl_(new Impl(mutex)) {
}
ContextPool::~ContextPool(void) {
delete impl_;
}
grn_ctx *ContextPool::pull(void) {
MRN_DBUG_ENTER_METHOD();
grn_ctx *ctx = impl_->pull();
DBUG_RETURN(ctx);
}
void ContextPool::release(grn_ctx *ctx) {
MRN_DBUG_ENTER_METHOD();
impl_->release(ctx);
DBUG_VOID_RETURN;
}
}

View File

@ -0,0 +1,41 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MRN_CONTEXT_POOL_HPP_
#define MRN_CONTEXT_POOL_HPP_
#include <mrn_mysql.h>
#include <groonga.h>
namespace mrn {
class ContextPool {
public:
ContextPool(mysql_mutex_t *mutex);
~ContextPool(void);
grn_ctx *pull(void);
void release(grn_ctx *context);
private:
class Impl;
Impl *impl_;
};
}
#endif /* MRN_CONTEXT_POOL_HPP_ */

View File

@ -0,0 +1,303 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2010-2013 Kentoku SHIBA
Copyright(C) 2011-2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mrn_count_skip_checker.hpp"
#include <item_sum.h>
// for debug
#define MRN_CLASS_NAME "mrn::CountSkipChecker"
namespace mrn {
CountSkipChecker::CountSkipChecker(grn_ctx *ctx,
TABLE *table,
SELECT_LEX *select_lex,
KEY *key_info,
key_part_map target_key_part_map,
bool is_storage_mode)
: ctx_(ctx),
table_(table),
select_lex_(select_lex),
key_info_(key_info),
target_key_part_map_(target_key_part_map),
is_storage_mode_(is_storage_mode) {
}
CountSkipChecker::~CountSkipChecker() {
}
bool CountSkipChecker::check() {
MRN_DBUG_ENTER_METHOD();
if (select_lex_->item_list.elements != 1) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] not only one item: %u",
select_lex_->item_list.elements);
DBUG_RETURN(false);
}
if (select_lex_->group_list.elements > 0) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] have groups: %u",
select_lex_->group_list.elements);
DBUG_RETURN(false);
}
if (MRN_SELECT_LEX_GET_HAVING_COND(select_lex_)) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] have HAVING");
DBUG_RETURN(false);
}
if (select_lex_->table_list.elements != 1) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] not only one table: %u",
select_lex_->table_list.elements);
DBUG_RETURN(false);
}
Item *info = static_cast<Item *>(select_lex_->item_list.first_node()->info);
if (info->type() != Item::SUM_FUNC_ITEM) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] item isn't sum function: %u",
info->type());
DBUG_RETURN(false);
}
Item_sum *sum_item = static_cast<Item_sum *>(info);
if (sum_item->sum_func() != Item_sum::COUNT_FUNC) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] not COUNT: %u",
sum_item->sum_func());
DBUG_RETURN(false);
}
if (ITEM_SUM_GET_NEST_LEVEL(sum_item) != 0 ||
ITEM_SUM_GET_AGGR_LEVEL(sum_item) != 0 ||
ITEM_SUM_GET_MAX_AGGR_LEVEL(sum_item) != -1 ||
sum_item->max_sum_func_level != -1) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] not simple COUNT(*): %d:%d:%d:%d",
ITEM_SUM_GET_NEST_LEVEL(sum_item),
ITEM_SUM_GET_AGGR_LEVEL(sum_item),
ITEM_SUM_GET_MAX_AGGR_LEVEL(sum_item),
sum_item->max_sum_func_level);
DBUG_RETURN(false);
}
Item *where = MRN_SELECT_LEX_GET_WHERE_COND(select_lex_);
if (!where) {
if (is_storage_mode_) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][true] no condition");
DBUG_RETURN(true);
} else {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] no condition with wrapper mode");
DBUG_RETURN(false);
}
}
bool skippable = is_skippable(where);
DBUG_RETURN(skippable);
}
bool CountSkipChecker::is_skippable(Item *where) {
MRN_DBUG_ENTER_METHOD();
bool skippable = false;
switch (where->type()) {
case Item::COND_ITEM:
{
Item_cond *cond_item = static_cast<Item_cond *>(where);
skippable = is_skippable(cond_item);
if (skippable) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][true] skippable multiple conditions");
}
}
break;
case Item::FUNC_ITEM:
{
Item_func *func_item = static_cast<Item_func *>(where);
if (func_item->functype() == Item_func::FT_FUNC) {
if (select_lex_->select_n_where_fields == 1) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][true] "
"only one full text search condition");
DBUG_RETURN(true);
} else {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] "
"full text search condition and more conditions: %u",
select_lex_->select_n_where_fields);
DBUG_RETURN(false);
}
} else {
skippable = is_skippable(func_item);
if (skippable) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][true] skippable condition");
}
}
}
break;
default:
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] unsupported top level item: %u",
where->type());
break;
}
DBUG_RETURN(skippable);
}
bool CountSkipChecker::is_skippable(Item_cond *cond_item) {
MRN_DBUG_ENTER_METHOD();
List_iterator<Item> iterator(*(cond_item->argument_list()));
Item *sub_item;
while ((sub_item = iterator++)) {
if (sub_item->type() != Item::FUNC_ITEM) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] "
"sub condition isn't function item: %u",
sub_item->type());
DBUG_RETURN(false);
}
if (!is_skippable(static_cast<Item_func *>(sub_item))) {
DBUG_RETURN(false);
}
}
DBUG_RETURN(true);
}
bool CountSkipChecker::is_skippable(Item_func *func_item) {
MRN_DBUG_ENTER_METHOD();
switch (func_item->functype()) {
case Item_func::EQ_FUNC:
case Item_func::EQUAL_FUNC:
case Item_func::NE_FUNC:
case Item_func::LT_FUNC:
case Item_func::LE_FUNC:
case Item_func::GE_FUNC:
case Item_func::GT_FUNC:
{
Item **arguments = func_item->arguments();
Item *left_item = arguments[0];
if (left_item->type() != Item::FIELD_ITEM) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] not field: %u:%u",
func_item->functype(),
left_item->type());
DBUG_RETURN(false);
}
bool skippable = is_skippable(static_cast<Item_field *>(left_item));
DBUG_RETURN(skippable);
}
break;
case Item_func::BETWEEN:
{
Item **arguments = func_item->arguments();
Item *target_item = arguments[0];
if (target_item->type() != Item::FIELD_ITEM) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] BETWEEN target isn't field: %u",
target_item->type());
DBUG_RETURN(false);
}
bool skippable = is_skippable(static_cast<Item_field *>(target_item));
DBUG_RETURN(skippable);
}
break;
case Item_func::MULT_EQUAL_FUNC:
#ifdef MRN_HAVE_ITEM_EQUAL_FIELDS_ITERATOR
{
Item_equal *equal_item = static_cast<Item_equal *>(func_item);
Item_equal_fields_iterator iterator(*equal_item);
Item *field_item;
while ((field_item = iterator++)) {
bool skippable = is_skippable(static_cast<Item_field *>(field_item));
if (!skippable) {
DBUG_RETURN(skippable);
}
}
DBUG_RETURN(true);
}
#endif
break;
default:
break;
}
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] unsupported function item: %u",
func_item->functype());
DBUG_RETURN(false);
}
bool CountSkipChecker::is_skippable(Item_field *field_item) {
MRN_DBUG_ENTER_METHOD();
Field *field = field_item->field;
if (!field) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] field is missing");
DBUG_RETURN(false);
}
if (field->table != table_) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] external table's field");
DBUG_RETURN(false);
}
if (!key_info_) {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] no active index: <%s>:<%s>",
*(field->table_name),
field->field_name);
DBUG_RETURN(false);
}
uint i;
KEY_PART_INFO *key_part = key_info_->key_part;
for (i = 0; i < KEY_N_KEY_PARTS(key_info_); i++) {
if (key_part[i].field == field) {
if ((target_key_part_map_ >> i) & 1) {
DBUG_RETURN(true);
} else {
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] "
"field's index are out of key part map: %u:%lu: <%s>:<%s>",
i,
target_key_part_map_,
*(field->table_name),
field->field_name);
DBUG_RETURN(false);
}
}
}
GRN_LOG(ctx_, GRN_LOG_DEBUG,
"[mroonga][count-skip][false] field isn't indexed: <%s>:<%s>",
*(field->table_name),
field->field_name);
DBUG_RETURN(false);
}
}

View File

@ -0,0 +1,57 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2016 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MRN_COUNT_SKIP_CHECKER_HPP_
#define MRN_COUNT_SKIP_CHECKER_HPP_
#include <mrn_mysql_compat.h>
#include <item_cmpfunc.h>
#include <groonga.h>
namespace mrn {
class CountSkipChecker {
public:
CountSkipChecker(grn_ctx *ctx,
TABLE *table,
SELECT_LEX *select_lex,
KEY *key_info,
key_part_map target_key_part_map,
bool is_storage_mode);
~CountSkipChecker();
bool check();
private:
grn_ctx *ctx_;
TABLE *table_;
SELECT_LEX *select_lex_;
KEY *key_info_;
key_part_map target_key_part_map_;
bool is_storage_mode_;
bool is_skippable(Item *where);
bool is_skippable(Item_cond *cond_item);
bool is_skippable(Item_func *func_item);
bool is_skippable(Item_field *field_item);
};
}
#endif /* MRN_COUNT_SKIP_CHECKER_HPP_ */

View File

@ -0,0 +1,27 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <mrn_mysql.h>
#include <mrn_mysql_compat.h>
#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
# include <current_thd.h>
#endif

View File

@ -0,0 +1,89 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <mrn_mysql.h>
#include "mrn_database.hpp"
#include "mrn_operations.hpp"
// for debug
#define MRN_CLASS_NAME "mrn::Database"
namespace mrn {
Database::Database(grn_ctx *ctx, grn_obj *db)
: ctx_(ctx),
db_(db),
broken_table_names_(NULL),
is_broken_(false) {
Operations operations(ctx_);
broken_table_names_ = operations.collect_processing_table_names();
is_broken_ = operations.is_locked();
}
Database::~Database(void) {
close();
}
void Database::close() {
MRN_DBUG_ENTER_METHOD();
if (db_) {
grn_hash_close(ctx_, broken_table_names_);
broken_table_names_ = NULL;
grn_obj_close(ctx_, db_);
db_ = NULL;
}
DBUG_VOID_RETURN;
}
grn_rc Database::remove() {
MRN_DBUG_ENTER_METHOD();
grn_rc rc = GRN_SUCCESS;
if (db_) {
grn_hash_close(ctx_, broken_table_names_);
broken_table_names_ = NULL;
rc = grn_obj_remove(ctx_, db_);
if (rc == GRN_SUCCESS) {
db_ = NULL;
}
}
DBUG_RETURN(rc);
}
grn_obj *Database::get() {
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(db_);
}
bool Database::is_broken() {
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(is_broken_);
}
bool Database::is_broken_table(const char *name, size_t name_size) {
MRN_DBUG_ENTER_METHOD();
grn_id id = grn_hash_get(ctx_, broken_table_names_, name, name_size, NULL);
DBUG_RETURN(id != GRN_ID_NIL);
}
void Database::mark_table_repaired(const char *name, size_t name_size) {
MRN_DBUG_ENTER_METHOD();
grn_hash_delete(ctx_, broken_table_names_, name, name_size, NULL);
DBUG_VOID_RETURN;
}
}

View File

@ -0,0 +1,47 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MRN_DATABASE_HPP_
#define MRN_DATABASE_HPP_
#include <groonga.h>
namespace mrn {
class Database {
public:
Database(grn_ctx *ctx, grn_obj *db);
~Database(void);
void close();
grn_rc remove();
grn_obj *get();
bool is_broken();
bool is_broken_table(const char *name, size_t name_size);
void mark_table_repaired(const char *name, size_t name_size);
private:
grn_ctx *ctx_;
grn_obj *db_;
grn_hash *broken_table_names_;
bool is_broken_;
};
}
#endif /* MRN_DATABASE_HPP_ */

View File

@ -56,9 +56,9 @@ namespace mrn {
if (cache_) {
void *db_address;
GRN_HASH_EACH(ctx_, cache_, id, NULL, 0, &db_address, {
grn_obj *db;
Database *db;
memcpy(&db, db_address, sizeof(grn_obj *));
grn_obj_unlink(ctx_, db);
delete db;
});
grn_hash_close(ctx_, cache_);
}
@ -80,7 +80,7 @@ namespace mrn {
DBUG_RETURN(true);
}
int DatabaseManager::open(const char *path, grn_obj **db) {
int DatabaseManager::open(const char *path, Database **db) {
MRN_DBUG_ENTER_METHOD();
int error = 0;
@ -100,36 +100,54 @@ namespace mrn {
mapper.db_name(), strlen(mapper.db_name()),
&db_address);
if (id == GRN_ID_NIL) {
grn_obj *grn_db;
struct stat db_stat;
if (stat(mapper.db_path(), &db_stat)) {
GRN_LOG(ctx_, GRN_LOG_INFO,
"database not found. creating...: <%s>", mapper.db_path());
if (path[0] == FN_CURLIB &&
(path[1] == FN_LIBCHAR || path[1] == FN_LIBCHAR2)) {
mrn_is_directory_separator(path[1])) {
ensure_database_directory();
}
*db = grn_db_create(ctx_, mapper.db_path(), NULL);
grn_db = grn_db_create(ctx_, mapper.db_path(), NULL);
if (ctx_->rc) {
error = ER_CANT_CREATE_TABLE;
my_message(error, ctx_->errbuf, MYF(0));
DBUG_RETURN(error);
}
} else {
*db = grn_db_open(ctx_, mapper.db_path());
grn_db = grn_db_open(ctx_, mapper.db_path());
if (ctx_->rc) {
error = ER_CANT_OPEN_FILE;
my_message(error, ctx_->errbuf, MYF(0));
DBUG_RETURN(error);
}
}
*db = new Database(ctx_, grn_db);
grn_hash_add(ctx_, cache_,
mapper.db_name(), strlen(mapper.db_name()),
&db_address, NULL);
memcpy(db_address, db, sizeof(grn_obj *));
error = ensure_normalizers_registered(*db);
memcpy(db_address, db, sizeof(Database *));
error = ensure_normalizers_registered((*db)->get());
if (!error) {
if ((*db)->is_broken()) {
error = ER_CANT_OPEN_FILE;
char error_message[MRN_MESSAGE_BUFFER_SIZE];
snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
"mroonga: database: open: "
"The database maybe broken. "
"We recommend you to recreate the database. "
"If the database isn't broken, "
"you can remove this error by running "
"'groonga %s table_remove mroonga_operations' "
"on server. But the latter isn't recommended.",
mapper.db_path());
my_message(error, error_message, MYF(0));
}
}
} else {
memcpy(db, db_address, sizeof(grn_obj *));
grn_ctx_use(ctx_, *db);
memcpy(db, db_address, sizeof(Database *));
grn_ctx_use(ctx_, (*db)->get());
}
DBUG_RETURN(error);
@ -150,10 +168,11 @@ namespace mrn {
DBUG_VOID_RETURN;
}
grn_obj *db = NULL;
memcpy(&db, db_address, sizeof(grn_obj *));
Database *db = NULL;
memcpy(&db, db_address, sizeof(Database *));
grn_ctx_use(ctx_, db->get());
if (db) {
grn_obj_close(ctx_, db);
delete db;
}
grn_hash_delete_by_id(ctx_, cache_, id, NULL);
@ -173,29 +192,35 @@ namespace mrn {
mapper.db_name(), strlen(mapper.db_name()),
&db_address);
grn_obj *db = NULL;
Database *db = NULL;
if (id == GRN_ID_NIL) {
struct stat dummy;
if (stat(mapper.db_path(), &dummy) == 0) {
db = grn_db_open(ctx_, mapper.db_path());
grn_obj *grn_db = grn_db_open(ctx_, mapper.db_path());
db = new Database(ctx_, grn_db);
}
} else {
memcpy(&db, db_address, sizeof(grn_obj *));
memcpy(&db, db_address, sizeof(Database *));
grn_ctx_use(ctx_, db->get());
}
if (!db) {
DBUG_RETURN(false);
}
if (grn_obj_remove(ctx_, db) == GRN_SUCCESS) {
if (db->remove() == GRN_SUCCESS) {
if (id != GRN_ID_NIL) {
grn_hash_delete_by_id(ctx_, cache_, id, NULL);
}
delete db;
DBUG_RETURN(true);
} else {
GRN_LOG(ctx_, GRN_LOG_ERROR,
"failed to drop database: <%s>: <%s>",
mapper.db_path(), ctx_->errbuf);
if (id == GRN_ID_NIL) {
delete db;
}
DBUG_RETURN(false);
}
}
@ -223,22 +248,28 @@ namespace mrn {
break;
}
void *db_address;
grn_obj *db;
Database *db;
grn_hash_cursor_get_value(ctx_, cursor, &db_address);
memcpy(&db, db_address, sizeof(grn_obj *));
memcpy(&db, db_address, sizeof(Database *));
grn_ctx_use(ctx_, db->get());
grn_rc rc = grn_hash_cursor_delete(ctx_, cursor, NULL);
if (rc) {
error = ER_ERROR_ON_READ;
my_message(error, ctx_->errbuf, MYF(0));
break;
}
grn_obj_close(ctx_, db);
delete db;
}
grn_hash_cursor_close(ctx_, cursor);
DBUG_RETURN(error);
}
const char *DatabaseManager::error_message() {
MRN_DBUG_ENTER_METHOD();
DBUG_RETURN(ctx_->errbuf);
}
void DatabaseManager::mkdir_p(const char *directory) {
MRN_DBUG_ENTER_METHOD();
@ -246,8 +277,7 @@ namespace mrn {
char sub_directory[MRN_MAX_PATH_SIZE];
sub_directory[0] = '\0';
while (true) {
if (directory[i] == FN_LIBCHAR ||
directory[i] == FN_LIBCHAR2 ||
if (mrn_is_directory_separator(directory[i]) ||
directory[i] == '\0') {
sub_directory[i] = '\0';
struct stat directory_status;
@ -290,8 +320,10 @@ namespace mrn {
const char *last_path_separator;
last_path_separator = strrchr(path_prefix, FN_LIBCHAR);
#ifdef FN_LIBCHAR2
if (!last_path_separator)
last_path_separator = strrchr(path_prefix, FN_LIBCHAR2);
#endif
if (!last_path_separator)
DBUG_VOID_RETURN;
if (path_prefix == last_path_separator)

View File

@ -22,6 +22,8 @@
#ifndef MRN_DATABASE_MANAGER_HPP_
#define MRN_DATABASE_MANAGER_HPP_
#include "mrn_database.hpp"
#include <groonga.h>
namespace mrn {
@ -30,10 +32,11 @@ namespace mrn {
DatabaseManager(grn_ctx *ctx, mysql_mutex_t *mutex);
~DatabaseManager(void);
bool init(void);
int open(const char *path, grn_obj **db);
int open(const char *path, Database **db);
void close(const char *path);
bool drop(const char *path);
int clear(void);
const char *error_message();
private:
grn_ctx *ctx_;

View File

@ -1,6 +1,6 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
Copyright(C) 2015-2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -36,6 +36,16 @@
#endif
namespace mrn {
struct CheckResult {
CheckResult() :
is_crashed(false),
is_corrupt(false) {
}
bool is_crashed;
bool is_corrupt;
};
DatabaseRepairer::DatabaseRepairer(grn_ctx *ctx, THD *thd)
: ctx_(ctx),
thd_(thd),
@ -53,10 +63,19 @@ namespace mrn {
bool DatabaseRepairer::is_crashed(void) {
MRN_DBUG_ENTER_METHOD();
bool is_crashed = false;
each_database(&DatabaseRepairer::is_crashed_body, &is_crashed);
CheckResult result;
each_database(&DatabaseRepairer::check_body, &result);
DBUG_RETURN(is_crashed);
DBUG_RETURN(result.is_crashed);
}
bool DatabaseRepairer::is_corrupt(void) {
MRN_DBUG_ENTER_METHOD();
CheckResult result;
each_database(&DatabaseRepairer::check_body, &result);
DBUG_RETURN(result.is_corrupt);
}
bool DatabaseRepairer::repair(void) {
@ -81,9 +100,19 @@ namespace mrn {
DBUG_VOID_RETURN;
}
do {
each_database_body(data.cFileName, each_body_func, user_data);
} while (FindNextFile(finder, &data) != 0);
grn_ctx ctx;
grn_rc rc = grn_ctx_init(&ctx, 0);
if (rc == GRN_SUCCESS) {
do {
each_database_body(data.cFileName, &ctx, each_body_func, user_data);
} while (FindNextFile(finder, &data) != 0);
grn_ctx_fin(&ctx);
} else {
GRN_LOG(ctx_, GRN_LOG_WARNING,
"[mroonga][database][repairer][each] "
"failed to initialize grn_ctx: %d: %s",
rc, grn_rc_to_string(rc));
}
FindClose(finder);
#else
DIR *dir = opendir(base_directory_);
@ -91,8 +120,18 @@ namespace mrn {
DBUG_VOID_RETURN;
}
while (struct dirent *entry = readdir(dir)) {
each_database_body(entry->d_name, each_body_func, user_data);
grn_ctx ctx;
grn_rc rc = grn_ctx_init(&ctx, 0);
if (rc == GRN_SUCCESS) {
while (struct dirent *entry = readdir(dir)) {
each_database_body(entry->d_name, &ctx, each_body_func, user_data);
}
grn_ctx_fin(&ctx);
} else {
GRN_LOG(ctx_, GRN_LOG_WARNING,
"[mroonga][database][repairer][each] "
"failed to initialize grn_ctx: %d: %s",
rc, grn_rc_to_string(rc));
}
closedir(dir);
#endif
@ -101,6 +140,7 @@ namespace mrn {
}
void DatabaseRepairer::each_database_body(const char *base_path,
grn_ctx *ctx,
EachBodyFunc each_body_func,
void *user_data) {
MRN_DBUG_ENTER_METHOD();
@ -123,14 +163,14 @@ namespace mrn {
char db_path[MRN_MAX_PATH_SIZE];
snprintf(db_path, MRN_MAX_PATH_SIZE,
"%s%c%s", base_directory_, FN_LIBCHAR, base_path);
grn_obj *db = grn_db_open(ctx_, db_path);
grn_obj *db = grn_db_open(ctx, db_path);
if (!db) {
DBUG_VOID_RETURN;
}
(this->*each_body_func)(db, db_path, user_data);
(this->*each_body_func)(ctx, db, db_path, user_data);
grn_obj_close(ctx_, db);
grn_obj_close(ctx, db);
DBUG_VOID_RETURN;
}
@ -150,8 +190,7 @@ namespace mrn {
size_t raw_path_prefix_length = strlen(raw_path_prefix);
size_t separator_position = raw_path_prefix_length;
for (; separator_position > 0; separator_position--) {
if (base_directory_buffer_[separator_position] == FN_LIBCHAR ||
base_directory_buffer_[separator_position] == FN_LIBCHAR2) {
if (mrn_is_directory_separator(base_directory_buffer_[separator_position])) {
break;
}
}
@ -169,34 +208,46 @@ namespace mrn {
DBUG_VOID_RETURN;
}
void DatabaseRepairer::is_crashed_body(grn_obj *db,
const char *db_path,
void *user_data) {
void DatabaseRepairer::check_body(grn_ctx *ctx,
grn_obj *db,
const char *db_path,
void *user_data) {
MRN_DBUG_ENTER_METHOD();
bool *is_crashed = static_cast<bool *>(user_data);
CheckResult *result = static_cast<CheckResult *>(user_data);
if (grn_obj_is_locked(ctx_, db)) {
*is_crashed = true;
if (grn_obj_is_locked(ctx, db)) {
result->is_crashed = true;
result->is_corrupt = true;
DBUG_VOID_RETURN;
}
grn_table_cursor *cursor;
cursor = grn_table_cursor_open(ctx_, db,
cursor = grn_table_cursor_open(ctx, db,
NULL, 0,
NULL, 0,
0, -1, GRN_CURSOR_BY_ID);
if (!cursor) {
*is_crashed = true;
result->is_crashed = true;
result->is_corrupt = true;
DBUG_VOID_RETURN;
}
grn_id id;
while ((id = grn_table_cursor_next(ctx_, cursor)) != GRN_ID_NIL) {
grn_obj *object = grn_ctx_at(ctx_, id);
while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
if (grn_id_is_builtin(ctx, id)) {
continue;
}
grn_obj *object = grn_ctx_at(ctx, id);
if (!object) {
continue;
if (ctx->rc == GRN_SUCCESS) {
continue;
} else {
result->is_corrupt = true;
break;
}
}
switch (object->header.type) {
@ -207,37 +258,40 @@ namespace mrn {
case GRN_COLUMN_FIX_SIZE:
case GRN_COLUMN_VAR_SIZE:
case GRN_COLUMN_INDEX:
grn_obj_is_locked(ctx_, object);
*is_crashed = true;
if (grn_obj_is_locked(ctx_, object)) {
result->is_crashed = true;
result->is_corrupt = true;
}
break;
default:
break;
}
grn_obj_unlink(ctx_, object);
grn_obj_unlink(ctx, object);
if (*is_crashed) {
if (result->is_crashed || result->is_corrupt) {
break;
}
}
grn_table_cursor_close(ctx_, cursor);
grn_table_cursor_close(ctx, cursor);
DBUG_VOID_RETURN;
}
void DatabaseRepairer::repair_body(grn_obj *db,
void DatabaseRepairer::repair_body(grn_ctx *ctx,
grn_obj *db,
const char *db_path,
void *user_data) {
MRN_DBUG_ENTER_METHOD();
bool *succeeded = static_cast<bool *>(user_data);
if (grn_db_recover(ctx_, db) != GRN_SUCCESS) {
if (grn_db_recover(ctx, db) != GRN_SUCCESS) {
push_warning_printf(thd_,
MRN_SEVERITY_WARNING,
ER_NOT_KEYFILE,
"mroonga: repair: "
"Failed to recover database: <%s>: <%s>",
db_path, ctx_->errbuf);
db_path, ctx->errbuf);
*succeeded = false;
}

View File

@ -1,6 +1,6 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
Copyright(C) 2015-2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -28,6 +28,7 @@ namespace mrn {
DatabaseRepairer(grn_ctx *ctx, THD *thd);
~DatabaseRepairer(void);
bool is_crashed(void);
bool is_corrupt(void);
bool repair(void);
private:
@ -40,18 +41,26 @@ namespace mrn {
size_t path_prefix_length_;
size_t mrn_db_file_suffix_length_;
typedef void (DatabaseRepairer::*EachBodyFunc)(grn_obj *db,
typedef void (DatabaseRepairer::*EachBodyFunc)(grn_ctx *ctx,
grn_obj *db,
const char *db_path,
void *user_data);
void each_database(EachBodyFunc each_body_func, void *user_data);
void each_database_body(const char *base_path,
grn_ctx *ctx,
EachBodyFunc each_body_func,
void *user_data);
void detect_paths(void);
void is_crashed_body(grn_obj *db, const char *db_path, void *user_data);
void repair_body(grn_obj *db, const char *db_path, void *user_data);
void check_body(grn_ctx *ctx,
grn_obj *db,
const char *db_path,
void *user_data);
void repair_body(grn_ctx *ctx,
grn_obj *db,
const char *db_path,
void *user_data);
};
}

View File

@ -1,7 +1,7 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2011 Kentoku SHIBA
Copyright(C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -26,7 +26,8 @@
#define MRN_CLASS_NAME "mrn::IndexTableName"
namespace mrn {
const char *IndexTableName::SEPARATOR = "-";
const char *IndexTableName::SEPARATOR = "#";
const char *IndexTableName::OLD_SEPARATOR = "-";
bool IndexTableName::is_custom_name(const char *table_name,
size_t table_name_length,
@ -43,9 +44,12 @@ namespace mrn {
DBUG_RETURN(true);
}
if (strncmp(SEPARATOR,
index_table_name + table_name_length,
strlen(SEPARATOR)) != 0) {
if ((strncmp(OLD_SEPARATOR,
index_table_name + table_name_length,
strlen(OLD_SEPARATOR)) != 0) &&
(strncmp(SEPARATOR,
index_table_name + table_name_length,
strlen(SEPARATOR)) != 0)) {
DBUG_RETURN(true);
}
@ -63,6 +67,12 @@ namespace mrn {
encoded_mysql_index_name_multibyte + MRN_MAX_KEY_SIZE,
mysql_index_name_multibyte,
mysql_index_name_multibyte + strlen(mysql_index_name_));
snprintf(old_name_, MRN_MAX_KEY_SIZE,
"%s%s%s",
table_name_,
OLD_SEPARATOR,
encoded_mysql_index_name_multibyte);
old_length_ = strlen(old_name_);
snprintf(name_, MRN_MAX_KEY_SIZE,
"%s%s%s",
table_name_,
@ -79,6 +89,14 @@ namespace mrn {
return length_;
}
const char *IndexTableName::old_c_str() {
return old_name_;
}
size_t IndexTableName::old_length() {
return old_length_;
}
uint IndexTableName::encode(uchar *encoded_start,
uchar *encoded_end,
const uchar *mysql_string_start,

View File

@ -1,7 +1,7 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2011 Kentoku SHIBA
Copyright(C) 2011-2012 Kouhei Sutou <kou@clear-code.com>
Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@ -27,6 +27,7 @@ namespace mrn {
class IndexTableName {
public:
static const char *SEPARATOR;
static const char *OLD_SEPARATOR;
static bool is_custom_name(const char *table_name,
size_t table_name_length,
@ -36,9 +37,13 @@ namespace mrn {
IndexTableName(const char *table_name, const char *mysql_index_name);
const char *c_str();
size_t length();
const char *old_c_str();
size_t old_length();
private:
const char *table_name_;
const char *mysql_index_name_;
char old_name_[MRN_MAX_KEY_SIZE];
size_t old_length_;
char name_[MRN_MAX_KEY_SIZE];
size_t length_;

View File

@ -288,6 +288,7 @@ namespace mrn {
decode_long_long_int(current_grn_key, &grn_time);
TimeConverter time_converter;
MYSQL_TIME mysql_time;
mysql_time.neg = FALSE;
mysql_time.time_type = MYSQL_TIMESTAMP_DATETIME;
time_converter.grn_time_to_mysql_time(grn_time, &mysql_time);
long long int mysql_datetime_packed =
@ -518,6 +519,14 @@ namespace mrn {
*data_type = TYPE_BYTE_SEQUENCE;
*data_size = key_part->length;
break;
#ifdef MRN_HAVE_MYSQL_TYPE_JSON
case MYSQL_TYPE_JSON:
// TODO
DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_JSON"));
*data_type = TYPE_BYTE_SEQUENCE;
*data_size = key_part->length;
break;
#endif
}
DBUG_VOID_RETURN;
}

View File

@ -20,11 +20,11 @@
#ifndef MRN_MULTIPLE_COLUMN_KEY_CODEC_HPP_
#define MRN_MULTIPLE_COLUMN_KEY_CODEC_HPP_
#include <groonga.h>
#include <mrn_mysql.h>
#include <mrn_mysql_compat.h>
#include <groonga.h>
namespace mrn {
class MultipleColumnKeyCodec {
public:

View File

@ -0,0 +1,51 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <mrn_mysql.h>
#include "mrn_operation.hpp"
// for debug
#define MRN_CLASS_NAME "mrn::Operation"
namespace mrn {
Operation::Operation(mrn::Operations *operations,
const char *type,
const char *table_name,
size_t table_name_size)
: operations_(operations),
id_(operations_->start(type, table_name, table_name_size)) {
}
Operation::~Operation() {
MRN_DBUG_ENTER_METHOD();
operations_->finish(id_);
DBUG_VOID_RETURN;
}
void Operation::record_target(grn_id record_id) {
MRN_DBUG_ENTER_METHOD();
operations_->record_target(id_, record_id);
DBUG_VOID_RETURN;
}
}

View File

@ -0,0 +1,42 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MRN_OPERATION_HPP_
#define MRN_OPERATION_HPP_
#include <mrn_operations.hpp>
namespace mrn {
class Operation {
public:
Operation(mrn::Operations *operations,
const char *type,
const char *table_name,
size_t table_name_size);
~Operation();
void record_target(grn_id record_id);
private:
mrn::Operations *operations_;
grn_id id_;
};
}
#endif /* MRN_OPERATION_HPP_ */

View File

@ -0,0 +1,401 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <mrn_mysql.h>
#include <string.h>
#include "mrn_operations.hpp"
// for debug
#define MRN_CLASS_NAME "mrn::Operations"
#define TABLE_NAME "mroonga_operations"
#define COLUMN_TYPE_NAME "type"
#define COLUMN_TABLE_NAME "table"
#define COLUMN_RECORD_NAME "record"
namespace mrn {
Operations::Operations(grn_ctx *ctx)
: ctx_(ctx) {
MRN_DBUG_ENTER_METHOD();
GRN_TEXT_INIT(&text_buffer_, GRN_OBJ_DO_SHALLOW_COPY);
GRN_UINT32_INIT(&id_buffer_, 0);
table_ = grn_ctx_get(ctx_, TABLE_NAME, -1);
if (!table_) {
table_ = grn_table_create(ctx_,
TABLE_NAME, strlen(TABLE_NAME),
NULL,
GRN_OBJ_TABLE_NO_KEY | GRN_OBJ_PERSISTENT,
NULL, NULL);
columns_.type_ =
grn_column_create(ctx_, table_,
COLUMN_TYPE_NAME, strlen(COLUMN_TYPE_NAME),
NULL,
GRN_OBJ_COLUMN_SCALAR | GRN_OBJ_PERSISTENT,
grn_ctx_at(ctx_, GRN_DB_SHORT_TEXT));
columns_.table_ =
grn_column_create(ctx_, table_,
COLUMN_TABLE_NAME, strlen(COLUMN_TABLE_NAME),
NULL,
GRN_OBJ_COLUMN_SCALAR | GRN_OBJ_PERSISTENT,
grn_ctx_at(ctx_, GRN_DB_SHORT_TEXT));
columns_.record_ =
grn_column_create(ctx_, table_,
COLUMN_RECORD_NAME, strlen(COLUMN_RECORD_NAME),
NULL,
GRN_OBJ_COLUMN_SCALAR | GRN_OBJ_PERSISTENT,
grn_ctx_at(ctx_, GRN_DB_UINT32));
} else {
columns_.type_ = grn_ctx_get(ctx_, TABLE_NAME "." COLUMN_TYPE_NAME, -1);
columns_.table_ = grn_ctx_get(ctx_, TABLE_NAME "." COLUMN_TABLE_NAME, -1);
columns_.record_ = grn_ctx_get(ctx_, TABLE_NAME "." COLUMN_RECORD_NAME, -1);
}
is_enabled_recording_ = true;
DBUG_VOID_RETURN;
}
Operations::~Operations() {
MRN_DBUG_ENTER_METHOD();
GRN_OBJ_FIN(ctx_, &id_buffer_);
GRN_OBJ_FIN(ctx_, &text_buffer_);
DBUG_VOID_RETURN;
}
bool Operations::is_locked() {
MRN_DBUG_ENTER_METHOD();
if (grn_obj_is_locked(ctx_, table_) > 0)
DBUG_RETURN(true);
if (grn_obj_is_locked(ctx_, columns_.type_) > 0)
DBUG_RETURN(true);
if (grn_obj_is_locked(ctx_, columns_.table_) > 0)
DBUG_RETURN(true);
if (grn_obj_is_locked(ctx_, columns_.record_) > 0)
DBUG_RETURN(true);
DBUG_RETURN(false);
}
grn_id Operations::start(const char *type,
const char *table_name, size_t table_name_size) {
MRN_DBUG_ENTER_METHOD();
if (!is_enabled_recording_) {
DBUG_RETURN(GRN_ID_NIL);
}
grn_id id = grn_table_add(ctx_, table_, NULL, 0, NULL);
GRN_TEXT_SETS(ctx_, &text_buffer_, type);
grn_obj_set_value(ctx_, columns_.type_, id, &text_buffer_, GRN_OBJ_SET);
GRN_TEXT_SET(ctx_, &text_buffer_, table_name, table_name_size);
grn_obj_set_value(ctx_, columns_.table_, id, &text_buffer_, GRN_OBJ_SET);
DBUG_RETURN(id);
}
void Operations::record_target(grn_id id, grn_id record_id) {
MRN_DBUG_ENTER_METHOD();
if (!is_enabled_recording_) {
DBUG_VOID_RETURN;
}
GRN_UINT32_SET(ctx_, &id_buffer_, record_id);
grn_obj_set_value(ctx_, columns_.record_, id, &id_buffer_, GRN_OBJ_SET);
DBUG_VOID_RETURN;
}
void Operations::finish(grn_id id) {
MRN_DBUG_ENTER_METHOD();
if (!is_enabled_recording_) {
DBUG_VOID_RETURN;
}
grn_table_delete_by_id(ctx_, table_, id);
DBUG_VOID_RETURN;
}
void Operations::enable_recording() {
MRN_DBUG_ENTER_METHOD();
is_enabled_recording_ = true;
DBUG_VOID_RETURN;
}
void Operations::disable_recording() {
MRN_DBUG_ENTER_METHOD();
is_enabled_recording_ = false;
DBUG_VOID_RETURN;
}
grn_hash *Operations::collect_processing_table_names() {
MRN_DBUG_ENTER_METHOD();
grn_hash *table_names =
grn_hash_create(ctx_, NULL, GRN_TABLE_MAX_KEY_SIZE, 0,
GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_KEY_VAR_SIZE);
grn_table_cursor *cursor;
cursor = grn_table_cursor_open(ctx_, table_, NULL, 0, NULL, 0, 0, -1, 0);
if (!cursor) {
GRN_LOG(ctx_, GRN_LOG_NOTICE,
"[operations] failed to open cursor: %s",
ctx_->errbuf);
DBUG_RETURN(table_names);
}
grn_id id;
while ((id = grn_table_cursor_next(ctx_, cursor))) {
GRN_BULK_REWIND(&text_buffer_);
grn_obj_get_value(ctx_, columns_.table_, id, &text_buffer_);
if (GRN_TEXT_LEN(&text_buffer_) > 0) {
grn_hash_add(ctx_, table_names,
GRN_TEXT_VALUE(&text_buffer_),
GRN_TEXT_LEN(&text_buffer_),
NULL,
NULL);
}
}
grn_table_cursor_close(ctx_, cursor);
DBUG_RETURN(table_names);
}
int Operations::repair(const char *table_name, size_t table_name_size) {
MRN_DBUG_ENTER_METHOD();
int error = 0;
grn_table_cursor *cursor;
cursor = grn_table_cursor_open(ctx_, table_, NULL, 0, NULL, 0, 0, -1, 0);
if (!cursor) {
error = HA_ERR_CRASHED_ON_USAGE;
if (ctx_->rc) {
my_message(error, ctx_->errbuf, MYF(0));
} else {
my_message(error,
"mroonga: repair: "
"failed to open cursor for operations table",
MYF(0));
}
DBUG_RETURN(error);
}
grn_obj *target_table = grn_ctx_get(ctx_, table_name, table_name_size);
if (!target_table) {
GRN_LOG(ctx_, GRN_LOG_WARNING,
"table doesn't exist for auto repair: <%.*s>",
static_cast<int>(table_name_size), table_name);
}
grn_id id;
while ((id = grn_table_cursor_next(ctx_, cursor))) {
GRN_BULK_REWIND(&text_buffer_);
grn_obj_get_value(ctx_, columns_.table_, id, &text_buffer_);
if (!((static_cast<size_t>(GRN_TEXT_LEN(&text_buffer_)) ==
table_name_size) &&
memcmp(GRN_TEXT_VALUE(&text_buffer_),
table_name,
table_name_size) == 0)) {
continue;
}
if (!target_table) {
grn_rc rc = grn_table_cursor_delete(ctx_, cursor);
if (rc != GRN_SUCCESS) {
GRN_BULK_REWIND(&text_buffer_);
grn_obj_get_value(ctx_, columns_.type_, id, &text_buffer_);
GRN_TEXT_PUTC(ctx_, &text_buffer_, '\0');
char error_message[MRN_MESSAGE_BUFFER_SIZE];
snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
"mroonga: repair: failed to delete an orphan operation: "
"[%u]: <%.*s>[%s]: <%s>(%d)",
id,
static_cast<int>(table_name_size), table_name,
GRN_TEXT_VALUE(&text_buffer_),
ctx_->errbuf,
rc);
my_message(error, error_message, MYF(0));
break;
}
continue;
}
GRN_BULK_REWIND(&id_buffer_);
grn_obj_get_value(ctx_, columns_.record_, id, &id_buffer_);
grn_id record_id = GRN_UINT32_VALUE(&id_buffer_);
if (record_id == GRN_ID_NIL) {
grn_rc rc = grn_table_cursor_delete(ctx_, cursor);
if (rc != GRN_SUCCESS) {
GRN_BULK_REWIND(&text_buffer_);
grn_obj_get_value(ctx_, columns_.type_, id, &text_buffer_);
GRN_TEXT_PUTC(ctx_, &text_buffer_, '\0');
char error_message[MRN_MESSAGE_BUFFER_SIZE];
snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
"mroonga: repair: "
"failed to delete an operation that has no related record: "
"[%u]: <%.*s>[%s]: <%s>(%d)",
id,
static_cast<int>(table_name_size), table_name,
GRN_TEXT_VALUE(&text_buffer_),
ctx_->errbuf,
rc);
my_message(error, error_message, MYF(0));
break;
}
continue;
}
GRN_BULK_REWIND(&text_buffer_);
grn_obj_get_value(ctx_, columns_.type_, id, &text_buffer_);
GRN_TEXT_PUTC(ctx_, &text_buffer_, '\0');
if (strcmp(GRN_TEXT_VALUE(&text_buffer_), "write") == 0 ||
strcmp(GRN_TEXT_VALUE(&text_buffer_), "delete") == 0) {
grn_rc rc = grn_table_delete_by_id(ctx_, target_table, record_id);
if (rc != GRN_SUCCESS) {
error = HA_ERR_CRASHED_ON_USAGE;
char error_message[MRN_MESSAGE_BUFFER_SIZE];
snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
"mroonga: repair: failed to delete an incomplete record: "
"[%u]: <%.*s>[%u]: <%s>(%d)",
id,
static_cast<int>(table_name_size), table_name,
record_id,
ctx_->errbuf,
rc);
my_message(error, error_message, MYF(0));
break;
}
rc = grn_table_cursor_delete(ctx_, cursor);
if (rc != GRN_SUCCESS) {
error = HA_ERR_CRASHED_ON_USAGE;
char error_message[MRN_MESSAGE_BUFFER_SIZE];
snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
"mroonga: repair: failed to delete an incomplete operation: "
"[%u]: <%.*s>[%u][%s]: <%s>(%d)",
id,
static_cast<int>(table_name_size), table_name,
record_id,
GRN_TEXT_VALUE(&text_buffer_),
ctx_->errbuf,
rc);
my_message(error, error_message, MYF(0));
break;
}
} else if (strcmp(GRN_TEXT_VALUE(&text_buffer_), "update") == 0) {
error = HA_ERR_CRASHED_ON_USAGE;
my_message(error,
"mroonga: repair: can't recover from crash while updating",
MYF(0));
break;
} else {
error = HA_ERR_CRASHED_ON_USAGE;
char error_message[MRN_MESSAGE_BUFFER_SIZE];
snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
"mroonga: repair: unknown operation type: "
"[%u]: <%.*s>[%u]: <%s>",
id,
static_cast<int>(table_name_size), table_name,
record_id,
GRN_TEXT_VALUE(&text_buffer_));
my_message(error, error_message, MYF(0));
break;
}
}
grn_table_cursor_close(ctx_, cursor);
DBUG_RETURN(error);
}
int Operations::clear(const char *table_name, size_t table_name_size) {
MRN_DBUG_ENTER_METHOD();
int error = 0;
grn_table_cursor *cursor;
cursor = grn_table_cursor_open(ctx_, table_, NULL, 0, NULL, 0, 0, -1, 0);
if (!cursor) {
error = HA_ERR_CRASHED_ON_USAGE;
if (ctx_->rc) {
my_message(error, ctx_->errbuf, MYF(0));
} else {
my_message(error,
"mroonga: clear: "
"failed to open cursor for operations table",
MYF(0));
}
DBUG_RETURN(error);
}
grn_id id;
while ((id = grn_table_cursor_next(ctx_, cursor))) {
GRN_BULK_REWIND(&text_buffer_);
grn_obj_get_value(ctx_, columns_.table_, id, &text_buffer_);
if ((static_cast<size_t>(GRN_TEXT_LEN(&text_buffer_)) ==
table_name_size) &&
memcmp(GRN_TEXT_VALUE(&text_buffer_),
table_name,
table_name_size) == 0) {
grn_rc rc = grn_table_cursor_delete(ctx_, cursor);
if (rc != GRN_SUCCESS) {
error = HA_ERR_CRASHED_ON_USAGE;
GRN_BULK_REWIND(&id_buffer_);
grn_obj_get_value(ctx_, columns_.record_, id, &id_buffer_);
GRN_BULK_REWIND(&text_buffer_);
grn_obj_get_value(ctx_, columns_.type_, id, &text_buffer_);
GRN_TEXT_PUTC(ctx_, &text_buffer_, '\0');
char error_message[MRN_MESSAGE_BUFFER_SIZE];
snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
"mroonga: clear: failed to delete an operation: "
"[%u]: <%.*s>[%u][%s]: <%s>(%d)",
id,
static_cast<int>(table_name_size), table_name,
GRN_UINT32_VALUE(&id_buffer_),
GRN_TEXT_VALUE(&text_buffer_),
ctx_->errbuf,
rc);
my_message(error, error_message, MYF(0));
break;
}
}
}
grn_table_cursor_close(ctx_, cursor);
DBUG_RETURN(error);
}
}

View File

@ -0,0 +1,60 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MRN_OPERATIONS_HPP_
#define MRN_OPERATIONS_HPP_
#include <groonga.h>
namespace mrn {
class Operations {
public:
Operations(grn_ctx *ctx);
~Operations();
bool is_locked();
grn_id start(const char *type,
const char *table_name, size_t table_name_size);
void record_target(grn_id id, grn_id target_id);
void finish(grn_id id);
void enable_recording();
void disable_recording();
grn_hash *collect_processing_table_names();
int repair(const char *table_name, size_t table_name_size);
int clear(const char *table_name, size_t table_name_size);
private:
grn_ctx *ctx_;
grn_obj text_buffer_;
grn_obj id_buffer_;
grn_obj *table_;
struct {
grn_obj *type_;
grn_obj *table_;
grn_obj *record_;
} columns_;
bool is_enabled_recording_;
};
}
#endif /* MRN_OPERATIONS_HPP_ */

View File

@ -222,4 +222,8 @@ namespace mrn {
mysql_path_[i] = '\0';
return mysql_path_;
}
bool PathMapper::is_internal_table_name() {
return mysql_table_name()[0] == '#';
}
}

View File

@ -38,6 +38,8 @@ namespace mrn {
const char *table_name();
const char *mysql_table_name();
const char *mysql_path();
bool is_internal_table_name();
bool is_temporary_table_name();
private:
const char *original_mysql_path_;
const char *path_prefix_;

View File

@ -0,0 +1,361 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mrn_query_parser.hpp"
#include <mrn_variables.hpp>
extern "C" {
/* Groonga's internal functions */
int grn_atoi(const char *nptr, const char *end, const char **rest);
uint grn_atoui(const char *nptr, const char *end, const char **rest);
}
#define MRN_CLASS_NAME "mrn::QueryParser"
namespace mrn {
QueryParser::QueryParser(grn_ctx *ctx,
THD *thd,
grn_obj *expression,
grn_obj *default_column,
uint n_sections,
grn_obj *match_columns)
: ctx_(ctx),
thd_(thd),
expression_(expression),
default_column_(default_column),
n_sections_(n_sections),
match_columns_(match_columns) {
}
QueryParser::~QueryParser() {
}
grn_rc QueryParser::parse(const char *query, size_t query_length) {
MRN_DBUG_ENTER_METHOD();
const char *raw_query = NULL;
size_t raw_query_length = 0;
grn_operator default_operator = GRN_OP_OR;
grn_expr_flags expression_flags = 0;
parse_pragma(query,
query_length,
&raw_query,
&raw_query_length,
&default_operator,
&expression_flags);
grn_obj *default_column = default_column_;
if (match_columns_) {
default_column = match_columns_;
}
grn_rc rc = grn_expr_parse(ctx_,
expression_,
raw_query,
raw_query_length,
default_column,
GRN_OP_MATCH,
default_operator,
expression_flags);
if (rc != GRN_SUCCESS) {
char error_message[MRN_MESSAGE_BUFFER_SIZE];
snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
"failed to parse fulltext search keyword: <%.*s>: <%s>",
static_cast<int>(query_length),
query,
ctx_->errbuf);
variables::ActionOnError action =
variables::get_action_on_fulltext_query_error(thd_);
switch (action) {
case variables::ACTION_ON_ERROR_ERROR:
my_message(ER_PARSE_ERROR, error_message, MYF(0));
break;
case variables::ACTION_ON_ERROR_ERROR_AND_LOG:
my_message(ER_PARSE_ERROR, error_message, MYF(0));
GRN_LOG(ctx_, GRN_LOG_ERROR, "%s", error_message);
break;
case variables::ACTION_ON_ERROR_IGNORE:
break;
case variables::ACTION_ON_ERROR_IGNORE_AND_LOG:
GRN_LOG(ctx_, GRN_LOG_ERROR, "%s", error_message);
break;
}
}
DBUG_RETURN(rc);
}
void QueryParser::parse_pragma(const char *query,
size_t query_length,
const char **raw_query,
size_t *raw_query_length,
grn_operator *default_operator,
grn_expr_flags *flags) {
MRN_DBUG_ENTER_METHOD();
const char *current_query = query;
size_t current_query_length = query_length;
*default_operator = GRN_OP_OR;
if (current_query_length >= 4 && memcmp(current_query, "*SS ", 4) == 0) {
*raw_query = current_query + 4;
*raw_query_length = current_query_length - 4;
*flags = GRN_EXPR_SYNTAX_SCRIPT;
DBUG_VOID_RETURN;
}
bool weight_specified = false;
*raw_query = query;
*raw_query_length = query_length;
*flags = default_expression_flags();
if (current_query_length >= 2 && current_query[0] == '*') {
bool parsed = false;
bool done = false;
current_query++;
current_query_length--;
while (!done) {
size_t consumed_query_length = 0;
switch (current_query[0]) {
case 'D':
if (parse_pragma_d(current_query + 1,
current_query_length - 1,
default_operator,
&consumed_query_length)) {
parsed = true;
consumed_query_length += 1;
current_query += consumed_query_length;
current_query_length -= consumed_query_length;
} else {
done = true;
}
break;
case 'W':
if (parse_pragma_w(current_query + 1,
current_query_length - 1,
&consumed_query_length)) {
parsed = true;
weight_specified = true;
consumed_query_length += 1;
current_query += consumed_query_length;
current_query_length -= consumed_query_length;
} else {
done = true;
}
break;
default:
done = true;
break;
}
}
if (parsed) {
*raw_query = current_query;
*raw_query_length = current_query_length;
}
}
// WORKAROUND: ignore the first '+' to support "+apple macintosh" pattern.
while (*raw_query_length > 0 && (*raw_query)[0] == ' ') {
(*raw_query)++;
(*raw_query_length)--;
}
if (*raw_query_length > 0 && (*raw_query)[0] == '+') {
(*raw_query)++;
(*raw_query_length)--;
}
if (!weight_specified && match_columns_) {
grn_expr_append_obj(ctx_, match_columns_, default_column_, GRN_OP_PUSH, 1);
}
DBUG_VOID_RETURN;
}
bool QueryParser::parse_pragma_w(const char *query,
size_t query_length,
size_t *consumed_query_length) {
MRN_DBUG_ENTER_METHOD();
*consumed_query_length = 0;
grn_obj section_value_buffer;
GRN_UINT32_INIT(&section_value_buffer, 0);
MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(bool, specified_sections, n_sections_);
for (uint i = 0; i < n_sections_; ++i) {
specified_sections[i] = false;
}
uint n_weights = 0;
while (query_length >= 1) {
if (n_weights >= 1) {
if (query[0] != ',') {
break;
}
size_t n_used_query_length = 1;
*consumed_query_length += n_used_query_length;
query_length -= n_used_query_length;
query += n_used_query_length;
if (query_length == 0) {
break;
}
}
uint section = 0;
if ('1' <= query[0] && query[0] <= '9') {
const char *section_start = query;
const char *query_end = query + query_length;
const char *query_rest;
section = grn_atoui(section_start, query_end, &query_rest);
if (section_start == query_rest) {
break;
}
if (!(0 < section && section <= n_sections_)) {
break;
}
section -= 1;
specified_sections[section] = true;
size_t n_used_query_length = query_rest - query;
*consumed_query_length += n_used_query_length;
query_length -= n_used_query_length;
query += n_used_query_length;
} else {
break;
}
int weight = 1;
if (query_length >= 2 && query[0] == ':') {
const char *weight_start = query + 1;
const char *query_end = query + query_length;
const char *query_rest;
weight = grn_atoi(weight_start, query_end, &query_rest);
if (weight_start == query_rest) {
break;
}
size_t n_used_query_length = query_rest - query;
*consumed_query_length += n_used_query_length;
query_length -= n_used_query_length;
query += n_used_query_length;
}
n_weights++;
append_section(section,
&section_value_buffer,
weight,
n_weights);
}
for (uint section = 0; section < n_sections_; ++section) {
if (specified_sections[section]) {
continue;
}
++n_weights;
int default_weight = 1;
append_section(section,
&section_value_buffer,
default_weight,
n_weights);
}
MRN_FREE_VARIABLE_LENGTH_ARRAYS(specified_sections);
GRN_OBJ_FIN(ctx_, &section_value_buffer);
DBUG_RETURN(n_weights > 0);
}
void QueryParser::append_section(uint section,
grn_obj *section_value_buffer,
int weight,
uint n_weights) {
MRN_DBUG_ENTER_METHOD();
if (!match_columns_) {
DBUG_VOID_RETURN;
}
grn_expr_append_obj(ctx_, match_columns_, default_column_, GRN_OP_PUSH, 1);
GRN_UINT32_SET(ctx_, section_value_buffer, section);
grn_expr_append_const(ctx_, match_columns_, section_value_buffer,
GRN_OP_PUSH, 1);
grn_expr_append_op(ctx_, match_columns_, GRN_OP_GET_MEMBER, 2);
if (weight != 1) {
grn_expr_append_const_int(ctx_, match_columns_, weight, GRN_OP_PUSH, 1);
grn_expr_append_op(ctx_, match_columns_, GRN_OP_STAR, 2);
}
if (n_weights >= 2) {
grn_expr_append_op(ctx_, match_columns_, GRN_OP_OR, 2);
}
DBUG_VOID_RETURN;
}
bool QueryParser::parse_pragma_d(const char *query,
size_t query_length,
grn_operator *default_operator,
size_t *consumed_query_length) {
MRN_DBUG_ENTER_METHOD();
bool succeeded = true;
if (query_length >= 1 && query[0] == '+') {
*default_operator = GRN_OP_AND;
*consumed_query_length = 1;
} else if (query_length >= 1 && query[0] == '-') {
*default_operator = GRN_OP_AND_NOT;
*consumed_query_length = 1;
} else if (query_length >= 2 && memcmp(query, "OR", 2) == 0) {
*default_operator = GRN_OP_OR;
*consumed_query_length = 2;
} else {
succeeded = false;
}
DBUG_RETURN(succeeded);
}
grn_expr_flags QueryParser::default_expression_flags() {
MRN_DBUG_ENTER_METHOD();
ulonglong syntax_flags = variables::get_boolean_mode_syntax_flags(thd_);
grn_expr_flags expression_flags = 0;
if (syntax_flags == variables::BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT) {
expression_flags = GRN_EXPR_SYNTAX_QUERY | GRN_EXPR_ALLOW_LEADING_NOT;
} else {
if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_SYNTAX_SCRIPT) {
expression_flags |= GRN_EXPR_SYNTAX_SCRIPT;
} else {
expression_flags |= GRN_EXPR_SYNTAX_QUERY;
}
if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_COLUMN) {
expression_flags |= GRN_EXPR_ALLOW_COLUMN;
}
if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_UPDATE) {
expression_flags |= GRN_EXPR_ALLOW_UPDATE;
}
if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_LEADING_NOT) {
expression_flags |= GRN_EXPR_ALLOW_LEADING_NOT;
}
}
DBUG_RETURN(expression_flags);
}
}

View File

@ -0,0 +1,67 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <mrn_mysql.h>
#include <mrn_mysql_compat.h>
#include <groonga.h>
namespace mrn {
class QueryParser {
public:
QueryParser(grn_ctx *ctx,
THD *thd,
grn_obj *expression,
grn_obj *default_column,
uint n_sections,
grn_obj *match_columns=NULL);
~QueryParser();
grn_rc parse(const char *query, size_t query_length);
void parse_pragma(const char *query,
size_t query_length,
const char **raw_query,
size_t *raw_query_length,
grn_operator *default_operator,
grn_expr_flags *flags);
private:
grn_ctx *ctx_;
THD *thd_;
grn_obj *expression_;
grn_obj *default_column_;
uint n_sections_;
grn_obj *match_columns_;
bool parse_pragma_w(const char *query,
size_t query_length,
size_t *consumed_query_length);
void append_section(uint section,
grn_obj *section_value_buffer,
int weight,
uint n_weights);
bool parse_pragma_d(const char *query,
size_t query_length,
grn_operator *default_operator,
size_t *consumed_query_length);
grn_expr_flags default_expression_flags();
};
}

View File

@ -0,0 +1,42 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mrn_smart_bitmap.hpp"
namespace mrn {
SmartBitmap::SmartBitmap(MY_BITMAP *bitmap)
: bitmap_(bitmap) {
}
SmartBitmap::~SmartBitmap() {
if (bitmap_) {
bitmap_free(bitmap_);
}
}
MY_BITMAP *SmartBitmap::get() {
return bitmap_;
}
MY_BITMAP *SmartBitmap::release() {
MY_BITMAP *bitmap = bitmap_;
bitmap_ = NULL;
return bitmap;
}
}

View File

@ -0,0 +1,36 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <mrn_mysql.h>
#include <my_bitmap.h>
namespace mrn {
class SmartBitmap {
public:
SmartBitmap(MY_BITMAP *bitmap);
~SmartBitmap();
MY_BITMAP *get();
MY_BITMAP *release();
private:
MY_BITMAP *bitmap_;
};
}

View File

@ -0,0 +1,41 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "mrn_table_fields_offset_mover.hpp"
namespace mrn {
TableFieldsOffsetMover::TableFieldsOffsetMover(TABLE *table,
my_ptrdiff_t diff)
: table_(table),
diff_(diff) {
uint n_columns = table_->s->fields;
for (uint i = 0; i < n_columns; ++i) {
Field *field = table_->field[i];
field->move_field_offset(diff_);
}
}
TableFieldsOffsetMover::~TableFieldsOffsetMover() {
uint n_columns = table_->s->fields;
for (uint i = 0; i < n_columns; ++i) {
Field *field = table_->field[i];
field->move_field_offset(-diff_);
}
}
}

View File

@ -0,0 +1,33 @@
/* -*- c-basic-offset: 2 -*- */
/*
Copyright(C) 2017 Kouhei Sutou <kou@clear-code.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <mrn_mysql.h>
namespace mrn {
class TableFieldsOffsetMover {
public:
TableFieldsOffsetMover(TABLE *table, my_ptrdiff_t diff);
~TableFieldsOffsetMover();
private:
TABLE *table_;
my_ptrdiff_t diff_;
};
}

View File

@ -39,5 +39,8 @@
#define ER_MRN_INVALID_INDEX_FLAG_NUM 16508
#define ER_MRN_INVALID_INDEX_FLAG_STR \
"The index flag '%-.64s' is invalid. It is ignored"
#define ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_NUM 16509
#define ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_STR \
"Index for virtual generated column is not supported: %s"
#endif /* MRN_ERR_H_ */

Some files were not shown because too many files have changed in this diff Show More