1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-08 11:22:35 +03:00

Merge tag 'mariadb-10.0.17' into 10.0-galera

Conflicts:
	storage/innobase/include/trx0trx.h
This commit is contained in:
Nirbhay Choubey
2015-02-27 17:36:54 -05:00
584 changed files with 50432 additions and 8938 deletions

View File

@@ -49,6 +49,8 @@
#include "mysqld.h" #include "mysqld.h"
#include <algorithm>
Rpl_filter *binlog_filter= 0; Rpl_filter *binlog_filter= 0;
#define BIN_LOG_HEADER_SIZE 4 #define BIN_LOG_HEADER_SIZE 4
@@ -67,6 +69,7 @@ ulong server_id = 0;
ulong bytes_sent = 0L, bytes_received = 0L; ulong bytes_sent = 0L, bytes_received = 0L;
ulong mysqld_net_retry_count = 10L; ulong mysqld_net_retry_count = 10L;
ulong open_files_limit; ulong open_files_limit;
ulong opt_binlog_rows_event_max_size;
uint test_flags = 0; uint test_flags = 0;
static uint opt_protocol= 0; static uint opt_protocol= 0;
static FILE *result_file; static FILE *result_file;
@@ -1436,6 +1439,12 @@ that may lead to an endless loop.",
"Used to reserve file descriptors for use by this program.", "Used to reserve file descriptors for use by this program.",
&open_files_limit, &open_files_limit, 0, GET_ULONG, &open_files_limit, &open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0}, REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
{"binlog-row-event-max-size", 0,
"The maximum size of a row-based binary log event in bytes. Rows will be "
"grouped into events smaller than this size if possible. "
"This value must be a multiple of 256.",
&opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size, 0,
GET_ULONG, REQUIRED_ARG, UINT_MAX, 256, ULONG_MAX, 0, 256, 0},
{"verify-binlog-checksum", 'c', "Verify checksum binlog events.", {"verify-binlog-checksum", 'c', "Verify checksum binlog events.",
(uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},

View File

@@ -35,7 +35,7 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
ENDIF() ENDIF()
# Turn on Werror (warning => error) when using maintainer mode. # Turn on Werror (warning => error) when using maintainer mode.
IF(MYSQL_MAINTAINER_MODE MATCHES "ON") IF(MYSQL_MAINTAINER_MODE MATCHES "ERR")
SET(MY_C_WARNING_FLAGS "${MY_C_WARNING_FLAGS} -DFORCE_INIT_OF_VARS -Werror") SET(MY_C_WARNING_FLAGS "${MY_C_WARNING_FLAGS} -DFORCE_INIT_OF_VARS -Werror")
SET(MY_CXX_WARNING_FLAGS "${MY_CXX_WARNING_FLAGS} -DFORCE_INIT_OF_VARS -Werror") SET(MY_CXX_WARNING_FLAGS "${MY_CXX_WARNING_FLAGS} -DFORCE_INIT_OF_VARS -Werror")
ENDIF() ENDIF()

View File

@@ -156,37 +156,37 @@ MACRO (MYSQL_CHECK_SSL)
LIST(REVERSE CMAKE_FIND_LIBRARY_SUFFIXES) LIST(REVERSE CMAKE_FIND_LIBRARY_SUFFIXES)
ENDIF() ENDIF()
# Verify version number. Version information looks like:
# #define OPENSSL_VERSION_NUMBER 0x1000103fL
# Encoded as MNNFFPPS: major minor fix patch status
FILE(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h"
OPENSSL_VERSION_NUMBER
REGEX "^#define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x[0-9].*"
)
STRING(REGEX REPLACE
"^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9]).*$" "\\1"
OPENSSL_MAJOR_VERSION "${OPENSSL_VERSION_NUMBER}"
)
IF(OPENSSL_INCLUDE_DIR AND IF(OPENSSL_INCLUDE_DIR AND
OPENSSL_LIBRARIES AND OPENSSL_LIBRARIES AND
CRYPTO_LIBRARY CRYPTO_LIBRARY
) )
# Verify version number. Version information looks like:
# #define OPENSSL_VERSION_NUMBER 0x1000103fL
# Encoded as MNNFFPPS: major minor fix patch status
FILE(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h"
OPENSSL_VERSION_NUMBER
REGEX "^#define[\t ]+OPENSSL_VERSION_NUMBER[\t ]+0x[0-9].*"
)
STRING(REGEX REPLACE
"^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9]).*$" "\\1"
OPENSSL_MAJOR_VERSION "${OPENSSL_VERSION_NUMBER}"
)
INCLUDE(CheckSymbolExists)
SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
CHECK_SYMBOL_EXISTS(SHA512_DIGEST_LENGTH "openssl/sha.h"
HAVE_SHA512_DIGEST_LENGTH)
SET(OPENSSL_FOUND TRUE) SET(OPENSSL_FOUND TRUE)
ELSE() ELSE()
SET(OPENSSL_FOUND FALSE) SET(OPENSSL_FOUND FALSE)
ENDIF() ENDIF()
MESSAGE(STATUS "OPENSSL_INCLUDE_DIR = ${OPENSSL_INCLUDE_DIR}")
MESSAGE(STATUS "OPENSSL_LIBRARIES = ${OPENSSL_LIBRARIES}")
MESSAGE(STATUS "CRYPTO_LIBRARY = ${CRYPTO_LIBRARY}")
MESSAGE(STATUS "OPENSSL_MAJOR_VERSION = ${OPENSSL_MAJOR_VERSION}")
INCLUDE(CheckSymbolExists)
SET(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
CHECK_SYMBOL_EXISTS(SHA512_DIGEST_LENGTH "openssl/sha.h"
HAVE_SHA512_DIGEST_LENGTH)
IF(OPENSSL_FOUND AND HAVE_SHA512_DIGEST_LENGTH) IF(OPENSSL_FOUND AND HAVE_SHA512_DIGEST_LENGTH)
MESSAGE(STATUS "OPENSSL_INCLUDE_DIR = ${OPENSSL_INCLUDE_DIR}")
MESSAGE(STATUS "OPENSSL_LIBRARIES = ${OPENSSL_LIBRARIES}")
MESSAGE(STATUS "CRYPTO_LIBRARY = ${CRYPTO_LIBRARY}")
MESSAGE(STATUS "OPENSSL_MAJOR_VERSION = ${OPENSSL_MAJOR_VERSION}")
SET(SSL_SOURCES "") SET(SSL_SOURCES "")
SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARY}) SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARY})
IF(CMAKE_SYSTEM_NAME MATCHES "SunOS") IF(CMAKE_SYSTEM_NAME MATCHES "SunOS")

View File

@@ -2,7 +2,6 @@ usr/sbin/mysqld
usr/lib/mysql/plugin/auth_pam.so usr/lib/mysql/plugin/auth_pam.so
usr/lib/mysql/plugin/auth_socket.so usr/lib/mysql/plugin/auth_socket.so
usr/lib/mysql/plugin/ha_mroonga.so usr/lib/mysql/plugin/ha_mroonga.so
usr/lib/mysql/plugin/ha_oqgraph.so
usr/lib/mysql/plugin/ha_sequence.so usr/lib/mysql/plugin/ha_sequence.so
usr/lib/mysql/plugin/ha_sphinx.so usr/lib/mysql/plugin/ha_sphinx.so
usr/lib/mysql/plugin/ha_innodb.so usr/lib/mysql/plugin/ha_innodb.so
@@ -15,7 +14,6 @@ usr/lib/mysql/plugin/semisync_master.so
usr/lib/mysql/plugin/semisync_slave.so usr/lib/mysql/plugin/semisync_slave.so
usr/lib/mysql/plugin/sql_errlog.so usr/lib/mysql/plugin/sql_errlog.so
usr/lib/mysql/plugin/server_audit.so usr/lib/mysql/plugin/server_audit.so
usr/lib/mysql/plugin/sphinx.so
usr/lib/libhsclient.so.* usr/lib/libhsclient.so.*
etc/mysql/debian-start etc/mysql/debian-start
etc/mysql/conf.d/mysqld_safe_syslog.cnf etc/mysql/conf.d/mysqld_safe_syslog.cnf

View File

@@ -21,7 +21,7 @@ invoke() {
fi fi
} }
MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --default-storage-engine=myisam" MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --disable-log-bin --skip-grant-tables --default-storage-engine=myisam"
test_mysql_access() { test_mysql_access() {
mysql --no-defaults -u root -h localhost </dev/null >/dev/null 2>&1 mysql --no-defaults -u root -h localhost </dev/null >/dev/null 2>&1
@@ -40,6 +40,7 @@ set_mysql_rootpw() {
# this avoids us having to call "test" or "[" on $rootpw # this avoids us having to call "test" or "[" on $rootpw
cat << EOF > $tfile cat << EOF > $tfile
USE mysql; USE mysql;
SET sql_log_bin=0;
UPDATE user SET password=PASSWORD("$rootpw") WHERE user='root'; UPDATE user SET password=PASSWORD("$rootpw") WHERE user='root';
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
EOF EOF
@@ -144,7 +145,7 @@ EOF
# Debian: beware of the bashisms... # Debian: beware of the bashisms...
# Debian: can safely run on upgrades with existing databases # Debian: can safely run on upgrades with existing databases
set +e set +e
/bin/bash /usr/bin/mysql_install_db --rpm --user=mysql 2>&1 | $ERR_LOGGER /bin/bash /usr/bin/mysql_install_db --rpm --user=mysql --disable-log-bin 2>&1 | $ERR_LOGGER
set -e set -e
## On every reconfiguration the maintenance user is recreated. ## On every reconfiguration the maintenance user is recreated.

View File

@@ -2,7 +2,6 @@ usr/sbin/mysqld
usr/lib/mysql/plugin/auth_pam.so usr/lib/mysql/plugin/auth_pam.so
usr/lib/mysql/plugin/auth_socket.so usr/lib/mysql/plugin/auth_socket.so
usr/lib/mysql/plugin/ha_mroonga.so usr/lib/mysql/plugin/ha_mroonga.so
usr/lib/mysql/plugin/ha_oqgraph.so
usr/lib/mysql/plugin/ha_sequence.so usr/lib/mysql/plugin/ha_sequence.so
usr/lib/mysql/plugin/ha_sphinx.so usr/lib/mysql/plugin/ha_sphinx.so
usr/lib/mysql/plugin/ha_innodb.so usr/lib/mysql/plugin/ha_innodb.so
@@ -15,7 +14,6 @@ usr/lib/mysql/plugin/semisync_master.so
usr/lib/mysql/plugin/semisync_slave.so usr/lib/mysql/plugin/semisync_slave.so
usr/lib/mysql/plugin/sql_errlog.so usr/lib/mysql/plugin/sql_errlog.so
usr/lib/mysql/plugin/server_audit.so usr/lib/mysql/plugin/server_audit.so
usr/lib/mysql/plugin/sphinx.so
usr/lib/libhsclient.so.* usr/lib/libhsclient.so.*
etc/apparmor.d/usr.sbin.mysqld etc/apparmor.d/usr.sbin.mysqld
usr/share/apport/package-hooks/source_mariadb-10.0.py usr/share/apport/package-hooks/source_mariadb-10.0.py

View File

@@ -21,7 +21,7 @@ invoke() {
fi fi
} }
MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --default-storage-engine=myisam" MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --disable-log-bin --skip-grant-tables --default-storage-engine=myisam"
test_mysql_access() { test_mysql_access() {
mysql --no-defaults -u root -h localhost </dev/null >/dev/null 2>&1 mysql --no-defaults -u root -h localhost </dev/null >/dev/null 2>&1
@@ -41,6 +41,7 @@ set_mysql_rootpw() {
# this avoids us having to call "test" or "[" on $rootpw # this avoids us having to call "test" or "[" on $rootpw
cat << EOF > $tfile cat << EOF > $tfile
USE mysql; USE mysql;
SET sql_log_bin=0;
UPDATE user SET password=PASSWORD("$rootpw") WHERE user='root'; UPDATE user SET password=PASSWORD("$rootpw") WHERE user='root';
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
EOF EOF
@@ -145,7 +146,7 @@ EOF
# Debian: beware of the bashisms... # Debian: beware of the bashisms...
# Debian: can safely run on upgrades with existing databases # Debian: can safely run on upgrades with existing databases
set +e set +e
/bin/bash /usr/bin/mysql_install_db --rpm --user=mysql 2>&1 | $ERR_LOGGER /bin/bash /usr/bin/mysql_install_db --rpm --user=mysql --disable-log-bin 2>&1 | $ERR_LOGGER
set -e set -e
## On every reconfiguration the maintenance user is recreated. ## On every reconfiguration the maintenance user is recreated.

View File

@@ -618,14 +618,17 @@ void scramble_323(char *to, const char *message, const char *password);
my_bool check_scramble_323(const unsigned char *reply, const char *message, my_bool check_scramble_323(const unsigned char *reply, const char *message,
unsigned long *salt); unsigned long *salt);
void get_salt_from_password_323(unsigned long *res, const char *password); void get_salt_from_password_323(unsigned long *res, const char *password);
#if MYSQL_VERSION_ID < 100100
void make_password_from_salt_323(char *to, const unsigned long *salt); void make_password_from_salt_323(char *to, const unsigned long *salt);
#endif
void make_scrambled_password(char *to, const char *password); void make_scrambled_password(char *to, const char *password);
void scramble(char *to, const char *message, const char *password); void scramble(char *to, const char *message, const char *password);
my_bool check_scramble(const unsigned char *reply, const char *message, my_bool check_scramble(const unsigned char *reply, const char *message,
const unsigned char *hash_stage2); const unsigned char *hash_stage2);
void get_salt_from_password(unsigned char *res, const char *password); void get_salt_from_password(unsigned char *res, const char *password);
#if MYSQL_VERSION_ID < 100100
void make_password_from_salt(char *to, const unsigned char *hash_stage2); void make_password_from_salt(char *to, const unsigned char *hash_stage2);
#endif
char *octet2hex(char *to, const char *str, unsigned int len); char *octet2hex(char *to, const char *str, unsigned int len);
/* end of password.c */ /* end of password.c */

View File

@@ -52,7 +52,7 @@ eval SELECT 'hello' INTO OUTFILE 'fake_file.$prefix';
# Use '/' instead of '\' in the error message. On windows platform, dir is # Use '/' instead of '\' in the error message. On windows platform, dir is
# formed with '\'. # formed with '\'.
--replace_regex /\\testing_1\\*/\/testing_1\// --replace_regex /\\testing_1\\*/\/testing_1\// /66/39/
--error 1010 --error 1010
DROP DATABASE testing_1; DROP DATABASE testing_1;
let $wait_binlog_event= DROP TABLE IF EXIST; let $wait_binlog_event= DROP TABLE IF EXIST;

View File

@@ -1506,7 +1506,12 @@ sub command_line_setup {
{ {
$default_vardir= "$glob_mysql_test_dir/var"; $default_vardir= "$glob_mysql_test_dir/var";
} }
$default_vardir = realpath $default_vardir unless IS_WINDOWS; unless (IS_WINDOWS) {
my $realpath = realpath($default_vardir);
die "realpath('$default_vardir') failed: $!\n"
unless defined($realpath) && $realpath ne '';
$default_vardir = $realpath;
}
if ( ! $opt_vardir ) if ( ! $opt_vardir )
{ {

View File

@@ -3008,5 +3008,11 @@ Warnings:
Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` where ('%' = concat(`test`.`t1`.`c1`)) Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` where ('%' = concat(`test`.`t1`.`c1`))
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-7629 Regression: Bit and hex string literals changed column names in 10.0.14
#
SELECT _binary 0x7E, _binary X'7E', _binary B'01111110';
_binary 0x7E _binary X'7E' _binary B'01111110'
~ ~ ~
#
# End of 10.0 tests # End of 10.0 tests
# #

View File

@@ -7907,5 +7907,11 @@ HEX(a) a
3F23 ?# 3F23 ?#
DROP TABLE t1; DROP TABLE t1;
# #
# MDEV-7629 Regression: Bit and hex string literals changed column names in 10.0.14
#
SELECT _latin1 0x7E, _latin1 X'7E', _latin1 B'01111110';
_latin1 0x7E _latin1 X'7E' _latin1 B'01111110'
~ ~ ~
#
# End of 10.0 tests # End of 10.0 tests
# #

View File

@@ -6259,6 +6259,12 @@ EXECUTE stmt USING @b,@b;
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation 'concat' ERROR HY000: Illegal mix of collations (latin1_swedish_ci,IMPLICIT) and (utf8_general_ci,COERCIBLE) for operation 'concat'
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
DROP TABLE t1; DROP TABLE t1;
#
# MDEV-7629 Regression: Bit and hex string literals changed column names in 10.0.14
#
SELECT _utf8 0x7E, _utf8 X'7E', _utf8 B'01111110';
_utf8 0x7E _utf8 X'7E' _utf8 B'01111110'
~ ~ ~
# Start of ctype_unescape.inc # Start of ctype_unescape.inc
SET @query=_binary'SELECT CHARSET(\'test\'),@@character_set_client,@@character_set_connection'; SET @query=_binary'SELECT CHARSET(\'test\'),@@character_set_client,@@character_set_connection';
PREPARE stmt FROM @query; PREPARE stmt FROM @query;

View File

@@ -5,7 +5,7 @@ explain extended select INTERVAL(55,10,20,30,40,50,60,70,80,90,100),interval(3,1
id select_type table type possible_keys key key_len ref rows filtered Extra id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings: Warnings:
Note 1003 select interval((55,10,20,30,40,50,60,70,80,90,100)) AS `INTERVAL(55,10,20,30,40,50,60,70,80,90,100)`,interval((3,1,(1 + 1),(((1 + 1) + 1) + 1))) AS `interval(3,1,1+1,1+1+1+1)`,field('IBM','NCA','ICL','SUN','IBM','DIGITAL') AS `field("IBM","NCA","ICL","SUN","IBM","DIGITAL")`,field('A','B','C') AS `field("A","B","C")`,elt(2,'ONE','TWO','THREE') AS `elt(2,"ONE","TWO","THREE")`,interval((0,1,2,3,4)) AS `interval(0,1,2,3,4)`,(elt(1,1,2,3) | 0) AS `elt(1,1,2,3)|0`,(elt(1,1.1,1.2,1.3) + 0) AS `elt(1,1.1,1.2,1.3)+0` Note 1003 select interval(55,10,20,30,40,50,60,70,80,90,100) AS `INTERVAL(55,10,20,30,40,50,60,70,80,90,100)`,interval(3,1,(1 + 1),(((1 + 1) + 1) + 1)) AS `interval(3,1,1+1,1+1+1+1)`,field('IBM','NCA','ICL','SUN','IBM','DIGITAL') AS `field("IBM","NCA","ICL","SUN","IBM","DIGITAL")`,field('A','B','C') AS `field("A","B","C")`,elt(2,'ONE','TWO','THREE') AS `elt(2,"ONE","TWO","THREE")`,interval(0,1,2,3,4) AS `interval(0,1,2,3,4)`,(elt(1,1,2,3) | 0) AS `elt(1,1,2,3)|0`,(elt(1,1.1,1.2,1.3) + 0) AS `elt(1,1.1,1.2,1.3)+0`
SELECT INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56); SELECT INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56);
INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56) INTERVAL(13, 7, 14, 21, 28, 35, 42, 49, 56)
1 1

View File

@@ -5874,4 +5874,17 @@ id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE t2 ALL NULL NULL NULL NULL 11 Using where 1 SIMPLE t2 ALL NULL NULL NULL NULL 11 Using where
set join_buffer_space_limit=default; set join_buffer_space_limit=default;
drop table t1; drop table t1;
#
# MDEV-6687: Assertion `0' failed in Protocol::end_statement on query
#
SET join_cache_level = 3;
# The following should have
# - table order PROFILING,user,
# - table user accessed with hash_ALL:
explain
SELECT * FROM INFORMATION_SCHEMA.PROFILING, mysql.user WHERE password_expired = PAGE_FAULTS_MINOR;
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE PROFILING ALL NULL NULL NULL NULL NULL Using where
1 SIMPLE user hash_ALL NULL #hash#$hj 1 information_schema.PROFILING.PAGE_FAULTS_MINOR 4 Using where; Using join buffer (flat, BNLH join)
set join_cache_level=default;
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;

View File

@@ -1409,4 +1409,40 @@ Note 1003 select `test`.`a`.`a` AS `a`,`test`.`a`.`b` AS `b`,`test`.`b`.`a` AS `
set histogram_size=@save_histogram_size; set histogram_size=@save_histogram_size;
set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
drop table t0,t1,t2; drop table t0,t1,t2;
#
# Bug mdev-7316: a conjunct in WHERE with selectivity == 0
#
CREATE TABLE t1 (a varchar(16), b int, PRIMARY KEY(a), KEY(b)) ENGINE=INNODB;
Warnings:
Warning 1286 Unknown storage engine 'INNODB'
Warning 1266 Using storage engine MyISAM for table 't1'
INSERT INTO t1 VALUES
('USAChinese',10), ('USAEnglish',20), ('USAFrench',30);
CREATE TABLE t2 (i int) ENGINE=INNODB;
Warnings:
Warning 1286 Unknown storage engine 'INNODB'
Warning 1266 Using storage engine MyISAM for table 't2'
INSERT INTO t2 VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(1),(2),(3),(4);
ANALYZE TABLE t1, t2;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
test.t2 analyze status Engine-independent statistics collected
test.t2 analyze status OK
set use_stat_tables='preferably';
set optimizer_use_condition_selectivity=3;
EXPLAIN EXTENDED
SELECT * FROM t1, t2
WHERE a <> 'USARussian' AND b IS NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ref PRIMARY,b b 5 const 1 100.00 Using index condition; Using where
1 SIMPLE t2 ALL NULL NULL NULL NULL 14 100.00 Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`i` AS `i` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`a` <> 'USARussian') and isnull(`test`.`t1`.`b`))
SELECT * FROM t1, t2
WHERE a <> 'USARussian' AND b IS NULL;
a b i
set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
DROP TABLE t1,t2;
set use_stat_tables=@save_use_stat_tables; set use_stat_tables=@save_use_stat_tables;

View File

@@ -1419,6 +1419,36 @@ Note 1003 select `test`.`a`.`a` AS `a`,`test`.`a`.`b` AS `b`,`test`.`b`.`a` AS `
set histogram_size=@save_histogram_size; set histogram_size=@save_histogram_size;
set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity; set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
drop table t0,t1,t2; drop table t0,t1,t2;
#
# Bug mdev-7316: a conjunct in WHERE with selectivity == 0
#
CREATE TABLE t1 (a varchar(16), b int, PRIMARY KEY(a), KEY(b)) ENGINE=INNODB;
INSERT INTO t1 VALUES
('USAChinese',10), ('USAEnglish',20), ('USAFrench',30);
CREATE TABLE t2 (i int) ENGINE=INNODB;
INSERT INTO t2 VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(1),(2),(3),(4);
ANALYZE TABLE t1, t2;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
test.t2 analyze status Engine-independent statistics collected
test.t2 analyze status OK
set use_stat_tables='preferably';
set optimizer_use_condition_selectivity=3;
EXPLAIN EXTENDED
SELECT * FROM t1, t2
WHERE a <> 'USARussian' AND b IS NULL;
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ref PRIMARY,b b 5 const 2 66.67 Using where; Using index
1 SIMPLE t2 ALL NULL NULL NULL NULL 14 100.00 Using join buffer (flat, BNL join)
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t2`.`i` AS `i` from `test`.`t1` join `test`.`t2` where ((`test`.`t1`.`a` <> 'USARussian') and isnull(`test`.`t1`.`b`))
SELECT * FROM t1, t2
WHERE a <> 'USARussian' AND b IS NULL;
a b i
set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
DROP TABLE t1,t2;
set use_stat_tables=@save_use_stat_tables; set use_stat_tables=@save_use_stat_tables;
set optimizer_switch=@save_optimizer_switch_for_selectivity_test; set optimizer_switch=@save_optimizer_switch_for_selectivity_test;
set @tmp_ust= @@use_stat_tables; set @tmp_ust= @@use_stat_tables;
@@ -1482,6 +1512,30 @@ select * from t1 where col2 != true;
col1 col2 col1 col2
drop table t1; drop table t1;
# #
# MDEV-7413: optimizer_use_condition_selectivity > 2 crashes 10.0.15+maria-1~wheezy
#
CREATE TABLE t1 (
parent_id int,
child_group_id int,
child_user_id int,
KEY (parent_id,child_group_id,child_user_id)
) ENGINE=InnoDB;
CREATE TABLE t2 (
id int,
lower_group_name varchar(255),
directory_id int(20),
UNIQUE KEY (directory_id)
) ENGINE=InnoDB;
CREATE TABLE t3 (id int) ENGINE=InnoDB;
insert into t1 values (1,1,1),(2,2,2);
insert into t2 values (10,'foo',10),(20,'bar',20);
insert into t3 values (101),(102);
set use_stat_tables = PREFERABLY, optimizer_use_condition_selectivity = 3;
select * from t1, t2, t3
where t1.child_user_id=t3.id and t1.child_group_id is null and t2.lower_group_name='foo' and t1.parent_id=t2.id and t2.directory_id=10;
parent_id child_group_id child_user_id id lower_group_name directory_id id
drop table t1,t2,t3;
#
# End of 10.0 tests # End of 10.0 tests
# #
set use_stat_tables= @tmp_ust; set use_stat_tables= @tmp_ust;

View File

@@ -284,4 +284,23 @@ DROP EVENT teste_bug11763507;
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# -- End of 5.1 tests # -- End of 5.1 tests
# ------------------------------------------------------------------ # ------------------------------------------------------------------
grant create routine on test.* to foo1@localhost identified by 'foo';
update mysql.user set password = replace(password, '*', '-') where user='foo1';
show grants;
Grants for foo1@localhost
GRANT USAGE ON *.* TO 'foo1'@'localhost' IDENTIFIED BY PASSWORD '*F3A2A51A9B0F2BE2468926B4132313728C250DBF'
GRANT CREATE ROUTINE ON `test`.* TO 'foo1'@'localhost'
flush privileges;
show grants;
Grants for foo1@localhost
GRANT USAGE ON *.* TO 'foo1'@'localhost' IDENTIFIED BY PASSWORD '-F3A2A51A9B0F2BE2468926B4132313728C250DBF'
GRANT CREATE ROUTINE ON `test`.* TO 'foo1'@'localhost'
create procedure spfoo() select 1;
show grants;
Grants for foo1@localhost
GRANT USAGE ON *.* TO 'foo1'@'localhost' IDENTIFIED BY PASSWORD '-F3A2A51A9B0F2BE2468926B4132313728C250DBF'
GRANT CREATE ROUTINE ON `test`.* TO 'foo1'@'localhost'
GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `test`.`spfoo` TO 'foo1'@'localhost'
drop procedure spfoo;
drop user foo1@localhost;
set @@global.concurrent_insert= @old_concurrent_insert; set @@global.concurrent_insert= @old_concurrent_insert;

View File

@@ -2146,6 +2146,57 @@ drop database mysqltest2;
drop database mysqltest3; drop database mysqltest3;
drop database mysqltest4; drop database mysqltest4;
# End of 5.5 tests # End of 5.5 tests
#
# MDEV-7220: Materialization strategy is not used for REPLACE ... SELECT
#
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int, b int, c int);
insert into t1
select A.a+B.a*10+C.a*100, A.a+B.a*10+C.a*100, A.a+B.a*10+C.a*100
from t0 A, t0 B, t0 C;
create table t2 (a int, b int, c int);
insert into t2 select A.a, A.a, A.a from t1 A;
insert into t2 select * from t2;
insert into t2 select * from t2;
create table t3 as select * from t2 limit 1;
# The testcase only makes sense if the following uses Materialization:
explain
select * from t1 where (a,b) in (select max(a),b from t2 group by b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 Using where
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.b 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 4000 Using temporary
flush status;
replace into t3
select * from t1 where (a,b) in (select max(a),b from t2 group by b);
# Sequential reads:
# 1K is read from t1
# 4K is read from t2
# 1K groups is read from the tmp. table
#
# Lookups:
# 4K lookups in group by table
# 1K lookups in temp.table
#
# Writes:
# 2x 1K writes to temporary tables (grouping table and subquery materialization table
#
# The point is that neither counter should be in the millions (this
# will happen if Materialization is not used
show status where Variable_name like 'Handler_read%' or Variable_name like 'Handler_%write%';
Variable_name Value
Handler_read_first 0
Handler_read_key 5000
Handler_read_last 0
Handler_read_next 0
Handler_read_prev 0
Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 6003
Handler_tmp_write 2000
Handler_write 1000
drop table t0,t1,t2,t3;
set @subselect_mat_test_optimizer_switch_value=null; set @subselect_mat_test_optimizer_switch_value=null;
set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off'; set @@optimizer_switch='materialization=on,in_to_exists=off,semijoin=off';
set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on'; set optimizer_switch='mrr=on,mrr_sort_keys=on,index_condition_pushdown=on';

View File

@@ -2186,3 +2186,54 @@ drop database mysqltest2;
drop database mysqltest3; drop database mysqltest3;
drop database mysqltest4; drop database mysqltest4;
# End of 5.5 tests # End of 5.5 tests
#
# MDEV-7220: Materialization strategy is not used for REPLACE ... SELECT
#
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int, b int, c int);
insert into t1
select A.a+B.a*10+C.a*100, A.a+B.a*10+C.a*100, A.a+B.a*10+C.a*100
from t0 A, t0 B, t0 C;
create table t2 (a int, b int, c int);
insert into t2 select A.a, A.a, A.a from t1 A;
insert into t2 select * from t2;
insert into t2 select * from t2;
create table t3 as select * from t2 limit 1;
# The testcase only makes sense if the following uses Materialization:
explain
select * from t1 where (a,b) in (select max(a),b from t2 group by b);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t1 ALL NULL NULL NULL NULL 1000 Using where
1 PRIMARY <subquery2> eq_ref distinct_key distinct_key 8 test.t1.a,test.t1.b 1
2 MATERIALIZED t2 ALL NULL NULL NULL NULL 4000 Using temporary
flush status;
replace into t3
select * from t1 where (a,b) in (select max(a),b from t2 group by b);
# Sequential reads:
# 1K is read from t1
# 4K is read from t2
# 1K groups is read from the tmp. table
#
# Lookups:
# 4K lookups in group by table
# 1K lookups in temp.table
#
# Writes:
# 2x 1K writes to temporary tables (grouping table and subquery materialization table
#
# The point is that neither counter should be in the millions (this
# will happen if Materialization is not used
show status where Variable_name like 'Handler_read%' or Variable_name like 'Handler_%write%';
Variable_name Value
Handler_read_first 0
Handler_read_key 5000
Handler_read_last 0
Handler_read_next 0
Handler_read_prev 0
Handler_read_rnd 0
Handler_read_rnd_deleted 0
Handler_read_rnd_next 6003
Handler_tmp_write 2000
Handler_write 1000
drop table t0,t1,t2,t3;

View File

@@ -109,3 +109,11 @@ DROP VIEW v1;
CREATE VIEW v1 AS select `test`.`t1`.`a` AS `a` from `test`.`t1` where exists(select ' a ' AS `alias` from `test`.`t1` group by ' a '); CREATE VIEW v1 AS select `test`.`t1`.`a` AS `a` from `test`.`t1` where exists(select ' a ' AS `alias` from `test`.`t1` group by ' a ');
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
create view v1 as select interval(55,10) as my_col;
show create view v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select interval(55,10) AS `my_col` latin1 latin1_swedish_ci
select * from v1;
my_col
1
drop view v1;

View File

@@ -1,4 +1,5 @@
create table t1(a int not null primary key, b int) engine=innodb; call mtr.add_suppression("InnoDB: Error: row_merge_drop_indexes_dict failed with error code*");
create table t1(a int, b int) engine=innodb;
create procedure innodb_insert_proc (repeat_count int) create procedure innodb_insert_proc (repeat_count int)
begin begin
declare current_num int; declare current_num int;
@@ -10,41 +11,53 @@ end while;
end// end//
commit; commit;
set autocommit=0; set autocommit=0;
call innodb_insert_proc(10000); call innodb_insert_proc(20000);
commit; commit;
set autocommit=1; set autocommit=1;
create table t2(a int) engine=innodb;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28'; set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28';
alter table t1 add testcol int; alter table t1 add testcol int;
ERROR HY000: The table 't1' is full ERROR HY000: The table 't1' is full
show create table t1; show create table t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL, `a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28_2'; alter table t2 add testcol int;
ERROR HY000: The table 't2' is full
alter table t1 add testcol int;
ERROR HY000: The table 't1' is full
alter table t1 add testcol int;
ERROR HY000: The table 't1' is full
alter table t1 add testcol2 int;
ERROR HY000: The table 't1' is full
alter table t1 add testcol3 int;
ERROR HY000: The table 't1' is full
alter table t1 add testcol int; alter table t1 add testcol int;
ERROR HY000: The table 't1' is full ERROR HY000: The table 't1' is full
show create table t1; show create table t1;
Table Create Table Table Create Table
t1 CREATE TABLE `t1` ( t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL, `a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ) ENGINE=InnoDB DEFAULT CHARSET=latin1
set DEBUG_DBUG=NULL; drop table t2;
alter table t1 add testcol2 int; alter table t1 add testcol2 int;
show create table t1; ERROR HY000: The table 't1' is full
Table Create Table alter table t1 add testcol3 int;
t1 CREATE TABLE `t1` ( ERROR HY000: The table 't1' is full
`a` int(11) NOT NULL, call innodb_insert_proc(20000);
`b` int(11) DEFAULT NULL, set autocommit=0;
`testcol2` int(11) DEFAULT NULL, call innodb_insert_proc(20000);
PRIMARY KEY (`a`) commit;
) ENGINE=InnoDB DEFAULT CHARSET=latin1 set autocommit=1;
select count(1) from t1; set DEBUG_DBUG='';
count(1)
10000
drop procedure innodb_insert_proc; drop procedure innodb_insert_proc;
drop table t1; drop table t1;
drop table if exists t2;

View File

@@ -0,0 +1,12 @@
select @@global.innodb_ft_server_stopword_table;
@@global.innodb_ft_server_stopword_table
NULL
CREATE TABLE `stop_it-IT` ENGINE = InnoDB SELECT * FROM information_schema.INNODB_FT_DEFAULT_STOPWORD;
SET @@global.innodb_ft_server_stopword_table = 'test/stop_it-IT';
ERROR 42000: Variable 'innodb_ft_server_stopword_table' can't be set to the value of 'test/stop_it-IT'
SET @@global.innodb_ft_server_stopword_table = 'test/stop_it@002dIT';
drop table `stop_it-IT`;
CREATE TABLE stop_it ENGINE = InnoDB SELECT * FROM information_schema.INNODB_FT_DEFAULT_STOPWORD;
SET @@global.innodb_ft_server_stopword_table = 'test/stop_it';
SET @@global.innodb_ft_server_stopword_table = NULL;
drop table stop_it;

View File

@@ -1,3 +1,3 @@
ERROR 42000: Row size too large (> ####). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline. ERROR 42000: The size of BLOB/TEXT data inserted in one transaction is greater than 10% of redo log size. Increase the redo log size using innodb_log_file_size.
f4 f8 f4 f8
f4 f8 f4 f8

View File

@@ -7,7 +7,9 @@
# DEBUG_SYNC must be compiled in. # DEBUG_SYNC must be compiled in.
--source include/have_debug_sync.inc --source include/have_debug_sync.inc
create table t1(a int not null primary key, b int) engine=innodb; call mtr.add_suppression("InnoDB: Error: row_merge_drop_indexes_dict failed with error code*");
create table t1(a int, b int) engine=innodb;
delimiter //; delimiter //;
create procedure innodb_insert_proc (repeat_count int) create procedure innodb_insert_proc (repeat_count int)
@@ -23,28 +25,51 @@ delimiter ;//
commit; commit;
set autocommit=0; set autocommit=0;
call innodb_insert_proc(10000); call innodb_insert_proc(20000);
commit; commit;
set autocommit=1; set autocommit=1;
create table t2(a int) engine=innodb;
show create table t2;
# This caused crash earlier # This caused crash earlier
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28'; set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28';
--error 1114 --error 1114
alter table t1 add testcol int; alter table t1 add testcol int;
show create table t1; show create table t1;
--error 1114
# This caused crash earlier alter table t2 add testcol int;
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28_2'; --error 1114
alter table t1 add testcol int;
--error 1114
alter table t1 add testcol int;
--error 1114
alter table t1 add testcol2 int;
--error 1114
alter table t1 add testcol3 int;
--error 1114 --error 1114
alter table t1 add testcol int; alter table t1 add testcol int;
show create table t1; show create table t1;
--error 0,1051
set DEBUG_DBUG=NULL; drop table t2;
--error 1114
alter table t1 add testcol2 int; alter table t1 add testcol2 int;
show create table t1; --error 1114
alter table t1 add testcol3 int;
--error 0,1114
call innodb_insert_proc(20000);
set autocommit=0;
--error 0,1114
call innodb_insert_proc(20000);
commit;
set autocommit=1;
select count(1) from t1; set DEBUG_DBUG='';
drop procedure innodb_insert_proc; drop procedure innodb_insert_proc;
drop table t1; drop table t1;
--disable_warnings
drop table if exists t2;
--enable_warnings

View File

@@ -0,0 +1,2 @@
--innodb_ft_default_stopword

View File

@@ -0,0 +1,16 @@
--source include/have_innodb.inc
select @@global.innodb_ft_server_stopword_table;
CREATE TABLE `stop_it-IT` ENGINE = InnoDB SELECT * FROM information_schema.INNODB_FT_DEFAULT_STOPWORD;
--error 1231
SET @@global.innodb_ft_server_stopword_table = 'test/stop_it-IT';
--error 0,1231
SET @@global.innodb_ft_server_stopword_table = 'test/stop_it@002dIT';
drop table `stop_it-IT`;
CREATE TABLE stop_it ENGINE = InnoDB SELECT * FROM information_schema.INNODB_FT_DEFAULT_STOPWORD;
SET @@global.innodb_ft_server_stopword_table = 'test/stop_it';
SET @@global.innodb_ft_server_stopword_table = NULL;
drop table stop_it;

View File

@@ -1,5 +1,7 @@
--source include/have_innodb.inc --source include/have_innodb.inc
--source include/have_partition.inc --source include/have_partition.inc
# Test causes OS error printout
--source include/not_windows.inc
--disable_query_log --disable_query_log
--disable_result_log --disable_result_log

View File

@@ -5,6 +5,11 @@
-- source include/have_innodb.inc -- source include/have_innodb.inc
if (`select plugin_auth_version <= "5.6.22-MariaDB-72.0" from information_schema.plugins where plugin_name='innodb'`)
{
--skip Not fixed in XtraDB as of 5.6.22-MariaDB-72.0 or earlier
}
-- disable_query_log -- disable_query_log
-- disable_result_log -- disable_result_log

View File

@@ -1136,6 +1136,80 @@ SET GLOBAL debug_dbug=@old_dbug;
SET GLOBAL slave_parallel_threads=0; SET GLOBAL slave_parallel_threads=0;
SET GLOBAL slave_parallel_threads=10; SET GLOBAL slave_parallel_threads=10;
include/start_slave.inc include/start_slave.inc
*** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption ***
include/stop_slave.inc
SET GLOBAL slave_parallel_threads=1;
SET @old_dbug= @@GLOBAL.debug_dbug;
SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000";
INSERT INTO t2 VALUES (101);
INSERT INTO t2 VALUES (102);
INSERT INTO t2 VALUES (103);
INSERT INTO t2 VALUES (104);
INSERT INTO t2 VALUES (105);
SET gtid_seq_no=1000;
INSERT INTO t2 VALUES (106);
INSERT INTO t2 VALUES (107);
INSERT INTO t2 VALUES (108);
INSERT INTO t2 VALUES (109);
INSERT INTO t2 VALUES (110);
INSERT INTO t2 VALUES (111);
INSERT INTO t2 VALUES (112);
INSERT INTO t2 VALUES (113);
INSERT INTO t2 VALUES (114);
INSERT INTO t2 VALUES (115);
INSERT INTO t2 VALUES (116);
INSERT INTO t2 VALUES (117);
INSERT INTO t2 VALUES (118);
INSERT INTO t2 VALUES (119);
INSERT INTO t2 VALUES (120);
INSERT INTO t2 VALUES (121);
INSERT INTO t2 VALUES (122);
INSERT INTO t2 VALUES (123);
INSERT INTO t2 VALUES (124);
INSERT INTO t2 VALUES (125);
INSERT INTO t2 VALUES (126);
INSERT INTO t2 VALUES (127);
INSERT INTO t2 VALUES (128);
INSERT INTO t2 VALUES (129);
INSERT INTO t2 VALUES (130);
include/save_master_gtid.inc
include/start_slave.inc
include/sync_with_master_gtid.inc
SELECT * FROM t2 WHERE a >= 100 ORDER BY a;
a
101
102
103
104
105
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
include/stop_slave.inc
SET GLOBAL debug_dbug=@old_dbug;
SET GLOBAL slave_parallel_threads=10;
include/start_slave.inc
include/stop_slave.inc include/stop_slave.inc
SET GLOBAL slave_parallel_threads=@old_parallel_threads; SET GLOBAL slave_parallel_threads=@old_parallel_threads;
include/start_slave.inc include/start_slave.inc

View File

@@ -986,4 +986,15 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back
include/diff_tables.inc [master:t1, slave:t1] include/diff_tables.inc [master:t1, slave:t1]
include/diff_tables.inc [master:log, slave:log] include/diff_tables.inc [master:log, slave:log]
drop table t1, log; drop table t1, log;
drop trigger if exists notexistent;
Warnings:
Note 1360 Trigger does not exist
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; drop trigger if exists notexistent
include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
slave-bin.000001 # Gtid # # GTID #-#-#
slave-bin.000001 # Query # # use `test`; drop trigger if exists notexistent
include/rpl_end.inc include/rpl_end.inc

View File

@@ -0,0 +1,19 @@
include/master-slave.inc
[connection master]
call mtr.add_suppression("Timeout waiting for reply of binlog*");
create table t1 (i int);
set global rpl_semi_sync_master_enabled = ON;
include/stop_slave.inc
set global rpl_semi_sync_slave_enabled = ON;
change master to master_log_file='master-bin.000002', master_log_pos = 320;
start slave;
include/wait_for_slave_io_error.inc [errno=1236]
insert into t1 values (1);
reset master;
include/stop_slave.inc
reset slave;
include/start_slave.inc
set global rpl_semi_sync_slave_enabled = OFF;
drop table t1;
set global rpl_semi_sync_master_enabled = OFF;
include/rpl_end.inc

View File

@@ -1843,6 +1843,62 @@ SET GLOBAL slave_parallel_threads=10;
--source include/start_slave.inc --source include/start_slave.inc
--echo *** MDEV-7335: Potential parallel slave deadlock with specific binlog corruption ***
--connection server_2
--source include/stop_slave.inc
SET GLOBAL slave_parallel_threads=1;
SET @old_dbug= @@GLOBAL.debug_dbug;
SET GLOBAL debug_dbug="+d,slave_discard_xid_for_gtid_0_x_1000";
--connection server_1
INSERT INTO t2 VALUES (101);
INSERT INTO t2 VALUES (102);
INSERT INTO t2 VALUES (103);
INSERT INTO t2 VALUES (104);
INSERT INTO t2 VALUES (105);
# Inject a partial event group (missing XID at the end). The bug was that such
# partial group was not handled appropriately, leading to server deadlock.
SET gtid_seq_no=1000;
INSERT INTO t2 VALUES (106);
INSERT INTO t2 VALUES (107);
INSERT INTO t2 VALUES (108);
INSERT INTO t2 VALUES (109);
INSERT INTO t2 VALUES (110);
INSERT INTO t2 VALUES (111);
INSERT INTO t2 VALUES (112);
INSERT INTO t2 VALUES (113);
INSERT INTO t2 VALUES (114);
INSERT INTO t2 VALUES (115);
INSERT INTO t2 VALUES (116);
INSERT INTO t2 VALUES (117);
INSERT INTO t2 VALUES (118);
INSERT INTO t2 VALUES (119);
INSERT INTO t2 VALUES (120);
INSERT INTO t2 VALUES (121);
INSERT INTO t2 VALUES (122);
INSERT INTO t2 VALUES (123);
INSERT INTO t2 VALUES (124);
INSERT INTO t2 VALUES (125);
INSERT INTO t2 VALUES (126);
INSERT INTO t2 VALUES (127);
INSERT INTO t2 VALUES (128);
INSERT INTO t2 VALUES (129);
INSERT INTO t2 VALUES (130);
--source include/save_master_gtid.inc
--connection server_2
--source include/start_slave.inc
--source include/sync_with_master_gtid.inc
# The partial event group (a=106) should be rolled back and thus missing.
SELECT * FROM t2 WHERE a >= 100 ORDER BY a;
--source include/stop_slave.inc
SET GLOBAL debug_dbug=@old_dbug;
SET GLOBAL slave_parallel_threads=10;
--source include/start_slave.inc
# Clean up. # Clean up.
--connection server_2 --connection server_2
--source include/stop_slave.inc --source include/stop_slave.inc

View File

@@ -532,6 +532,19 @@ connection master;
drop table t1, log; drop table t1, log;
sync_slave_with_master; sync_slave_with_master;
#
# MDEV-6769 DROP TRIGGER IF NOT EXIST binlogged on master but not on slave
#
let $slave_pos= query_get_value(SHOW MASTER STATUS, Position, 1);
connection master;
let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1);
drop trigger if exists notexistent;
source include/show_binlog_events.inc;
sync_slave_with_master;
let $binlog_start= $slave_pos;
source include/show_binlog_events.inc;
connection master;
# #
# End of tests # End of tests
# #

View File

@@ -0,0 +1,31 @@
--source include/have_semisync.inc
--source include/master-slave.inc
call mtr.add_suppression("Timeout waiting for reply of binlog*");
create table t1 (i int);
set global rpl_semi_sync_master_enabled = ON;
--connection slave
--source include/stop_slave.inc
set global rpl_semi_sync_slave_enabled = ON;
change master to master_log_file='master-bin.000002', master_log_pos = 320;
start slave;
--let $slave_io_errno=1236
--source include/wait_for_slave_io_error.inc
--connection master
insert into t1 values (1);
reset master;
--connection slave
--source include/stop_slave.inc
reset slave;
--source include/start_slave.inc
set global rpl_semi_sync_slave_enabled = OFF;
--connection master
drop table t1;
set global rpl_semi_sync_master_enabled = OFF;
--source include/rpl_end.inc

View File

@@ -19,6 +19,11 @@ set names binary;
SET NAMES binary; SET NAMES binary;
--source include/ctype_like_cond_propagation.inc --source include/ctype_like_cond_propagation.inc
--echo #
--echo # MDEV-7629 Regression: Bit and hex string literals changed column names in 10.0.14
--echo #
SELECT _binary 0x7E, _binary X'7E', _binary B'01111110';
--echo # --echo #
--echo # End of 10.0 tests --echo # End of 10.0 tests
--echo # --echo #

View File

@@ -240,6 +240,11 @@ SHOW WARNINGS;
SELECT HEX(a),a FROM t1; SELECT HEX(a),a FROM t1;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-7629 Regression: Bit and hex string literals changed column names in 10.0.14
--echo #
SELECT _latin1 0x7E, _latin1 X'7E', _latin1 B'01111110';
--echo # --echo #
--echo # End of 10.0 tests --echo # End of 10.0 tests
--echo # --echo #

View File

@@ -1744,6 +1744,11 @@ EXECUTE stmt USING @b,@b;
DEALLOCATE PREPARE stmt; DEALLOCATE PREPARE stmt;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-7629 Regression: Bit and hex string literals changed column names in 10.0.14
--echo #
SELECT _utf8 0x7E, _utf8 X'7E', _utf8 B'01111110';
let $ctype_unescape_combinations=selected; let $ctype_unescape_combinations=selected;
--source include/ctype_unescape.inc --source include/ctype_unescape.inc

View File

@@ -3848,6 +3848,18 @@ set join_buffer_space_limit=default;
drop table t1; drop table t1;
--echo #
--echo # MDEV-6687: Assertion `0' failed in Protocol::end_statement on query
--echo #
SET join_cache_level = 3;
--echo # The following should have
--echo # - table order PROFILING,user,
--echo # - table user accessed with hash_ALL:
explain
SELECT * FROM INFORMATION_SCHEMA.PROFILING, mysql.user WHERE password_expired = PAGE_FAULTS_MINOR;
set join_cache_level=default;
# The following command must be the last one the file # The following command must be the last one the file
# this must be the last command in the file # this must be the last command in the file
set @@optimizer_switch=@save_optimizer_switch; set @@optimizer_switch=@save_optimizer_switch;

View File

@@ -149,11 +149,11 @@ UPDATE `t``\""e` SET a = 4 WHERE a = 22;
# NOTE: replace_regex is very slow on match copy/past '(.*)' regex's # NOTE: replace_regex is very slow on match copy/past '(.*)' regex's
# on big texts, removing a lot of text before + after makes it much faster. # on big texts, removing a lot of text before + after makes it much faster.
#/.*in (.*) trx.*/\1/ #/.*in (.*) trx.*/\1/
--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // --replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // /trx table locks [0-9]* // /total table locks [0-9]* //
SHOW ENGINE InnoDB STATUS; SHOW ENGINE InnoDB STATUS;
set @old_sql_mode = @@sql_mode; set @old_sql_mode = @@sql_mode;
set sql_mode = 'ANSI_QUOTES'; set sql_mode = 'ANSI_QUOTES';
--replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // --replace_regex /.*RECORD LOCKS space id [0-9]* page no [0-9]* n bits [0-9]* // / trx id .*// /.*index .* in // /trx table locks [0-9]* // /total table locks [0-9]* //
SHOW ENGINE InnoDB STATUS; SHOW ENGINE InnoDB STATUS;
set @@sql_mode = @old_sql_mode; set @@sql_mode = @old_sql_mode;
--echo # con1 --echo # con1

View File

@@ -942,5 +942,34 @@ set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivit
drop table t0,t1,t2; drop table t0,t1,t2;
--echo #
--echo # Bug mdev-7316: a conjunct in WHERE with selectivity == 0
--echo #
CREATE TABLE t1 (a varchar(16), b int, PRIMARY KEY(a), KEY(b)) ENGINE=INNODB;
INSERT INTO t1 VALUES
('USAChinese',10), ('USAEnglish',20), ('USAFrench',30);
CREATE TABLE t2 (i int) ENGINE=INNODB;
INSERT INTO t2 VALUES
(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(1),(2),(3),(4);
ANALYZE TABLE t1, t2;
set use_stat_tables='preferably';
set optimizer_use_condition_selectivity=3;
EXPLAIN EXTENDED
SELECT * FROM t1, t2
WHERE a <> 'USARussian' AND b IS NULL;
SELECT * FROM t1, t2
WHERE a <> 'USARussian' AND b IS NULL;
set optimizer_use_condition_selectivity=@save_optimizer_use_condition_selectivity;
DROP TABLE t1,t2;
set use_stat_tables=@save_use_stat_tables; set use_stat_tables=@save_use_stat_tables;

View File

@@ -79,6 +79,36 @@ select * from t1 where col2 != true;
drop table t1; drop table t1;
--echo #
--echo # MDEV-7413: optimizer_use_condition_selectivity > 2 crashes 10.0.15+maria-1~wheezy
--echo #
CREATE TABLE t1 (
parent_id int,
child_group_id int,
child_user_id int,
KEY (parent_id,child_group_id,child_user_id)
) ENGINE=InnoDB;
CREATE TABLE t2 (
id int,
lower_group_name varchar(255),
directory_id int(20),
UNIQUE KEY (directory_id)
) ENGINE=InnoDB;
CREATE TABLE t3 (id int) ENGINE=InnoDB;
insert into t1 values (1,1,1),(2,2,2);
insert into t2 values (10,'foo',10),(20,'bar',20);
insert into t3 values (101),(102);
set use_stat_tables = PREFERABLY, optimizer_use_condition_selectivity = 3;
select * from t1, t2, t3
where t1.child_user_id=t3.id and t1.child_group_id is null and t2.lower_group_name='foo' and t1.parent_id=t2.id and t2.directory_id=10;
drop table t1,t2,t3;
--echo # --echo #
--echo # End of 10.0 tests --echo # End of 10.0 tests
--echo # --echo #

View File

@@ -461,6 +461,26 @@ DROP EVENT teste_bug11763507;
--echo # -- End of 5.1 tests --echo # -- End of 5.1 tests
--echo # ------------------------------------------------------------------ --echo # ------------------------------------------------------------------
#
# A case of SHOW GRANTS
# (creating a new procedure changes the password)
#
grant create routine on test.* to foo1@localhost identified by 'foo';
update mysql.user set password = replace(password, '*', '-') where user='foo1';
--connect (foo,localhost,foo1,foo)
show grants;
--connection default
flush privileges;
--connection foo
show grants;
create procedure spfoo() select 1;
show grants;
--connection default
--disconnect foo
drop procedure spfoo;
drop user foo1@localhost;
# #
# Restore global concurrent_insert value. Keep in the end of the test file. # Restore global concurrent_insert value. Keep in the end of the test file.
# #

View File

@@ -1843,3 +1843,45 @@ drop database mysqltest4;
--echo # End of 5.5 tests --echo # End of 5.5 tests
--echo #
--echo # MDEV-7220: Materialization strategy is not used for REPLACE ... SELECT
--echo #
create table t0(a int);
insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
create table t1 (a int, b int, c int);
insert into t1
select A.a+B.a*10+C.a*100, A.a+B.a*10+C.a*100, A.a+B.a*10+C.a*100
from t0 A, t0 B, t0 C;
create table t2 (a int, b int, c int);
insert into t2 select A.a, A.a, A.a from t1 A;
insert into t2 select * from t2;
insert into t2 select * from t2;
create table t3 as select * from t2 limit 1;
--echo # The testcase only makes sense if the following uses Materialization:
explain
select * from t1 where (a,b) in (select max(a),b from t2 group by b);
flush status;
replace into t3
select * from t1 where (a,b) in (select max(a),b from t2 group by b);
--echo # Sequential reads:
--echo # 1K is read from t1
--echo # 4K is read from t2
--echo # 1K groups is read from the tmp. table
--echo #
--echo # Lookups:
--echo # 4K lookups in group by table
--echo # 1K lookups in temp.table
--echo #
--echo # Writes:
--echo # 2x 1K writes to temporary tables (grouping table and subquery materialization table
--echo #
--echo # The point is that neither counter should be in the millions (this
--echo # will happen if Materialization is not used
show status where Variable_name like 'Handler_read%' or Variable_name like 'Handler_%write%';
drop table t0,t1,t2,t3;

View File

@@ -90,3 +90,12 @@ eval CREATE VIEW v1 AS $query;
DROP VIEW v1; DROP VIEW v1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# MDEV-7482 VIEW containing INTERVAL(...)
#
create view v1 as select interval(55,10) as my_col;
show create view v1;
select * from v1;
drop view v1;

View File

@@ -855,7 +855,7 @@ static int search_default_file_with_ext(Process_option_func opt_handler,
ptr, name, line))) ptr, name, line)))
goto err; goto err;
if (!(search_dir= my_dir(ptr, MYF(MY_WME)))) if (!(search_dir= my_dir(ptr, MYF(MY_WME | MY_WANT_SORT))))
goto err; goto err;
for (i= 0; i < (uint) search_dir->number_of_files; i++) for (i= 0; i < (uint) search_dir->number_of_files; i++)

View File

@@ -1503,7 +1503,13 @@ done:
/* Come here if error and we need to rollback. */ /* Come here if error and we need to rollback. */
err: err:
error= 1; /* Transaction was rolled back */ error= 1; /* Transaction was rolled back */
ha_rollback_trans(thd, all); /*
In parallel replication, rollback is delayed, as there is extra replication
book-keeping to be done before rolling back and allowing a conflicting
transaction to continue (MDEV-7458).
*/
if (!(thd->rgi_slave && thd->rgi_slave->is_parallel_exec))
ha_rollback_trans(thd, all);
end: end:
if (rw_trans && mdl_request.ticket) if (rw_trans && mdl_request.ticket)

View File

@@ -2931,8 +2931,9 @@ public:
{ {
set_cs_specified(true); set_cs_specified(true);
} }
Item_string_with_introducer(const String *str, CHARSET_INFO *tocs) Item_string_with_introducer(const char *name,
:Item_string(str->ptr(), str->length(), tocs) const char *str, uint length, CHARSET_INFO *tocs)
:Item_string(name, str, length, tocs)
{ {
set_cs_specified(true); set_cs_specified(true);
} }

View File

@@ -734,6 +734,11 @@ public:
void fix_length_and_dec(); void fix_length_and_dec();
const char *func_name() const { return "interval"; } const char *func_name() const { return "interval"; }
uint decimal_precision() const { return 2; } uint decimal_precision() const { return 2; }
void print(String *str, enum_query_type query_type)
{
str->append(func_name());
print_args(str, 0, query_type);
}
}; };

View File

@@ -55,6 +55,8 @@
#define my_b_write_string(A, B) my_b_write((A), (B), (uint) (sizeof(B) - 1)) #define my_b_write_string(A, B) my_b_write((A), (B), (uint) (sizeof(B) - 1))
using std::max;
/** /**
BINLOG_CHECKSUM variable. BINLOG_CHECKSUM variable.
*/ */
@@ -1329,9 +1331,10 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
} }
data_len= uint4korr(buf + EVENT_LEN_OFFSET); data_len= uint4korr(buf + EVENT_LEN_OFFSET);
if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN || if (data_len < LOG_EVENT_MINIMAL_HEADER_LEN ||
data_len > current_thd->variables.max_allowed_packet) data_len > max(current_thd->variables.max_allowed_packet,
opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
{ {
DBUG_PRINT("error",("data_len: %ld", data_len)); DBUG_PRINT("error",("data_len: %lu", data_len));
result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS : result= ((data_len < LOG_EVENT_MINIMAL_HEADER_LEN) ? LOG_READ_BOGUS :
LOG_READ_TOO_LARGE); LOG_READ_TOO_LARGE);
goto end; goto end;
@@ -1452,7 +1455,7 @@ failed my_b_read"));
*/ */
DBUG_RETURN(0); DBUG_RETURN(0);
} }
uint data_len = uint4korr(head + EVENT_LEN_OFFSET); ulong data_len = uint4korr(head + EVENT_LEN_OFFSET);
char *buf= 0; char *buf= 0;
const char *error= 0; const char *error= 0;
Log_event *res= 0; Log_event *res= 0;
@@ -1461,7 +1464,8 @@ failed my_b_read"));
uint max_allowed_packet= thd ? slave_max_allowed_packet:~(uint)0; uint max_allowed_packet= thd ? slave_max_allowed_packet:~(uint)0;
#endif #endif
if (data_len > max_allowed_packet) if (data_len > max<ulong>(max_allowed_packet,
opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
{ {
error = "Event too big"; error = "Event too big";
goto err; goto err;
@@ -1495,7 +1499,7 @@ err:
{ {
DBUG_ASSERT(error != 0); DBUG_ASSERT(error != 0);
sql_print_error("Error in Log_event::read_log_event(): " sql_print_error("Error in Log_event::read_log_event(): "
"'%s', data_len: %d, event_type: %d", "'%s', data_len: %lu, event_type: %d",
error,data_len,(uchar)(head[EVENT_TYPE_OFFSET])); error,data_len,(uchar)(head[EVENT_TYPE_OFFSET]));
my_free(buf); my_free(buf);
/* /*

View File

@@ -513,8 +513,6 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
Subquery !contains {GROUP BY, ORDER BY [LIMIT], Subquery !contains {GROUP BY, ORDER BY [LIMIT],
aggregate functions}) && subquery predicate is not under "NOT IN")) aggregate functions}) && subquery predicate is not under "NOT IN"))
(*) The subquery must be part of a SELECT or CREATE TABLE ... SELECT statement.
The current condition also excludes multi-table update statements.
A note about prepared statements: we want the if-branch to be taken on A note about prepared statements: we want the if-branch to be taken on
PREPARE and each EXECUTE. The rewrites are only done once, but we need PREPARE and each EXECUTE. The rewrites are only done once, but we need
select_lex->sj_subselects list to be populated for every EXECUTE. select_lex->sj_subselects list to be populated for every EXECUTE.
@@ -523,9 +521,7 @@ bool is_materialization_applicable(THD *thd, Item_in_subselect *in_subs,
if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0 if (optimizer_flag(thd, OPTIMIZER_SWITCH_MATERIALIZATION) && // 0
!child_select->is_part_of_union() && // 1 !child_select->is_part_of_union() && // 1
parent_unit->first_select()->leaf_tables.elements && // 2 parent_unit->first_select()->leaf_tables.elements && // 2
(thd->lex->sql_command == SQLCOM_SELECT || // * child_select->outer_select()->leaf_tables.elements && // 2A
thd->lex->sql_command == SQLCOM_CREATE_TABLE) && // *
child_select->outer_select()->leaf_tables.elements && // 2A
subquery_types_allow_materialization(in_subs) && subquery_types_allow_materialization(in_subs) &&
(in_subs->is_top_level_item() || //3 (in_subs->is_top_level_item() || //3
optimizer_flag(thd, optimizer_flag(thd,

View File

@@ -640,7 +640,7 @@ handle_rpl_parallel_thread(void *arg)
} }
DBUG_ASSERT(qev->typ==rpl_parallel_thread::queued_event::QUEUED_EVENT); DBUG_ASSERT(qev->typ==rpl_parallel_thread::queued_event::QUEUED_EVENT);
thd->rgi_slave= group_rgi= rgi; thd->rgi_slave= rgi;
gco= rgi->gco; gco= rgi->gco;
/* Handle a new event group, which will be initiated by a GTID event. */ /* Handle a new event group, which will be initiated by a GTID event. */
if ((event_type= qev->ev->get_type_code()) == GTID_EVENT) if ((event_type= qev->ev->get_type_code()) == GTID_EVENT)
@@ -657,6 +657,21 @@ handle_rpl_parallel_thread(void *arg)
} }
}); });
if(unlikely(thd->wait_for_commit_ptr) && group_rgi != NULL)
{
/*
This indicates that we get a new GTID event in the middle of
a not completed event group. This is corrupt binlog (the master
will never write such binlog), so it does not happen unless
someone tries to inject wrong crafted binlog, but let us still
try to handle it somewhat nicely.
*/
group_rgi->cleanup_context(thd, true);
finish_event_group(rpt, group_rgi->gtid_sub_id,
group_rgi->parallel_entry, group_rgi);
rpt->loc_free_rgi(group_rgi);
}
in_event_group= true; in_event_group= true;
/* /*
If the standalone flag is set, then this event group consists of a If the standalone flag is set, then this event group consists of a
@@ -742,19 +757,6 @@ handle_rpl_parallel_thread(void *arg)
unlock_or_exit_cond(thd, &entry->LOCK_parallel_entry, unlock_or_exit_cond(thd, &entry->LOCK_parallel_entry,
&did_enter_cond, &old_stage); &did_enter_cond, &old_stage);
if(thd->wait_for_commit_ptr)
{
/*
This indicates that we get a new GTID event in the middle of
a not completed event group. This is corrupt binlog (the master
will never write such binlog), so it does not happen unless
someone tries to inject wrong crafted binlog, but let us still
try to handle it somewhat nicely.
*/
rgi->cleanup_context(thd, true);
thd->wait_for_commit_ptr->unregister_wait_for_prior_commit();
thd->wait_for_commit_ptr->wakeup_subsequent_commits(rgi->worker_error);
}
thd->wait_for_commit_ptr= &rgi->commit_orderer; thd->wait_for_commit_ptr= &rgi->commit_orderer;
if (opt_gtid_ignore_duplicates) if (opt_gtid_ignore_duplicates)
@@ -780,6 +782,7 @@ handle_rpl_parallel_thread(void *arg)
} }
} }
group_rgi= rgi;
group_ending= is_group_ending(qev->ev, event_type); group_ending= is_group_ending(qev->ev, event_type);
if (group_ending && likely(!rgi->worker_error)) if (group_ending && likely(!rgi->worker_error))
{ {

View File

@@ -374,6 +374,9 @@ int init_slave()
if (run_slave_init_thread()) if (run_slave_init_thread())
return 1; return 1;
if (global_rpl_thread_pool.init(opt_slave_parallel_threads))
return 1;
/* /*
This is called when mysqld starts. Before client connections are This is called when mysqld starts. Before client connections are
accepted. However bootstrap may conflict with us if it does START SLAVE. accepted. However bootstrap may conflict with us if it does START SLAVE.
@@ -407,9 +410,6 @@ int init_slave()
goto err; goto err;
} }
if (global_rpl_thread_pool.init(opt_slave_parallel_threads))
return 1;
/* /*
If --slave-skip-errors=... was not used, the string value for the If --slave-skip-errors=... was not used, the string value for the
system variable has not been set up yet. Do it now. system variable has not been set up yet. Do it now.
@@ -5691,6 +5691,18 @@ static int queue_event(Master_info* mi,const char* buf, ulong event_len)
} }
break; break;
#ifndef DBUG_OFF
case XID_EVENT:
DBUG_EXECUTE_IF("slave_discard_xid_for_gtid_0_x_1000",
{
/* Inject an event group that is missing its XID commit event. */
if (mi->last_queued_gtid.domain_id == 0 &&
mi->last_queued_gtid.seq_no == 1000)
goto skip_relay_logging;
});
/* Fall through to default case ... */
#endif
default: default:
default_action: default_action:
if (mi->using_gtid != Master_info::USE_GTID_NO && mi->gtid_event_seen) if (mi->using_gtid != Master_info::USE_GTID_NO && mi->gtid_event_seen)

View File

@@ -9879,7 +9879,6 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
List<LEX_USER> user_list; List<LEX_USER> user_list;
bool result; bool result;
ACL_USER *au; ACL_USER *au;
char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
Dummy_error_handler error_handler; Dummy_error_handler error_handler;
DBUG_ENTER("sp_grant_privileges"); DBUG_ENTER("sp_grant_privileges");
@@ -9920,33 +9919,10 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
if(au) if(au)
{ {
if (au->salt_len)
{
if (au->salt_len == SCRAMBLE_LENGTH)
{
make_password_from_salt(passwd_buff, au->salt);
combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
}
else if (au->salt_len == SCRAMBLE_LENGTH_323)
{
make_password_from_salt_323(passwd_buff, (ulong *) au->salt);
combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
}
else
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_PASSWD_LENGTH,
ER(ER_PASSWD_LENGTH), SCRAMBLED_PASSWORD_CHAR_LENGTH);
return TRUE;
}
combo->password.str= passwd_buff;
}
if (au->plugin.str != native_password_plugin_name.str && if (au->plugin.str != native_password_plugin_name.str &&
au->plugin.str != old_password_plugin_name.str) au->plugin.str != old_password_plugin_name.str)
{
combo->plugin= au->plugin; combo->plugin= au->plugin;
combo->auth= au->auth_string; combo->auth= au->auth_string;
}
} }
if (user_list.push_back(combo)) if (user_list.push_back(combo))

View File

@@ -2499,11 +2499,15 @@ mysql_execute_command(THD *thd)
according to slave filtering rules. according to slave filtering rules.
Returning success without producing any errors in this case. Returning success without producing any errors in this case.
*/ */
DBUG_RETURN(0); if (!thd->lex->check_exists)
DBUG_RETURN(0);
/*
DROP TRIGGER IF NOT EXISTS will return without an error later
after possibly writing the query to a binlog
*/
} }
else // force searching in slave.cc:tables_ok()
// force searching in slave.cc:tables_ok() all_tables->updating= 1;
all_tables->updating= 1;
} }
/* /*

View File

@@ -1948,6 +1948,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
slave_connection_state until_gtid_state_obj; slave_connection_state until_gtid_state_obj;
rpl_gtid error_gtid; rpl_gtid error_gtid;
binlog_send_info info(thd, packet, flags, log_file_name); binlog_send_info info(thd, packet, flags, log_file_name);
bool has_transmit_started= false;
int old_max_allowed_packet= thd->variables.max_allowed_packet; int old_max_allowed_packet= thd->variables.max_allowed_packet;
@@ -2007,16 +2008,6 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
DBUG_SET("+d,corrupt_read_log_event2"); DBUG_SET("+d,corrupt_read_log_event2");
}); });
if (global_system_variables.log_warnings > 1)
sql_print_information("Start binlog_dump to slave_server(%lu), pos(%s, %lu)",
thd->variables.server_id, log_ident, (ulong)pos);
if (RUN_HOOK(binlog_transmit, transmit_start, (thd, flags, log_ident, pos)))
{
errmsg= "Failed to run hook 'transmit_start'";
my_errno= ER_UNKNOWN_ERROR;
goto err;
}
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2)) if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2))
{ {
@@ -2113,6 +2104,17 @@ impossible position";
goto err; goto err;
} }
if (global_system_variables.log_warnings > 1)
sql_print_information("Start binlog_dump to slave_server(%lu), pos(%s, %lu)",
thd->variables.server_id, log_ident, (ulong)pos);
if (RUN_HOOK(binlog_transmit, transmit_start, (thd, flags, log_ident, pos)))
{
errmsg= "Failed to run hook 'transmit_start'";
my_errno= ER_UNKNOWN_ERROR;
goto err;
}
has_transmit_started= true;
/* reset transmit packet for the fake rotate event below */ /* reset transmit packet for the fake rotate event below */
if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg)) if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
goto err; goto err;
@@ -2680,7 +2682,8 @@ end:
end_io_cache(&log); end_io_cache(&log);
mysql_file_close(file, MYF(MY_WME)); mysql_file_close(file, MYF(MY_WME));
RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags)); if (has_transmit_started)
RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
my_eof(thd); my_eof(thd);
THD_STAGE_INFO(thd, stage_waiting_to_finalize_termination); THD_STAGE_INFO(thd, stage_waiting_to_finalize_termination);
mysql_mutex_lock(&LOCK_thread_count); mysql_mutex_lock(&LOCK_thread_count);
@@ -2749,7 +2752,8 @@ err:
else else
strcpy(error_text, errmsg); strcpy(error_text, errmsg);
end_io_cache(&log); end_io_cache(&log);
RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags)); if (has_transmit_started)
RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
/* /*
Exclude iteration through thread list Exclude iteration through thread list
this is needed for purge_logs() - it will iterate through this is needed for purge_logs() - it will iterate through

View File

@@ -4958,7 +4958,18 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array, KEY_FIELD *key_field)
} }
#define FT_KEYPART (MAX_REF_PARTS+10) /*
A key part number that means we're using a fulltext scan.
In order not to confuse it with regular equalities, we need to pick
a number that's greater than MAX_REF_PARTS.
Hash Join code stores field->field_index in KEYUSE::keypart, so the
number needs to be bigger than MAX_FIELDS, also.
CAUTION: sql_test.cc has its own definition of FT_KEYPART.
*/
#define FT_KEYPART (MAX_FIELDS+10)
static bool static bool
add_ft_keys(DYNAMIC_ARRAY *keyuse_array, add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
@@ -7452,7 +7463,11 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
fldno= table->key_info[key].key_part[keyparts-1].fieldnr - 1; fldno= table->key_info[key].key_part[keyparts-1].fieldnr - 1;
if (keyuse->val->const_item()) if (keyuse->val->const_item())
{ {
sel /= table->field[fldno]->cond_selectivity; if (table->field[fldno]->cond_selectivity > 0)
{
sel /= table->field[fldno]->cond_selectivity;
set_if_smaller(sel, 1.0);
}
/* /*
TODO: we could do better here: TODO: we could do better here:
1. cond_selectivity might be =1 (the default) because quick 1. cond_selectivity might be =1 (the default) because quick
@@ -7506,7 +7521,10 @@ double table_cond_selectivity(JOIN *join, uint idx, JOIN_TAB *s,
if (!(next_field->table->map & rem_tables) && next_field->table != table) if (!(next_field->table->map & rem_tables) && next_field->table != table)
{ {
if (field->cond_selectivity > 0) if (field->cond_selectivity > 0)
{
sel/= field->cond_selectivity; sel/= field->cond_selectivity;
set_if_smaller(sel, 1.0);
}
break; break;
} }
} }

View File

@@ -220,7 +220,7 @@ TEST_join(JOIN *join)
} }
#define FT_KEYPART (MAX_REF_PARTS+10) #define FT_KEYPART (MAX_FIELDS+10)
void print_keyuse(KEYUSE *keyuse) void print_keyuse(KEYUSE *keyuse)
{ {

View File

@@ -13404,7 +13404,12 @@ literal:
| UNDERSCORE_CHARSET hex_or_bin_String | UNDERSCORE_CHARSET hex_or_bin_String
{ {
Item_string_with_introducer *item_str; Item_string_with_introducer *item_str;
item_str= new (thd->mem_root) Item_string_with_introducer($2, $1); /*
Pass NULL as name. Name will be set in the "select_item" rule and
will include the introducer and the original hex/bin notation.
*/
item_str= new (thd->mem_root)
Item_string_with_introducer(NULL, $2->ptr(), $2->length(), $1);
if (!item_str || !item_str->check_well_formed_result(true)) if (!item_str || !item_str->check_well_formed_result(true))
MYSQL_YYABORT; MYSQL_YYABORT;

View File

@@ -21,9 +21,9 @@ ha_connect.cc connect.cc user_connect.cc mycat.cc
fmdlex.c osutil.c plugutil.c rcmsg.c rcmsg.h fmdlex.c osutil.c plugutil.c rcmsg.c rcmsg.h
array.cpp blkfil.cpp colblk.cpp csort.cpp array.cpp blkfil.cpp colblk.cpp csort.cpp
filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamvct.cpp filamzip.cpp filamap.cpp filamdbf.cpp filamfix.cpp filamtxt.cpp filamvct.cpp filamzip.cpp
filter.cpp json.cpp maputil.cpp myutil.cpp plgdbutl.cpp reldef.cpp tabcol.cpp filter.cpp json.cpp jsonudf.cpp maputil.cpp myutil.cpp plgdbutl.cpp reldef.cpp
tabdos.cpp tabfix.cpp tabfmt.cpp tabjson.cpp table.cpp tabmul.cpp taboccur.cpp tabcol.cpp tabdos.cpp tabfix.cpp tabfmt.cpp tabjson.cpp table.cpp tabmul.cpp
tabpivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp tabvct.cpp tabvir.cpp taboccur.cpp tabpivot.cpp tabsys.cpp tabtbl.cpp tabutil.cpp tabvct.cpp tabvir.cpp
tabxcl.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp tabxcl.cpp valblk.cpp value.cpp xindex.cpp xobject.cpp
array.h blkfil.h block.h catalog.h checklvl.h colblk.h connect.h csort.h array.h blkfil.h block.h catalog.h checklvl.h colblk.h connect.h csort.h

View File

@@ -50,6 +50,7 @@ class DllExport ARRAY : public XOBJECT, public CSORT { // Array descblock
// void SetCorrel(bool b) {Correlated = b;} // void SetCorrel(bool b) {Correlated = b;}
// Methods // Methods
using XOBJECT::GetIntValue;
virtual void Reset(void) {Bot = -1;} virtual void Reset(void) {Bot = -1;}
virtual int Qcompare(int *, int *); virtual int Qcompare(int *, int *);
virtual bool Compare(PXOB) {assert(FALSE); return FALSE;} virtual bool Compare(PXOB) {assert(FALSE); return FALSE;}

View File

@@ -40,4 +40,11 @@ enum USETEMP {TMP_NO = 0, /* Never */
TMP_FORCE = 3, /* Forced for MAP tables */ TMP_FORCE = 3, /* Forced for MAP tables */
TMP_TEST = 4}; /* Testing value */ TMP_TEST = 4}; /* Testing value */
/***********************************************************************/
/* Following definitions indicate conversion of TEXT columns. */
/***********************************************************************/
enum TYPCONV {TPC_NO = 0, /* Never */
TPC_YES = 1, /* Always */
TPC_SKIP = 2}; /* Skip TEXT columns */
#endif // _CHKLVL_DEFINED_ #endif // _CHKLVL_DEFINED_

View File

@@ -469,9 +469,12 @@ RCODE CntReadNext(PGLOBAL g, PTDB tdbp)
} while (rc == RC_NF); } while (rc == RC_NF);
if (rc == RC_OK)
rc= EvalColumns(g, tdbp, false);
err: err:
g->jump_level--; g->jump_level--;
return (rc != RC_OK) ? rc : EvalColumns(g, tdbp, false); return rc;
} // end of CntReadNext } // end of CntReadNext
/***********************************************************************/ /***********************************************************************/

View File

@@ -235,7 +235,7 @@ typedef struct _global { /* Global structure */
void *Xchk; /* indexes in create/alter */ void *Xchk; /* indexes in create/alter */
short Alchecked; /* Checked for ALTER */ short Alchecked; /* Checked for ALTER */
short Mrr; /* True when doing mrr */ short Mrr; /* True when doing mrr */
short Trace; int N; /* Utility */
int jump_level; int jump_level;
jmp_buf jumper[MAX_JUMP + 2]; jmp_buf jumper[MAX_JUMP + 2];
} GLOBAL; } GLOBAL;

View File

@@ -165,23 +165,24 @@
/***********************************************************************/ /***********************************************************************/
/* Initialize the ha_connect static members. */ /* Initialize the ha_connect static members. */
/***********************************************************************/ /***********************************************************************/
#define SZCONV 8192 #define SZCONV 8192
#define SZWORK 67108864 // Default work area size 64M #define SZWORK 67108864 // Default work area size 64M
#define SZWMIN 4194304 // Minimum work area size 4M #define SZWMIN 4194304 // Minimum work area size 4M
#define JSONMAX 10 // JSON Default max grp size
extern "C" { extern "C" {
char version[]= "Version 1.03.0006 January 13, 2015"; char version[]= "Version 1.03.0006 February 06, 2015";
char compver[]= "Version 1.03.0006 " __DATE__ " " __TIME__;
#if defined(WIN32) #if defined(WIN32)
char compver[]= "Version 1.03.0006 " __DATE__ " " __TIME__;
char slash= '\\'; char slash= '\\';
#else // !WIN32 #else // !WIN32
char slash= '/'; char slash= '/';
#endif // !WIN32 #endif // !WIN32
// int trace= 0; // The general trace value // int trace= 0; // The general trace value
ulong xconv= 0; // The type conversion option // ulong xconv= 0; // The type conversion option
int zconv= 0; // The text conversion size // int zconv= 0; // The text conversion size
} // extern "C" } // extern "C"
#if defined(XMAP) #if defined(XMAP)
@@ -215,6 +216,9 @@ bool CheckSelf(PGLOBAL g, TABLE_SHARE *s, const char *host,
const char *db, char *tab, const char *src, int port); const char *db, char *tab, const char *src, int port);
bool ExactInfo(void); bool ExactInfo(void);
USETEMP UseTemp(void); USETEMP UseTemp(void);
int GetConvSize(void);
TYPCONV GetTypeConv(void);
uint GetJsonGrpSize(void);
uint GetWorkSize(void); uint GetWorkSize(void);
void SetWorkSize(uint); void SetWorkSize(uint);
extern "C" const char *msglang(void); extern "C" const char *msglang(void);
@@ -289,6 +293,44 @@ static MYSQL_THDVAR_UINT(work_size,
"Size of the CONNECT work area.", "Size of the CONNECT work area.",
NULL, NULL, SZWORK, SZWMIN, UINT_MAX, 1); NULL, NULL, SZWORK, SZWMIN, UINT_MAX, 1);
// Size used when converting TEXT columns to VARCHAR
static MYSQL_THDVAR_INT(conv_size,
PLUGIN_VAR_RQCMDARG, // opt
"Size used when converting TEXT columns.",
NULL, NULL, SZCONV, 0, 65500, 1);
/**
Type conversion:
no: Unsupported types -> TYPE_ERROR
yes: TEXT -> VARCHAR
skip: skip unsupported type columns in Discovery
*/
const char *xconv_names[]=
{
"NO", "YES", "SKIP", NullS
};
TYPELIB xconv_typelib=
{
array_elements(xconv_names) - 1, "xconv_typelib",
xconv_names, NULL
};
static MYSQL_THDVAR_ENUM(
type_conv, // name
PLUGIN_VAR_RQCMDARG, // opt
"Unsupported types conversion.", // comment
NULL, // check
NULL, // update function
0, // def (no)
&xconv_typelib); // typelib
// Estimate max number of rows for JSON aggregate functions
static MYSQL_THDVAR_UINT(json_grp_size,
PLUGIN_VAR_RQCMDARG, // opt
"max number of rows for JSON aggregate functions.",
NULL, NULL, JSONMAX, 1, INT_MAX, 1);
#if defined(XMSG) || defined(NEWMSG) #if defined(XMSG) || defined(NEWMSG)
const char *language_names[]= const char *language_names[]=
{ {
@@ -317,6 +359,9 @@ static MYSQL_THDVAR_ENUM(
extern "C" int GetTraceValue(void) {return THDVAR(current_thd, xtrace);} extern "C" int GetTraceValue(void) {return THDVAR(current_thd, xtrace);}
bool ExactInfo(void) {return THDVAR(current_thd, exact_info);} bool ExactInfo(void) {return THDVAR(current_thd, exact_info);}
USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);} USETEMP UseTemp(void) {return (USETEMP)THDVAR(current_thd, use_tempfile);}
int GetConvSize(void) {return THDVAR(current_thd, conv_size);}
TYPCONV GetTypeConv(void) {return (TYPCONV)THDVAR(current_thd, type_conv);}
uint GetJsonGrpSize(void) {return THDVAR(current_thd, json_grp_size);}
uint GetWorkSize(void) {return THDVAR(current_thd, work_size);} uint GetWorkSize(void) {return THDVAR(current_thd, work_size);}
void SetWorkSize(uint n) void SetWorkSize(uint n)
{ {
@@ -598,7 +643,11 @@ static int connect_init_func(void *p)
} }
#endif // 0 (LINUX) #endif // 0 (LINUX)
#if defined(WIN32)
sql_print_information("CONNECT: %s", compver); sql_print_information("CONNECT: %s", compver);
#else // !WIN32
sql_print_information("CONNECT: %s", version);
#endif // !WIN32
#ifdef LIBXML2_SUPPORT #ifdef LIBXML2_SUPPORT
XmlInitParserLib(); XmlInitParserLib();
@@ -934,6 +983,9 @@ ulonglong ha_connect::table_flags() const
char *GetListOption(PGLOBAL g, const char *opname, char *GetListOption(PGLOBAL g, const char *opname,
const char *oplist, const char *def) const char *oplist, const char *def)
{ {
if (!oplist)
return (char*)def;
char key[16], val[256]; char key[16], val[256];
char *pk, *pv, *pn; char *pk, *pv, *pn;
char *opval= (char*) def; char *opval= (char*) def;
@@ -997,8 +1049,12 @@ char *ha_connect::GetRealString(const char *s)
char *sv; char *sv;
if (IsPartitioned() && s) { if (IsPartitioned() && s) {
sv= (char*)PlugSubAlloc(xp->g, NULL, strlen(s) + strlen(partname)); // sv= (char*)PlugSubAlloc(xp->g, NULL, strlen(s) + strlen(partname));
// With wrong string pattern, the size of the constructed string
// can be more than strlen(s) + strlen(partname)
sv= (char*)PlugSubAlloc(xp->g, NULL, 0);
sprintf(sv, s, partname); sprintf(sv, s, partname);
PlugSubAlloc(xp->g, NULL, strlen(sv) + 1);
} else } else
sv= (char*)s; sv= (char*)s;
@@ -1064,9 +1120,16 @@ char *ha_connect::GetStringOption(char *opname, char *sdef)
} // endif Table_charset } // endif Table_charset
if (!opval && options && options->oplist) if (!opval && options && options->oplist) {
opval= GetListOption(xp->g, opname, options->oplist); opval= GetListOption(xp->g, opname, options->oplist);
if (opval && (!stricmp(opname, "connect")
|| !stricmp(opname, "tabname")
|| !stricmp(opname, "filename")))
opval = GetRealString(opval);
} // endif opval
if (!opval) { if (!opval) {
if (sdef && !strcmp(sdef, "*")) { if (sdef && !strcmp(sdef, "*")) {
// Return the handler default value // Return the handler default value
@@ -2467,6 +2530,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
char *body= filp->Body; char *body= filp->Body;
unsigned int i; unsigned int i;
bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC); bool ismul= false, x= (tty == TYPE_AM_MYX || tty == TYPE_AM_XDBC);
bool nonul= (tty == TYPE_AM_ODBC && (tdbp->GetMode() == MODE_INSERT ||
tdbp->GetMode() == MODE_DELETE));
OPVAL vop= OP_XX; OPVAL vop= OP_XX;
if (!cond) if (!cond)
@@ -2484,7 +2549,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
if (trace) if (trace)
htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(), htrc("Cond: Ftype=%d name=%s\n", cond_item->functype(),
cond_item->func_name()); cond_item->func_name());
switch (cond_item->functype()) { switch (cond_item->functype()) {
case Item_func::COND_AND_FUNC: vop= OP_AND; break; case Item_func::COND_AND_FUNC: vop= OP_AND; break;
@@ -2503,7 +2568,7 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
for (i= 0; i < arglist->elements; i++) for (i= 0; i < arglist->elements; i++)
if ((subitem= li++)) { if ((subitem= li++)) {
if (!CheckCond(g, filp, tty, subitem)) { if (!CheckCond(g, filp, tty, subitem)) {
if (vop == OP_OR) if (vop == OP_OR || nonul)
return NULL; return NULL;
else else
*p2= 0; *p2= 0;
@@ -2599,6 +2664,8 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
if (trace) { if (trace) {
htrc("Field index=%d\n", pField->field->field_index); htrc("Field index=%d\n", pField->field->field_index);
htrc("Field name=%s\n", pField->field->field_name); htrc("Field name=%s\n", pField->field->field_name);
htrc("Field type=%d\n", pField->field->type());
htrc("Field_type=%d\n", args[i]->field_type());
} // endif trace } // endif trace
// IN and BETWEEN clauses should be col VOP list // IN and BETWEEN clauses should be col VOP list
@@ -2618,8 +2685,9 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
char buff[256]; char buff[256];
String *res, tmp(buff, sizeof(buff), &my_charset_bin); String *res, tmp(buff, sizeof(buff), &my_charset_bin);
Item_basic_constant *pval= (Item_basic_constant *)args[i]; Item_basic_constant *pval= (Item_basic_constant *)args[i];
Item::Type type= args[i]->real_type();
switch (args[i]->real_type()) { switch (type) {
case COND::STRING_ITEM: case COND::STRING_ITEM:
case COND::INT_ITEM: case COND::INT_ITEM:
case COND::REAL_ITEM: case COND::REAL_ITEM:
@@ -2644,10 +2712,64 @@ PCFIL ha_connect::CheckCond(PGLOBAL g, PCFIL filp, AMT tty, Item *cond)
if (!x) { if (!x) {
// Append the value to the filter // Append the value to the filter
if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) switch (args[i]->field_type()) {
strcat(strncat(strcat(body, "'"), res->ptr(), res->length()), "'"); case MYSQL_TYPE_TIMESTAMP:
else case MYSQL_TYPE_DATETIME:
strncat(body, res->ptr(), res->length()); if (tty == TYPE_AM_ODBC) {
strcat(body, "{ts '");
strcat(strncat(body, res->ptr(), res->length()), "'}");
break;
} // endif ODBC
case MYSQL_TYPE_DATE:
if (tty == TYPE_AM_ODBC) {
strcat(body, "{d '");
strcat(strncat(body, res->ptr(), res->length()), "'}");
break;
} // endif ODBC
case MYSQL_TYPE_TIME:
if (tty == TYPE_AM_ODBC) {
strcat(body, "{t '");
strcat(strncat(body, res->ptr(), res->length()), "'}");
break;
} // endif ODBC
case MYSQL_TYPE_VARCHAR:
if (tty == TYPE_AM_ODBC && i) {
switch (args[0]->field_type()) {
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
strcat(body, "{ts '");
strncat(body, res->ptr(), res->length());
strcat(body, "'}");
break;
case MYSQL_TYPE_DATE:
strcat(body, "{d '");
strncat(body, res->ptr(), res->length());
strcat(body, "'}");
break;
case MYSQL_TYPE_TIME:
strcat(body, "{t '");
strncat(body, res->ptr(), res->length());
strcat(body, "'}");
break;
default:
strcat(body, "'");
strncat(body, res->ptr(), res->length());
strcat(body, "'");
} // endswitch field type
} else {
strcat(body, "'");
strncat(body, res->ptr(), res->length());
strcat(body, "'");
} // endif tty
break;
default:
strncat(body, res->ptr(), res->length());
} // endswitch field type
} else { } else {
if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) { if (args[i]->field_type() == MYSQL_TYPE_VARCHAR) {
@@ -2753,7 +2875,7 @@ const COND *ha_connect::cond_push(const COND *cond)
} else if (x && cond) } else if (x && cond)
tdbp->SetCondFil(filp); // Wrong filter tdbp->SetCondFil(filp); // Wrong filter
} else } else if (tty != TYPE_AM_JSN && tty != TYPE_AM_JSON)
tdbp->SetFilter(CondFilter(g, (Item *)cond)); tdbp->SetFilter(CondFilter(g, (Item *)cond));
fin: fin:
@@ -4620,7 +4742,7 @@ static bool add_field(String *sql, const char *field_name, int typ,
char *dft, char *xtra, int flag, bool dbf, char v) char *dft, char *xtra, int flag, bool dbf, char v)
{ {
char var = (len > 255) ? 'V' : v; char var = (len > 255) ? 'V' : v;
bool error= false; bool q, error= false;
const char *type= PLGtoMYSQLtype(typ, dbf, var); const char *type= PLGtoMYSQLtype(typ, dbf, var);
error|= sql->append('`'); error|= sql->append('`');
@@ -4661,7 +4783,12 @@ static bool add_field(String *sql, const char *field_name, int typ,
if (dft && *dft) { if (dft && *dft) {
error|= sql->append(" DEFAULT "); error|= sql->append(" DEFAULT ");
if (!IsTypeNum(typ)) { if (typ == TYPE_DATE)
q = (strspn(dft, "0123456789 -:/") == strlen(dft));
else
q = !IsTypeNum(typ);
if (q) {
error|= sql->append("'"); error|= sql->append("'");
error|= sql->append_for_single_quote(dft, strlen(dft)); error|= sql->append_for_single_quote(dft, strlen(dft));
error|= sql->append("'"); error|= sql->append("'");
@@ -4831,6 +4958,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
int port= 0, hdr= 0, mxr __attribute__((unused))= 0, mxe= 0, rc= 0; int port= 0, hdr= 0, mxr __attribute__((unused))= 0, mxe= 0, rc= 0;
int cop __attribute__((unused)) = 0; int cop __attribute__((unused)) = 0;
#if defined(ODBC_SUPPORT) #if defined(ODBC_SUPPORT)
POPARM sop = NULL;
char *ucnc = NULL;
bool cnc= false;
int cto= -1, qto= -1; int cto= -1, qto= -1;
#endif // ODBC_SUPPORT #endif // ODBC_SUPPORT
uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL); uint tm, fnc= FNC_NO, supfnc= (FNC_NO | FNC_COL);
@@ -4875,7 +5005,8 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
if (topt->oplist) { if (topt->oplist) {
host= GetListOption(g, "host", topt->oplist, "localhost"); host= GetListOption(g, "host", topt->oplist, "localhost");
user= GetListOption(g, "user", topt->oplist, "root"); user= GetListOption(g, "user", topt->oplist,
(ttp == TAB_ODBC ? NULL : "root"));
// Default value db can come from the DBNAME=xxx option. // Default value db can come from the DBNAME=xxx option.
db= GetListOption(g, "database", topt->oplist, db); db= GetListOption(g, "database", topt->oplist, db);
col= GetListOption(g, "colist", topt->oplist, col); col= GetListOption(g, "colist", topt->oplist, col);
@@ -4894,6 +5025,9 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0")); mxr= atoi(GetListOption(g,"maxres", topt->oplist, "0"));
cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1")); cto= atoi(GetListOption(g,"ConnectTimeout", topt->oplist, "-1"));
qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1")); qto= atoi(GetListOption(g,"QueryTimeout", topt->oplist, "-1"));
if ((ucnc= GetListOption(g, "UseDSN", topt->oplist)))
cnc= (!*ucnc || *ucnc == 'y' || *ucnc == 'Y' || atoi(ucnc) != 0);
#endif #endif
mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0")); mxe= atoi(GetListOption(g,"maxerr", topt->oplist, "0"));
#if defined(PROMPT_OK) #if defined(PROMPT_OK)
@@ -4901,7 +5035,7 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
#endif // PROMPT_OK #endif // PROMPT_OK
} else { } else {
host= "localhost"; host= "localhost";
user= "root"; user= (ttp == TAB_ODBC ? NULL : "root");
} // endif option_list } // endif option_list
if (!(shm= (char*)db)) if (!(shm= (char*)db))
@@ -4978,10 +5112,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
} // endif dsn } // endif dsn
#endif // PROMPT_OK #endif // PROMPT_OK
} else if (!dsn) } else if (!dsn) {
sprintf(g->Message, "Missing %s connection string", topt->type); sprintf(g->Message, "Missing %s connection string", topt->type);
else } else {
// Store ODBC additional parameters
sop= (POPARM)PlugSubAlloc(g, NULL, sizeof(ODBCPARM));
sop->User= (char*)user;
sop->Pwd= (char*)pwd;
sop->Cto= cto;
sop->Qto= qto;
sop->UseCnc= cnc;
ok= true; ok= true;
} // endif's
supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER); supfnc |= (FNC_TABLE | FNC_DSN | FNC_DRIVER);
break; break;
@@ -5112,15 +5254,15 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
case FNC_NO: case FNC_NO:
case FNC_COL: case FNC_COL:
if (src) { if (src) {
qrp= ODBCSrcCols(g, dsn, (char*)src, cto, qto); qrp= ODBCSrcCols(g, dsn, (char*)src, sop);
src= NULL; // for next tests src= NULL; // for next tests
} else } else
qrp= ODBCColumns(g, dsn, shm, tab, NULL, qrp= ODBCColumns(g, dsn, shm, tab, NULL,
mxr, cto, qto, fnc == FNC_COL); mxr, fnc == FNC_COL, sop);
break; break;
case FNC_TABLE: case FNC_TABLE:
qrp= ODBCTables(g, dsn, shm, tab, mxr, cto, qto, true); qrp= ODBCTables(g, dsn, shm, tab, mxr, true, sop);
break; break;
case FNC_DSN: case FNC_DSN:
qrp= ODBCDataSources(g, mxr, true); qrp= ODBCDataSources(g, mxr, true);
@@ -5237,9 +5379,10 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
for (crp= qrp->Colresp; crp; crp= crp->Next) for (crp= qrp->Colresp; crp; crp= crp->Next)
switch (crp->Fld) { switch (crp->Fld) {
case FLD_NAME: case FLD_NAME:
if (ttp == TAB_CSV && topt->data_charset && if (ttp == TAB_PRX ||
(ttp == TAB_CSV && topt->data_charset &&
(!stricmp(topt->data_charset, "UTF8") || (!stricmp(topt->data_charset, "UTF8") ||
!stricmp(topt->data_charset, "UTF-8"))) !stricmp(topt->data_charset, "UTF-8"))))
cnm= crp->Kdata->GetCharValue(i); cnm= crp->Kdata->GetCharValue(i);
else else
cnm= encode(g, crp->Kdata->GetCharValue(i)); cnm= encode(g, crp->Kdata->GetCharValue(i));
@@ -5299,9 +5442,18 @@ static int connect_assisted_discovery(handlerton *hton, THD* thd,
// typ must be PLG type, not SQL type // typ must be PLG type, not SQL type
if (!(plgtyp= TranslateSQLType(typ, dec, prec, v))) { if (!(plgtyp= TranslateSQLType(typ, dec, prec, v))) {
sprintf(g->Message, "Unsupported SQL type %d", typ); if (GetTypeConv() == TPC_SKIP) {
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0)); // Skip this column
goto err; sprintf(g->Message, "Column %s skipped (unsupported type %d)",
cnm, typ);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN, 0, g->Message);
continue;
} else {
sprintf(g->Message, "Unsupported SQL type %d", typ);
my_message(ER_UNKNOWN_ERROR, g->Message, MYF(0));
goto err;
} // endif type_conv
} else } else
typ= plgtyp; typ= plgtyp;
@@ -6341,58 +6493,6 @@ struct st_mysql_storage_engine connect_storage_engine=
/***********************************************************************/ /***********************************************************************/
/* CONNECT global variables definitions. */ /* CONNECT global variables definitions. */
/***********************************************************************/ /***********************************************************************/
// Size used when converting TEXT columns to VARCHAR
#if defined(_DEBUG)
static MYSQL_SYSVAR_INT(conv_size, zconv,
PLUGIN_VAR_RQCMDARG, // opt
"Size used when converting TEXT columns.",
NULL, NULL, SZCONV, 0, 65500, 1);
#else
static MYSQL_SYSVAR_INT(conv_size, zconv,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, // opt
"Size used when converting TEXT columns.",
NULL, NULL, SZCONV, 0, 65500, 1);
#endif
/**
Type conversion:
no: Unsupported types -> TYPE_ERROR
yes: TEXT -> VARCHAR
skip: skip unsupported type columns in Discovery
*/
const char *xconv_names[]=
{
"NO", "YES", "SKIP", NullS
};
TYPELIB xconv_typelib=
{
array_elements(xconv_names) - 1, "xconv_typelib",
xconv_names, NULL
};
#if defined(_DEBUG)
static MYSQL_SYSVAR_ENUM(
type_conv, // name
xconv, // varname
PLUGIN_VAR_RQCMDARG, // opt
"Unsupported types conversion.", // comment
NULL, // check
NULL, // update function
0, // def (no)
&xconv_typelib); // typelib
#else
static MYSQL_SYSVAR_ENUM(
type_conv, // name
xconv, // varname
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Unsupported types conversion.", // comment
NULL, // check
NULL, // update function
0, // def (no)
&xconv_typelib); // typelib
#endif
#if defined(XMAP) #if defined(XMAP)
// Using file mapping for indexes if true // Using file mapping for indexes if true
static MYSQL_SYSVAR_BOOL(indx_map, xmap, PLUGIN_VAR_RQCMDARG, static MYSQL_SYSVAR_BOOL(indx_map, xmap, PLUGIN_VAR_RQCMDARG,
@@ -6425,6 +6525,7 @@ static struct st_mysql_sys_var* connect_system_variables[]= {
#if defined(XMSG) #if defined(XMSG)
MYSQL_SYSVAR(errmsg_dir_path), MYSQL_SYSVAR(errmsg_dir_path),
#endif // XMSG #endif // XMSG
MYSQL_SYSVAR(json_grp_size),
NULL NULL
}; };

View File

@@ -34,7 +34,7 @@
/***********************************************************************/ /***********************************************************************/
PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma) PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
{ {
int i; int i, rc;
bool b = false; bool b = false;
PJSON jsp = NULL; PJSON jsp = NULL;
STRG src; STRG src;
@@ -48,22 +48,33 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
src.str = s; src.str = s;
src.len = len; src.len = len;
// Save stack and allocation environment and prepare error return
if (g->jump_level == MAX_JUMP) {
strcpy(g->Message, MSG(TOO_MANY_JUMPS));
return NULL;
} // endif jump_level
if ((rc= setjmp(g->jumper[++g->jump_level])) != 0) {
goto err;
} // endif rc
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
switch (s[i]) { switch (s[i]) {
case '[': case '[':
if (jsp) { if (jsp) {
strcpy(g->Message, "More than one item in file"); strcpy(g->Message, "More than one item in file");
return NULL; goto err;
} else if (!(jsp = ParseArray(g, ++i, src))) } else if (!(jsp = ParseArray(g, ++i, src)))
return NULL; goto err;
break; break;
case '{': case '{':
if (jsp) { if (jsp) {
strcpy(g->Message, "More than one item in file"); strcpy(g->Message, "More than one item in file");
return NULL; goto err;
} else if (!(jsp = ParseObject(g, ++i, src))) } else if (!(jsp = ParseObject(g, ++i, src)))
return NULL; goto err;
break; break;
case ' ': case ' ':
case '\t': case '\t':
@@ -79,7 +90,12 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
} // endif pretty } // endif pretty
sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty); sprintf(g->Message, "Unexpected ',' (pretty=%d)", pretty);
return NULL; goto err;
case '"':
if (!(jsp = ParseValue(g, i, src)))
goto err;
break;
case '(': case '(':
b = true; b = true;
break; break;
@@ -92,13 +108,18 @@ PJSON ParseJson(PGLOBAL g, char *s, int len, int pretty, bool *comma)
default: default:
sprintf(g->Message, "Bad '%c' character near %.*s", sprintf(g->Message, "Bad '%c' character near %.*s",
s[i], ARGS); s[i], ARGS);
return NULL; goto err;
}; // endswitch s[i] }; // endswitch s[i]
if (!jsp) if (!jsp)
sprintf(g->Message, "Invalid Json string '%.*s'", 50, s); sprintf(g->Message, "Invalid Json string '%.*s'", 50, s);
g->jump_level--;
return jsp; return jsp;
err:
g->jump_level--;
return NULL;
} // end of ParseJson } // end of ParseJson
/***********************************************************************/ /***********************************************************************/
@@ -312,18 +333,25 @@ err:
/***********************************************************************/ /***********************************************************************/
char *ParseString(PGLOBAL g, int& i, STRG& src) char *ParseString(PGLOBAL g, int& i, STRG& src)
{ {
char *p, *s = src.str; char *s = src.str;
int n = 0, len = src.len; uchar *p;
int n = 0, len = src.len;
// Be sure of memory availability
if (len + 1 - i > (signed)((PPOOLHEADER)g->Sarea)->FreeBlk) {
strcpy(g->Message, "ParseString: Out of memory");
return NULL;
} // endif len
// The size to allocate is not known yet // The size to allocate is not known yet
p = (char*)PlugSubAlloc(g, NULL, 0); p = (uchar*)PlugSubAlloc(g, NULL, 0);
for (; i < len; i++) for (; i < len; i++)
switch (s[i]) { switch (s[i]) {
case '"': case '"':
p[n++] = 0; p[n++] = 0;
PlugSubAlloc(g, NULL, n); PlugSubAlloc(g, NULL, n);
return p; return (char*)p;
case '\\': case '\\':
if (++i < len) { if (++i < len) {
if (s[i] == 'u') { if (s[i] == 'u') {
@@ -504,8 +532,11 @@ PSZ Serialize(PGLOBAL g, PJSON jsp, FILE *fs, int pretty)
err = (b && jp->WriteChr('\t')); err = (b && jp->WriteChr('\t'));
err |= SerializeObject(jp, (PJOB)jsp); err |= SerializeObject(jp, (PJOB)jsp);
break; break;
case TYPE_JVAL:
err = SerializeValue(jp, (PJVAL)jsp);
break;
default: default:
strcpy(g->Message, "json tree is not an Array or an Object"); strcpy(g->Message, "Invalid json tree");
} // endswitch Type } // endswitch Type
if (fs) { if (fs) {
@@ -575,9 +606,9 @@ bool SerializeObject(JOUT *js, PJOB jobp)
else if (js->WriteChr(',')) else if (js->WriteChr(','))
return true; return true;
if (js->WriteChr('\"') || if (js->WriteChr('"') ||
js->WriteStr(pair->Key) || js->WriteStr(pair->Key) ||
js->WriteChr('\"') || js->WriteChr('"') ||
js->WriteChr(':') || js->WriteChr(':') ||
SerializeValue(js, pair->Val)) SerializeValue(js, pair->Val))
return true; return true;
@@ -675,12 +706,13 @@ bool JOUTSTR::Escape(const char *s)
for (unsigned int i = 0; i < strlen(s); i++) for (unsigned int i = 0; i < strlen(s); i++)
switch (s[i]) { switch (s[i]) {
case '"':
case '\\':
case '\t': case '\t':
case '\n': case '\n':
case '\r': case '\r':
case '\b': case '\b':
case '\f': case '\f': WriteChr('\\');
case '"': WriteChr('\\');
// passthru // passthru
default: default:
WriteChr(s[i]); WriteChr(s[i]);
@@ -723,12 +755,13 @@ bool JOUTFILE::Escape(const char *s)
for (unsigned int i = 0; i < strlen(s); i++) for (unsigned int i = 0; i < strlen(s); i++)
switch (s[i]) { switch (s[i]) {
case '\t': fputs("\\t", Stream); break; case '"': fputs("\\\"", Stream); break;
case '\n': fputs("\\n", Stream); break; case '\\': fputs("\\\\", Stream); break;
case '\r': fputs("\\r", Stream); break; case '\t': fputs("\\t", Stream); break;
case '\b': fputs("\\b", Stream); break; case '\n': fputs("\\n", Stream); break;
case '\f': fputs("\\f", Stream); break; case '\r': fputs("\\r", Stream); break;
case '"': fputs("\\\"", Stream); break; case '\b': fputs("\\b", Stream); break;
case '\f': fputs("\\f", Stream); break;
default: default:
fputc(s[i], Stream); fputc(s[i], Stream);
break; break;
@@ -1053,3 +1086,27 @@ PSZ JVALUE::GetString(void)
return (Value) ? Value->GetCharString(buf) : NULL; return (Value) ? Value->GetCharString(buf) : NULL;
} // end of GetString } // end of GetString
/***********************************************************************/
/* Set the Value's value as the given integer. */
/***********************************************************************/
void JVALUE::SetInteger(PGLOBAL g, int n)
{
Value = AllocateValue(g, &n, TYPE_INT);
} // end of AddInteger
/***********************************************************************/
/* Set the Value's value as the given DOUBLE. */
/***********************************************************************/
void JVALUE::SetFloat(PGLOBAL g, double f)
{
Value = AllocateValue(g, &f, TYPE_DOUBLE, 6);
} // end of AddFloat
/***********************************************************************/
/* Set the Value's value as the given string. */
/***********************************************************************/
void JVALUE::SetString(PGLOBAL g, PSZ s)
{
Value = AllocateValue(g, s, TYPE_STRING);
} // end of AddFloat

View File

@@ -18,7 +18,8 @@ enum JTYP {TYPE_STRG = 1,
TYPE_BOOL = 4, TYPE_BOOL = 4,
TYPE_INTG = 7, TYPE_INTG = 7,
TYPE_JSON = 12, TYPE_JSON = 12,
TYPE_JAR, TYPE_JOB, TYPE_JAR,
TYPE_JOB,
TYPE_JVAL}; TYPE_JVAL};
class JOUT; class JOUT;
@@ -156,6 +157,9 @@ class JSON : public BLOCK {
virtual void SetValue(PGLOBAL g, PJVAL jvp, PSZ key) {X} virtual void SetValue(PGLOBAL g, PJVAL jvp, PSZ key) {X}
virtual void SetValue(PVAL valp) {X} virtual void SetValue(PVAL valp) {X}
virtual void SetValue(PJSON jsp) {X} virtual void SetValue(PJSON jsp) {X}
virtual void SetString(PGLOBAL g, PSZ s) {X}
virtual void SetInteger(PGLOBAL g, int n) {X}
virtual void SetFloat(PGLOBAL g, double f) {X}
virtual bool DeleteValue(int i) {X return true;} virtual bool DeleteValue(int i) {X return true;}
protected: protected:
@@ -171,6 +175,8 @@ class JOBJECT : public JSON {
public: public:
JOBJECT(void) : JSON() {First = Last = NULL;} JOBJECT(void) : JSON() {First = Last = NULL;}
using JSON::GetValue;
using JSON::SetValue;
virtual void Clear(void) {First = Last = NULL; Size = 0;} virtual void Clear(void) {First = Last = NULL; Size = 0;}
virtual JTYP GetType(void) {return TYPE_JOB;} virtual JTYP GetType(void) {return TYPE_JOB;}
virtual PJPR AddPair(PGLOBAL g, PSZ key); virtual PJPR AddPair(PGLOBAL g, PSZ key);
@@ -192,6 +198,8 @@ class JARRAY : public JSON {
public: public:
JARRAY(void) : JSON() {Alloc = 0; First = Last = NULL; Mvals = NULL;} JARRAY(void) : JSON() {Alloc = 0; First = Last = NULL; Mvals = NULL;}
using JSON::GetValue;
using JSON::SetValue;
virtual void Clear(void) {First = Last = NULL; Size = 0;} virtual void Clear(void) {First = Last = NULL; Size = 0;}
virtual JTYP GetType(void) {return TYPE_JAR;} virtual JTYP GetType(void) {return TYPE_JAR;}
virtual PJAR GetArray(void) {return this;} virtual PJAR GetArray(void) {return this;}
@@ -223,6 +231,8 @@ class JVALUE : public JSON {
{Jsp = jsp; Value = NULL; Next = NULL; Del = false;} {Jsp = jsp; Value = NULL; Next = NULL; Del = false;}
JVALUE(PGLOBAL g, PVAL valp); JVALUE(PGLOBAL g, PVAL valp);
using JSON::GetValue;
using JSON::SetValue;
virtual void Clear(void) virtual void Clear(void)
{Jsp = NULL; Value = NULL; Next = NULL; Del = false; Size = 0;} {Jsp = NULL; Value = NULL; Next = NULL; Del = false; Size = 0;}
virtual JTYP GetType(void) {return TYPE_JVAL;} virtual JTYP GetType(void) {return TYPE_JVAL;}
@@ -236,6 +246,9 @@ class JVALUE : public JSON {
virtual PSZ GetString(void); virtual PSZ GetString(void);
virtual void SetValue(PVAL valp) {Value = valp;} virtual void SetValue(PVAL valp) {Value = valp;}
virtual void SetValue(PJSON jsp) {Jsp = jsp;} virtual void SetValue(PJSON jsp) {Jsp = jsp;}
virtual void SetString(PGLOBAL g, PSZ s);
virtual void SetInteger(PGLOBAL g, int n);
virtual void SetFloat(PGLOBAL g, double f);
protected: protected:
PJSON Jsp; // To the json value PJSON Jsp; // To the json value

582
storage/connect/jsonudf.cpp Normal file
View File

@@ -0,0 +1,582 @@
/************* jsonudf C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: jsonudf Version 1.0 */
/* (C) Copyright to the author Olivier BERTRAND 2015 */
/* This program are the JSON User Defined Functions . */
/***********************************************************************/
/***********************************************************************/
/* Include relevant sections of the MariaDB header file. */
/***********************************************************************/
#include <my_global.h>
#include <mysqld.h>
#include <mysql.h>
#include <sql_error.h>
#include "global.h"
#include "plgdbsem.h"
#include "json.h"
#define MEMFIX 512
uint GetJsonGrpSize(void);
extern "C" {
DllExport my_bool Json_Value_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Value(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *);
DllExport void Json_Value_deinit(UDF_INIT*);
DllExport my_bool Json_Array_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Array(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *);
DllExport void Json_Array_deinit(UDF_INIT*);
DllExport my_bool Json_Array_Add_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Array_Add(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *);
DllExport void Json_Array_Add_deinit(UDF_INIT*);
DllExport my_bool Json_Object_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport char *Json_Object(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *);
DllExport void Json_Object_deinit(UDF_INIT*);
DllExport my_bool Json_Array_Grp_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport void Json_Array_Grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
DllExport char *Json_Array_Grp(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *);
DllExport void Json_Array_Grp_clear(UDF_INIT *, char *, char *);
DllExport void Json_Array_Grp_deinit(UDF_INIT*);
DllExport my_bool Json_Object_Grp_init(UDF_INIT*, UDF_ARGS*, char*);
DllExport void Json_Object_Grp_add(UDF_INIT *, UDF_ARGS *, char *, char *);
DllExport char *Json_Object_Grp(UDF_INIT*, UDF_ARGS*, char*,
unsigned long*, char *, char *);
DllExport void Json_Object_Grp_clear(UDF_INIT *, char *, char *);
DllExport void Json_Object_Grp_deinit(UDF_INIT*);
} // extern "C"
/***********************************************************************/
/* Allocate and initialise the memory area. */
/***********************************************************************/
static my_bool JsonInit(UDF_INIT *initid, char *message,
unsigned long reslen, unsigned long memlen)
{
PGLOBAL g = PlugInit(NULL, memlen);
if (!g) {
strcpy(message, "Allocation error");
return true;
} else if (g->Sarea_Size == 0) {
strcpy(message, g->Message);
PlugExit(g);
return true;
} else
initid->ptr = (char*)g;
initid->maybe_null = false;
initid->max_length = reslen;
return false;
} // end of Json_Object_init
/***********************************************************************/
/* Returns true if the argument is a JSON string. */
/***********************************************************************/
static my_bool IsJson(UDF_ARGS *args, int i)
{
return (args->arg_type[i] == STRING_RESULT &&
!strnicmp(args->attributes[i], "Json_", 5));
} // end of IsJson
/***********************************************************************/
/* Calculate the reslen and memlen needed by a function. */
/***********************************************************************/
static my_bool CalcLen(UDF_ARGS *args, my_bool obj,
unsigned long& reslen, unsigned long& memlen)
{
unsigned long i, k;
reslen = args->arg_count + 2;
// Calculate the result max length
for (i = 0; i < args->arg_count; i++) {
if (obj) {
if (!(k = args->attribute_lengths[i]))
k = strlen(args->attributes[i]);
reslen += (k + 3); // For quotes and :
} // endif obj
switch (args->arg_type[i]) {
case STRING_RESULT:
if (IsJson(args, i))
reslen += args->lengths[i];
else
reslen += (args->lengths[i] + 1) * 2; // Pessimistic !
break;
case INT_RESULT:
reslen += 20;
break;
case REAL_RESULT:
reslen += 31;
break;
case DECIMAL_RESULT:
reslen += (args->lengths[i] + 7); // 6 decimals
break;
case TIME_RESULT:
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
default:
// What should we do here ?
break;
} // endswitch arg_type
} // endfor i
// Calculate the amount of memory needed
memlen = MEMFIX + sizeof(JOUTSTR) + reslen;
for (i = 0; i < args->arg_count; i++) {
memlen += (args->lengths[i] + sizeof(JVALUE));
if (obj) {
if (!(k = args->attribute_lengths[i]))
k = strlen(args->attributes[i]);
memlen += (k + sizeof(JOBJECT) + sizeof(JPAIR));
} else
memlen += sizeof(JARRAY);
switch (args->arg_type[i]) {
case STRING_RESULT:
if (IsJson(args, i))
memlen += args->lengths[i] * 5; // Estimate parse memory
memlen += sizeof(TYPVAL<PSZ>);
break;
case INT_RESULT:
memlen += sizeof(TYPVAL<int>);
break;
case REAL_RESULT:
case DECIMAL_RESULT:
memlen += sizeof(TYPVAL<double>);
break;
case TIME_RESULT:
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
default:
// What should we do here ?
break;
} // endswitch arg_type
} // endfor i
return false;
} // end of CalcLen
/***********************************************************************/
/* Make a zero terminated string from the passed argument. */
/***********************************************************************/
static PSZ MakePSZ(PGLOBAL g, UDF_ARGS *args, int i)
{
if (args->args[i]) {
int n = args->lengths[i];
PSZ s = (PSZ)PlugSubAlloc(g, NULL, n + 1);
memcpy(s, args->args[i], n);
s[n] = 0;
return s;
} else
return NULL;
} // end of MakePSZ
/***********************************************************************/
/* Make a valid key from the passed argument. */
/***********************************************************************/
static PSZ MakeKey(PGLOBAL g, UDF_ARGS *args, int i)
{
int n = args->attribute_lengths[i];
bool b; // true if attribute is zero terminated
PSZ p, s = args->attributes[i];
if (s && *s && (n || *s == '\'')) {
if ((b = (!n || !s[n])))
n = strlen(s);
if (n > 5 && IsJson(args, i)) {
s += 5;
n -= 5;
} else if (*s == '\'' && s[n-1] == '\'') {
s++;
n -= 2;
b = false;
} // endif *s
if (n < 1)
return "Key";
if (!b) {
p = (PSZ)PlugSubAlloc(g, NULL, n + 1);
memcpy(p, s, n);
p[n] = 0;
s = p;
} // endif b
} // endif s
return s;
} // end of MakeKey
/***********************************************************************/
/* Make a JSON value from the passed argument. */
/***********************************************************************/
static PJVAL MakeValue(PGLOBAL g, UDF_ARGS *args, int i)
{
char *sap = args->args[i];
PJSON jsp;
PJVAL jvp = new(g) JVALUE;
if (sap) switch (args->arg_type[i]) {
case STRING_RESULT:
if (args->lengths[i]) {
if (IsJson(args, i)) {
if (!(jsp = ParseJson(g, sap, args->lengths[i], 0)))
push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0,
g->Message);
if (jsp && jsp->GetType() == TYPE_JVAL)
jvp = (PJVAL)jsp;
else
jvp->SetValue(jsp);
} else
jvp->SetString(g, MakePSZ(g, args, i));
} // endif str
break;
case INT_RESULT:
jvp->SetInteger(g, *(int*)sap);
break;
case REAL_RESULT:
jvp->SetFloat(g, *(double*)sap);
break;
case DECIMAL_RESULT:
jvp->SetFloat(g, atof(MakePSZ(g, args, i)));
break;
case TIME_RESULT:
case ROW_RESULT:
case IMPOSSIBLE_RESULT:
default:
break;
} // endswitch arg_type
return jvp;
} // end of MakeValue
/***********************************************************************/
/* Make a Json value containing the parameter. */
/***********************************************************************/
my_bool Json_Value_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count > 1) {
strcpy(message, "Json_Value cannot accept more than 1 argument");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Value_init
char *Json_Value(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str;
PJVAL jvp;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
jvp = MakeValue(g, args, 0);
if (!(str = Serialize(g, jvp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of Json_Value
void Json_Value_deinit(UDF_INIT* initid)
{
PlugExit((PGLOBAL)initid->ptr);
} // end of Json_Value_deinit
/***********************************************************************/
/* Make a Json array containing all the parameters. */
/***********************************************************************/
my_bool Json_Array_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Array_init
char *Json_Array(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str;
uint i;
PJAR arp;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
arp = new(g) JARRAY;
for (i = 0; i < args->arg_count; i++)
arp->AddValue(g, MakeValue(g, args, i));
arp->InitArray(g);
if (!(str = Serialize(g, arp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of Json_Array
void Json_Array_deinit(UDF_INIT* initid)
{
PlugExit((PGLOBAL)initid->ptr);
} // end of Json_Array_deinit
/***********************************************************************/
/* Add values to a Json array. */
/***********************************************************************/
my_bool Json_Array_Add_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
if (args->arg_count < 2) {
strcpy(message, "Json_Value_Add must have at least 2 arguments");
return true;
} else if (!IsJson(args, 0)) {
strcpy(message, "Json_Value_Add first argument must be a json array");
return true;
} else
CalcLen(args, false, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Array_Add_init
char *Json_Array_Add(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str;
PJVAL jvp;
PJAR arp;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
jvp = MakeValue(g, args, 0);
if (jvp->GetValType() != TYPE_JAR) {
arp = new(g) JARRAY;
arp->AddValue(g, jvp);
} else
arp = jvp->GetArray();
for (uint i = 1; i < args->arg_count; i++)
arp->AddValue(g, MakeValue(g, args, i));
arp->InitArray(g);
if (!(str = Serialize(g, arp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of Json_Array_Add
void Json_Array_Add_deinit(UDF_INIT* initid)
{
PlugExit((PGLOBAL)initid->ptr);
} // end of Json_Array_Add_deinit
/***********************************************************************/
/* Make a Json Oject containing all the parameters. */
/***********************************************************************/
my_bool Json_Object_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen;
CalcLen(args, true, reslen, memlen);
return JsonInit(initid, message, reslen, memlen);
} // end of Json_Object_init
char *Json_Object(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str;
uint i;
PJOB objp;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
objp = new(g) JOBJECT;
for (i = 0; i < args->arg_count; i++)
objp->SetValue(g, MakeValue(g, args, i), MakeKey(g, args, i));
if (!(str = Serialize(g, objp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of Json_Object
void Json_Object_deinit(UDF_INIT* initid)
{
PlugExit((PGLOBAL)initid->ptr);
} // end of Json_Object_deinit
/***********************************************************************/
/* Make a Json array from values comming from rows. */
/***********************************************************************/
my_bool Json_Array_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, n = GetJsonGrpSize();
if (args->arg_count != 1) {
strcpy(message, "Json_Array_Grp can only accept 1 argument");
return true;
} else
CalcLen(args, false, reslen, memlen);
reslen *= n;
memlen += ((memlen - MEMFIX) * (n - 1));
if (JsonInit(initid, message, reslen, memlen))
return true;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)new(g) JARRAY;
g->N = (int)n;
return false;
} // end of Json_Array_Grp_init
void Json_Array_Grp_add(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PJAR arp = (PJAR)g->Activityp;
if (g->N-- > 0)
arp->AddValue(g, MakeValue(g, args, 0));
} // end of Json_Array_Grp_add
char *Json_Array_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
PJAR arp = (PJAR)g->Activityp;
if (g->N < 0)
push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0,
"Result truncated to json_grp_size values");
arp->InitArray(g);
if (!(str = Serialize(g, arp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of Json_Array_Grp
void Json_Array_Grp_clear(UDF_INIT *initid, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)new(g) JARRAY;
g->N = GetJsonGrpSize();
} // end of Json_Array_Grp_clear
void Json_Array_Grp_deinit(UDF_INIT* initid)
{
PlugExit((PGLOBAL)initid->ptr);
} // end of Json_Array_Grp_deinit
/***********************************************************************/
/* Make a Json object from values comming from rows. */
/***********************************************************************/
my_bool Json_Object_Grp_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
{
unsigned long reslen, memlen, n = GetJsonGrpSize();
if (args->arg_count != 2) {
strcpy(message, "Json_Array_Grp can only accept 2 argument");
return true;
} else
CalcLen(args, true, reslen, memlen);
reslen *= n;
memlen += ((memlen - MEMFIX) * (n - 1));
if (JsonInit(initid, message, reslen, memlen))
return true;
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)new(g) JOBJECT;
g->N = (int)n;
return false;
} // end of Json_Object_Grp_init
void Json_Object_Grp_add(UDF_INIT *initid, UDF_ARGS *args,
char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PJOB objp = (PJOB)g->Activityp;
if (g->N-- > 0)
objp->SetValue(g, MakeValue(g, args, 0), MakePSZ(g, args, 1));
} // end of Json_Object_Grp_add
char *Json_Object_Grp(UDF_INIT *initid, UDF_ARGS *args, char *result,
unsigned long *res_length, char *is_null, char *error)
{
char *str;
PGLOBAL g = (PGLOBAL)initid->ptr;
PJOB objp = (PJOB)g->Activityp;
if (g->N < 0)
push_warning(current_thd, Sql_condition::WARN_LEVEL_WARN, 0,
"Result truncated to json_grp_size values");
if (!(str = Serialize(g, objp, NULL, 0)))
str = strcpy(result, g->Message);
*res_length = strlen(str);
return str;
} // end of Json_Object_Grp
void Json_Object_Grp_clear(UDF_INIT *initid, char *is_null, char *error)
{
PGLOBAL g = (PGLOBAL)initid->ptr;
PlugSubSet(g, g->Sarea, g->Sarea_Size);
g->Activityp = (PACTIVITY)new(g) JOBJECT;
g->N = GetJsonGrpSize();
} // end of Json_Object_Grp_clear
void Json_Object_Grp_deinit(UDF_INIT* initid)
{
PlugExit((PGLOBAL)initid->ptr);
} // end of Json_Object_Grp_deinit

View File

@@ -51,7 +51,8 @@
#define DLL_EXPORT // Items are exported from this DLL #define DLL_EXPORT // Items are exported from this DLL
#include "myconn.h" #include "myconn.h"
extern "C" int zconv; //extern "C" int zconv;
int GetConvSize(void);
extern MYSQL_PLUGIN_IMPORT uint mysqld_port; extern MYSQL_PLUGIN_IMPORT uint mysqld_port;
extern MYSQL_PLUGIN_IMPORT char *mysqld_unix_port; extern MYSQL_PLUGIN_IMPORT char *mysqld_unix_port;
@@ -265,7 +266,7 @@ PQRYRES MyColumns(PGLOBAL g, THD *thd, const char *host, const char *db,
return NULL; return NULL;
} else if (type == TYPE_STRING) { } else if (type == TYPE_STRING) {
if (v == 'X') { if (v == 'X') {
len = zconv; len = GetConvSize();
sprintf(g->Message, "Column %s converted to varchar(%d)", sprintf(g->Message, "Column %s converted to varchar(%d)",
colname, len); colname, len);
PushWarning(g, thd); PushWarning(g, thd);

View File

@@ -89,8 +89,8 @@ ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher L
UPDATE t1 SET AuthorFN = 'Philippe' WHERE AuthorLN = 'Knab'; UPDATE t1 SET AuthorFN = 'Philippe' WHERE AuthorLN = 'Knab';
SELECT * FROM t1 WHERE ISBN = '9782212090819'; SELECT * FROM t1 WHERE ISBN = '9782212090819';
ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
9782212090819 fr applications Jean-Christophe Bernadac Construire une application XML Eyrolles Paris 1999 9782212090819 fr applications Philippe Bernadac Construire une application XML Eyrolles Paris 1999
9782212090819 fr applications Philippe Knab Construire une application XML Eyrolles Paris 1999 9782212090819 fr applications Fran<EFBFBD>ois Knab Construire une application XML Eyrolles Paris 1999
# #
# To add an author a new table must be created # To add an author a new table must be created
# #
@@ -104,8 +104,8 @@ William J. Pardi
INSERT INTO t2 VALUES('Charles','Dickens'); INSERT INTO t2 VALUES('Charles','Dickens');
SELECT * FROM t1; SELECT * FROM t1;
ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year ISBN Language Subject AuthorFN AuthorLN Title Translation Translator Publisher Location Year
9782212090819 fr applications Jean-Christophe Bernadac Construire une application XML Eyrolles Paris 1999 9782212090819 fr applications Philippe Bernadac Construire une application XML Eyrolles Paris 1999
9782212090819 fr applications Philippe Knab Construire une application XML Eyrolles Paris 1999 9782212090819 fr applications Fran<EFBFBD>ois Knab Construire une application XML Eyrolles Paris 1999
9782840825685 fr applications William J. Pardi XML en Action adapt<70> de l'anglais par James Guerin Microsoft Press Paris 1999 9782840825685 fr applications William J. Pardi XML en Action adapt<70> de l'anglais par James Guerin Microsoft Press Paris 1999
9782840825685 fr applications Charles Dickens XML en Action adapt<70> de l'anglais par James Guerin Microsoft Press Paris 1999 9782840825685 fr applications Charles Dickens XML en Action adapt<70> de l'anglais par James Guerin Microsoft Press Paris 1999
DROP TABLE t1; DROP TABLE t1;
@@ -127,11 +127,11 @@ line
"SUBJECT": "applications", "SUBJECT": "applications",
"AUTHOR": [ "AUTHOR": [
{ {
"FIRSTNAME": "Jean-Christophe", "FIRSTNAME": "Philippe",
"LASTNAME": "Bernadac" "LASTNAME": "Bernadac"
}, },
{ {
"FIRSTNAME": "Philippe", "FIRSTNAME": "Fran<EFBFBD>ois",
"LASTNAME": "Knab" "LASTNAME": "Knab"
} }
], ],
@@ -192,7 +192,7 @@ Janet 4 Car 17.00
Janet 5 Beer+Car+Beer+Food 57.00 Janet 5 Beer+Car+Beer+Food 57.00
DROP TABLE t1; DROP TABLE t1;
# #
# Cannot be fully expanded # Now it can be fully expanded
# #
CREATE TABLE t1 ( CREATE TABLE t1 (
WHO CHAR(12), WHO CHAR(12),
@@ -201,7 +201,31 @@ WHAT CHAR(32) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:WHAT',
AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT') AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT')
ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.jsn'; ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.jsn';
SELECT * FROM t1; SELECT * FROM t1;
ERROR HY000: Got error 174 'Cannot expand more than one array' from CONNECT WHO WEEK WHAT AMOUNT
Joe 3 Beer 18.00
Joe 3 Food 12.00
Joe 3 Food 19.00
Joe 3 Car 20.00
Joe 4 Beer 19.00
Joe 4 Beer 16.00
Joe 4 Food 17.00
Joe 4 Food 17.00
Joe 4 Beer 14.00
Joe 5 Beer 14.00
Joe 5 Food 12.00
Beth 3 Beer 16.00
Beth 4 Food 17.00
Beth 4 Beer 15.00
Beth 5 Food 12.00
Beth 5 Beer 20.00
Janet 3 Car 19.00
Janet 3 Food 18.00
Janet 3 Beer 18.00
Janet 4 Car 17.00
Janet 5 Beer 14.00
Janet 5 Car 12.00
Janet 5 Beer 19.00
Janet 5 Food 12.00
DROP TABLE t1; DROP TABLE t1;
# #
# Expand expense in 3 one week tables # Expand expense in 3 one week tables

View File

@@ -128,7 +128,7 @@ SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;
--echo # --echo #
--echo # Cannot be fully expanded --echo # Now it can be fully expanded
--echo # --echo #
CREATE TABLE t1 ( CREATE TABLE t1 (
WHO CHAR(12), WHO CHAR(12),
@@ -136,7 +136,7 @@ WEEK INT(2) FIELD_FORMAT='WEEK:[X]:NUMBER',
WHAT CHAR(32) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:WHAT', WHAT CHAR(32) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:WHAT',
AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT') AMOUNT DOUBLE(8,2) FIELD_FORMAT='WEEK:[X]:EXPENSE:[X]:AMOUNT')
ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.jsn'; ENGINE=CONNECT TABLE_TYPE=JSON FILE_NAME='expense.jsn';
--error ER_GET_ERRMSG #--error ER_GET_ERRMSG
SELECT * FROM t1; SELECT * FROM t1;
DROP TABLE t1; DROP TABLE t1;

View File

@@ -26,14 +26,16 @@
#include "myutil.h" #include "myutil.h"
#define DLL_EXPORT // Items are exported from this DLL #define DLL_EXPORT // Items are exported from this DLL
extern "C" int xconv; //extern "C" int xconv;
TYPCONV GetTypeConv(void);
/************************************************************************/ /************************************************************************/
/* Convert from MySQL type name to PlugDB type number */ /* Convert from MySQL type name to PlugDB type number */
/************************************************************************/ /************************************************************************/
int MYSQLtoPLG(char *typname, char *var) int MYSQLtoPLG(char *typname, char *var)
{ {
int type; int type;
TYPCONV xconv = GetTypeConv();
if (!stricmp(typname, "int") || !stricmp(typname, "mediumint") || if (!stricmp(typname, "int") || !stricmp(typname, "mediumint") ||
!stricmp(typname, "integer")) !stricmp(typname, "integer"))
@@ -57,13 +59,13 @@ int MYSQLtoPLG(char *typname, char *var)
type = TYPE_TINY; type = TYPE_TINY;
else if (!stricmp(typname, "text") && var) { else if (!stricmp(typname, "text") && var) {
switch (xconv) { switch (xconv) {
case 1: case TPC_YES:
type = TYPE_STRING; type = TYPE_STRING;
*var = 'X'; *var = 'X';
break; break;
case 2: case TPC_SKIP:
*var = 'K'; *var = 'K';
default: default: // TPC_NO
type = TYPE_ERROR; type = TYPE_ERROR;
} // endswitch xconv } // endswitch xconv
@@ -88,7 +90,7 @@ int MYSQLtoPLG(char *typname, char *var)
} else if (type == TYPE_STRING && !stricmp(typname, "varchar")) } else if (type == TYPE_STRING && !stricmp(typname, "varchar"))
// This is to make the difference between CHAR and VARCHAR // This is to make the difference between CHAR and VARCHAR
*var = 'V'; *var = 'V';
else if (type == TYPE_ERROR && xconv == 2) else if (type == TYPE_ERROR && xconv == TPC_SKIP)
*var = 'K'; *var = 'K';
else else
*var = 0; *var = 0;
@@ -174,7 +176,7 @@ const char *PLGtoMYSQLtype(int type, bool dbf, char v)
/************************************************************************/ /************************************************************************/
int MYSQLtoPLG(int mytype, char *var) int MYSQLtoPLG(int mytype, char *var)
{ {
int type; int type, xconv = GetTypeConv();
switch (mytype) { switch (mytype) {
case MYSQL_TYPE_SHORT: case MYSQL_TYPE_SHORT:
@@ -221,7 +223,7 @@ int MYSQLtoPLG(int mytype, char *var)
case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_LONG_BLOB:
if (var) { if (var) {
switch (xconv) { switch (xconv) {
case 1: case TPC_YES:
if (*var != 'B') { if (*var != 'B') {
// This is a TEXT column // This is a TEXT column
type = TYPE_STRING; type = TYPE_STRING;
@@ -230,9 +232,9 @@ int MYSQLtoPLG(int mytype, char *var)
type = TYPE_ERROR; type = TYPE_ERROR;
break; break;
case 2: case TPC_SKIP:
*var = 'K'; // Skip *var = 'K'; // Skip
default: default: // TPC_NO
type = TYPE_ERROR; type = TYPE_ERROR;
} // endswitch xconv } // endswitch xconv

View File

@@ -2,6 +2,14 @@
#define DEFAULT_LOGIN_TIMEOUT -1 // means do not set #define DEFAULT_LOGIN_TIMEOUT -1 // means do not set
#define DEFAULT_QUERY_TIMEOUT -1 // means do not set #define DEFAULT_QUERY_TIMEOUT -1 // means do not set
typedef struct odbc_parms {
char *User; // User connect info
char *Pwd; // Password connect info
int Cto; // Connect timeout
int Qto; // Query timeout
bool UseCnc; // Use SQLConnect (!SQLDriverConnect)
} ODBCPARM, *POPARM;
/***********************************************************************/ /***********************************************************************/
/* ODBC catalog function prototypes. */ /* ODBC catalog function prototypes. */
/***********************************************************************/ /***********************************************************************/
@@ -10,8 +18,8 @@ char *ODBCCheckConnection(PGLOBAL g, char *dsn, int cop);
#endif // PROMPT_OK #endif // PROMPT_OK
PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info); PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info);
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table, PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
char *colpat, int maxres, int cto, int qto, bool info); char *colpat, int maxres, bool info, POPARM sop);
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, int cto, int qto); PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, POPARM sop);
PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat, PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
int maxres, int cto, int qto, bool info); int maxres, bool info, POPARM sop);
PQRYRES ODBCDrivers(PGLOBAL g, int maxres, bool info); PQRYRES ODBCDrivers(PGLOBAL g, int maxres, bool info);

View File

@@ -37,8 +37,8 @@
#include "xobject.h" #include "xobject.h"
//#include "kindex.h" //#include "kindex.h"
#include "xtable.h" #include "xtable.h"
#include "tabodbc.h"
#include "odbccat.h" #include "odbccat.h"
#include "tabodbc.h"
#include "plgcnx.h" // For DB types #include "plgcnx.h" // For DB types
#include "resource.h" #include "resource.h"
#include "valblk.h" #include "valblk.h"
@@ -53,6 +53,8 @@
extern "C" HINSTANCE s_hModule; // Saved module handle extern "C" HINSTANCE s_hModule; // Saved module handle
#endif // WIN32 #endif // WIN32
int GetConvSize();
/***********************************************************************/ /***********************************************************************/
/* Some macro's (should be defined elsewhere to be more accessible) */ /* Some macro's (should be defined elsewhere to be more accessible) */
/***********************************************************************/ /***********************************************************************/
@@ -122,7 +124,7 @@ int TranslateSQLType(int stp, int prec, int& len, char& v)
case SQL_LONGVARCHAR: // (-1) case SQL_LONGVARCHAR: // (-1)
v = 'V'; v = 'V';
type = TYPE_STRING; type = TYPE_STRING;
len = MY_MIN(abs(len), 256); len = MY_MIN(abs(len), GetConvSize());
break; break;
case SQL_NUMERIC: // 2 case SQL_NUMERIC: // 2
case SQL_DECIMAL: // 3 case SQL_DECIMAL: // 3
@@ -291,7 +293,7 @@ static void ResetNullValues(CATPARM *cap)
/* of an ODBC table that will be retrieved by GetData commands. */ /* of an ODBC table that will be retrieved by GetData commands. */
/***********************************************************************/ /***********************************************************************/
PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table, PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
char *colpat, int maxres, int cto, int qto, bool info) char *colpat, int maxres, bool info, POPARM sop)
{ {
int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING, int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT, TYPE_SHORT, TYPE_STRING, TYPE_INT, TYPE_INT,
@@ -310,10 +312,8 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
/************************************************************************/ /************************************************************************/
if (!info) { if (!info) {
ocp = new(g) ODBConn(g, NULL); ocp = new(g) ODBConn(g, NULL);
ocp->SetLoginTimeout((DWORD)cto);
ocp->SetQueryTimeout((DWORD)qto);
if (ocp->Open(dsn, 10) < 1) // openReadOnly + noODBCdialog if (ocp->Open(dsn, sop, 10) < 1) // openReadOnly + noODBCdialog
return NULL; return NULL;
if (table && !strchr(table, '%')) { if (table && !strchr(table, '%')) {
@@ -342,7 +342,7 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
} // endif ocp } // endif ocp
if (trace) if (trace)
htrc("ODBCColumns: max=%d len=%d,%d,%d\n", htrc("ODBCColumns: max=%d len=%d,%d,%d,%d\n",
maxres, length[0], length[1], length[2], length[3]); maxres, length[0], length[1], length[2], length[3]);
/************************************************************************/ /************************************************************************/
@@ -388,12 +388,13 @@ PQRYRES ODBCColumns(PGLOBAL g, char *dsn, char *db, char *table,
/* ODBCSrcCols: constructs the result blocks containing the */ /* ODBCSrcCols: constructs the result blocks containing the */
/* description of all the columns of a Srcdef option. */ /* description of all the columns of a Srcdef option. */
/**************************************************************************/ /**************************************************************************/
PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, int cto, int qto) PQRYRES ODBCSrcCols(PGLOBAL g, char *dsn, char *src, POPARM sop)
{ {
ODBConn *ocp = new(g) ODBConn(g, NULL); ODBConn *ocp = new(g) ODBConn(g, NULL);
ocp->SetLoginTimeout((DWORD)cto); if (ocp->Open(dsn, sop, 10) < 1) // openReadOnly + noOdbcDialog
ocp->SetQueryTimeout((DWORD)qto); return NULL;
return ocp->GetMetaData(g, dsn, src); return ocp->GetMetaData(g, dsn, src);
} // end of ODBCSrcCols } // end of ODBCSrcCols
@@ -574,7 +575,7 @@ PQRYRES ODBCDataSources(PGLOBAL g, int maxres, bool info)
/* an ODBC database that will be retrieved by GetData commands. */ /* an ODBC database that will be retrieved by GetData commands. */
/**************************************************************************/ /**************************************************************************/
PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat, PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
int maxres, int cto, int qto, bool info) int maxres, bool info, POPARM sop)
{ {
int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING, int buftyp[] = {TYPE_STRING, TYPE_STRING, TYPE_STRING,
TYPE_STRING, TYPE_STRING}; TYPE_STRING, TYPE_STRING};
@@ -594,10 +595,8 @@ PQRYRES ODBCTables(PGLOBAL g, char *dsn, char *db, char *tabpat,
/* Open the connection with the ODBC data source. */ /* Open the connection with the ODBC data source. */
/**********************************************************************/ /**********************************************************************/
ocp = new(g) ODBConn(g, NULL); ocp = new(g) ODBConn(g, NULL);
ocp->SetLoginTimeout((DWORD)cto);
ocp->SetQueryTimeout((DWORD)qto);
if (ocp->Open(dsn, 2) < 1) // 2 is openReadOnly if (ocp->Open(dsn, sop, 2) < 1) // 2 is openReadOnly
return NULL; return NULL;
if (!maxres) if (!maxres)
@@ -925,11 +924,14 @@ ODBConn::ODBConn(PGLOBAL g, TDBODBC *tdbp)
m_Catver = (tdbp) ? tdbp->Catver : 0; m_Catver = (tdbp) ? tdbp->Catver : 0;
m_Rows = 0; m_Rows = 0;
m_Connect = NULL; m_Connect = NULL;
m_User = NULL;
m_Pwd = NULL;
m_Updatable = true; m_Updatable = true;
m_Transact = false; m_Transact = false;
m_Scrollable = (tdbp) ? tdbp->Scrollable : false; m_Scrollable = (tdbp) ? tdbp->Scrollable : false;
m_First = true; m_First = true;
m_Full = false; m_Full = false;
m_UseCnc = false;
m_IDQuoteChar[0] = '"'; m_IDQuoteChar[0] = '"';
m_IDQuoteChar[1] = 0; m_IDQuoteChar[1] = 0;
//*m_ErrMsg = '\0'; //*m_ErrMsg = '\0';
@@ -1061,7 +1063,7 @@ void ODBConn::OnSetOptions(HSTMT hstmt)
/***********************************************************************/ /***********************************************************************/
/* Open: connect to a data source. */ /* Open: connect to a data source. */
/***********************************************************************/ /***********************************************************************/
int ODBConn::Open(PSZ ConnectString, DWORD options) int ODBConn::Open(PSZ ConnectString, POPARM sop, DWORD options)
{ {
PGLOBAL& g = m_G; PGLOBAL& g = m_G;
//ASSERT_VALID(this); //ASSERT_VALID(this);
@@ -1070,6 +1072,11 @@ int ODBConn::Open(PSZ ConnectString, DWORD options)
m_Updatable = !(options & openReadOnly); m_Updatable = !(options & openReadOnly);
m_Connect = ConnectString; m_Connect = ConnectString;
m_User = sop->User;
m_Pwd = sop->Pwd;
m_LoginTimeout = sop->Cto;
m_QueryTimeout = sop->Qto;
m_UseCnc = sop->UseCnc;
// Allocate the HDBC and make connection // Allocate the HDBC and make connection
try { try {
@@ -1078,10 +1085,14 @@ int ODBConn::Open(PSZ ConnectString, DWORD options)
AllocConnect(options); AllocConnect(options);
/*ver = GetStringInfo(SQL_ODBC_VER);*/ /*ver = GetStringInfo(SQL_ODBC_VER);*/
if (Connect(options)) { if (!m_UseCnc) {
strcpy(g->Message, MSG(CONNECT_CANCEL)); if (DriverConnect(options)) {
return 0; strcpy(g->Message, MSG(CONNECT_CANCEL));
} // endif return 0;
} // endif
} else // Connect using SQLConnect
Connect();
/*ver = GetStringInfo(SQL_DRIVER_ODBC_VER);*/ /*ver = GetStringInfo(SQL_DRIVER_ODBC_VER);*/
// Verify support for required functionality and cache info // Verify support for required functionality and cache info
@@ -1163,10 +1174,27 @@ void ODBConn::AllocConnect(DWORD Options)
return; return;
} // end of AllocConnect } // end of AllocConnect
/***********************************************************************/
/* Connect to data source using SQLConnect. */
/***********************************************************************/
void ODBConn::Connect(void)
{
SQLRETURN rc;
SQLSMALLINT ul = (m_User ? SQL_NTS : 0);
SQLSMALLINT pl = (m_Pwd ? SQL_NTS : 0);
rc = SQLConnect(m_hdbc, (SQLCHAR*)m_Connect, SQL_NTS,
(SQLCHAR*)m_User, ul, (SQLCHAR*)m_Pwd, pl);
if (!Check(rc))
ThrowDBX(rc, "SQLConnect");
} // end of Connect
/***********************************************************************/ /***********************************************************************/
/* Connect to data source using SQLDriverConnect. */ /* Connect to data source using SQLDriverConnect. */
/***********************************************************************/ /***********************************************************************/
bool ODBConn::Connect(DWORD Options) bool ODBConn::DriverConnect(DWORD Options)
{ {
RETCODE rc; RETCODE rc;
SWORD nResult; SWORD nResult;
@@ -1213,7 +1241,7 @@ bool ODBConn::Connect(DWORD Options)
// All done // All done
return false; return false;
} // end of Connect } // end of DriverConnect
void ODBConn::VerifyConnect() void ODBConn::VerifyConnect()
{ {
@@ -1712,6 +1740,8 @@ bool ODBConn::BindParam(ODBCCOL *colp)
strcpy(m_G->Message, x->GetErrorMessage(0)); strcpy(m_G->Message, x->GetErrorMessage(0));
colsize = colp->GetPrecision(); colsize = colp->GetPrecision();
sqlt = GetSQLType(buftype); sqlt = GetSQLType(buftype);
dec = IsTypeChar(buftype) ? 0 : colp->GetScale();
nul = SQL_NULLABLE_UNKNOWN;
} // end try/catch } // end try/catch
buf = colp->GetBuffer(0); buf = colp->GetBuffer(0);
@@ -1865,9 +1895,6 @@ PQRYRES ODBConn::GetMetaData(PGLOBAL g, char *dsn, char *src)
RETCODE rc; RETCODE rc;
HSTMT hstmt; HSTMT hstmt;
if (Open(dsn, 10) < 1) // openReadOnly + noOdbcDialog
return NULL;
try { try {
rc = SQLAllocStmt(m_hdbc, &hstmt); rc = SQLAllocStmt(m_hdbc, &hstmt);

View File

@@ -119,7 +119,7 @@ class ODBConn : public BLOCK {
noOdbcDialog = 0x0008, // Don't display ODBC Connect dialog noOdbcDialog = 0x0008, // Don't display ODBC Connect dialog
forceOdbcDialog = 0x0010}; // Always display ODBC connect dialog forceOdbcDialog = 0x0010}; // Always display ODBC connect dialog
int Open(PSZ ConnectString, DWORD Options = 0); int Open(PSZ ConnectString, POPARM sop, DWORD Options = 0);
int Rewind(char *sql, ODBCCOL *tocols); int Rewind(char *sql, ODBCCOL *tocols);
void Close(void); void Close(void);
PQRYRES AllocateResult(PGLOBAL g); PQRYRES AllocateResult(PGLOBAL g);
@@ -135,8 +135,10 @@ class ODBConn : public BLOCK {
public: public:
// Operations // Operations
void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;} //void SetLoginTimeout(DWORD sec) {m_LoginTimeout = sec;}
void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;} //void SetQueryTimeout(DWORD sec) {m_QueryTimeout = sec;}
//void SetUserName(PSZ user) {m_User = user;}
//void SetUserPwd(PSZ pwd) {m_Pwd = pwd;}
int GetResultSize(char *sql, ODBCCOL *colp); int GetResultSize(char *sql, ODBCCOL *colp);
int ExecDirectSQL(char *sql, ODBCCOL *tocols); int ExecDirectSQL(char *sql, ODBCCOL *tocols);
int Fetch(void); int Fetch(void);
@@ -155,7 +157,7 @@ class ODBConn : public BLOCK {
// Implementation // Implementation
public: public:
// virtual ~ODBConn(); //virtual ~ODBConn();
// ODBC operations // ODBC operations
protected: protected:
@@ -163,7 +165,8 @@ class ODBConn : public BLOCK {
void ThrowDBX(RETCODE rc, PSZ msg, HSTMT hstmt = SQL_NULL_HSTMT); void ThrowDBX(RETCODE rc, PSZ msg, HSTMT hstmt = SQL_NULL_HSTMT);
void ThrowDBX(PSZ msg); void ThrowDBX(PSZ msg);
void AllocConnect(DWORD dwOptions); void AllocConnect(DWORD dwOptions);
bool Connect(DWORD Options); void Connect(void);
bool DriverConnect(DWORD Options);
void VerifyConnect(void); void VerifyConnect(void);
void GetConnectInfo(void); void GetConnectInfo(void);
void Free(void); void Free(void);
@@ -185,11 +188,14 @@ class ODBConn : public BLOCK {
DWORD m_RowsetSize; DWORD m_RowsetSize;
char m_IDQuoteChar[2]; char m_IDQuoteChar[2];
PSZ m_Connect; PSZ m_Connect;
PSZ m_User;
PSZ m_Pwd;
int m_Catver; int m_Catver;
int m_Rows; int m_Rows;
bool m_Updatable; bool m_Updatable;
bool m_Transact; bool m_Transact;
bool m_Scrollable; bool m_Scrollable;
bool m_UseCnc;
bool m_First; bool m_First;
bool m_Full; bool m_Full;
}; // end of ODBConn class definition }; // end of ODBConn class definition

View File

@@ -311,7 +311,7 @@ PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
else else
crp->Kdata = NULL; crp->Kdata = NULL;
if (g->Trace) if (trace)
htrc("Column(%d) %s type=%d len=%d value=%p\n", htrc("Column(%d) %s type=%d len=%d value=%p\n",
crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata); crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata);

View File

@@ -144,12 +144,12 @@ PGLOBAL PlugInit(LPCSTR Language, uint worksize)
return NULL; return NULL;
} else { } else {
g->Sarea_Size = worksize; g->Sarea_Size = worksize;
g->Trace = 0;
g->Createas = 0; g->Createas = 0;
g->Alchecked = 0; g->Alchecked = 0;
g->Mrr = 0; g->Mrr = 0;
g->Activityp = g->ActivityStart = NULL; g->Activityp = g->ActivityStart = NULL;
g->Xchk = NULL; g->Xchk = NULL;
g->N = 0;
strcpy(g->Message, ""); strcpy(g->Message, "");
/*******************************************************************/ /*******************************************************************/

View File

@@ -222,6 +222,7 @@ class DllExport DOSCOL : public COLBLK {
virtual PVBLK GetDval(void) {return Dval;} virtual PVBLK GetDval(void) {return Dval;}
// Methods // Methods
using COLBLK::Print;
virtual bool VarSize(void); virtual bool VarSize(void);
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check); virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check);
virtual void ReadColumn(PGLOBAL g); virtual void ReadColumn(PGLOBAL g);

View File

@@ -1,5 +1,5 @@
/************* tabjson C++ Program Source Code File (.CPP) *************/ /************* tabjson C++ Program Source Code File (.CPP) *************/
/* PROGRAM NAME: tabxjson Version 1.0 */ /* PROGRAM NAME: tabjson Version 1.0 */
/* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */ /* (C) Copyright to the author Olivier BERTRAND 2014 - 2015 */
/* This program are the JSON class DB execution routines. */ /* This program are the JSON class DB execution routines. */
/***********************************************************************/ /***********************************************************************/
@@ -119,12 +119,12 @@ TDBJSN::TDBJSN(PJDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp)
Fpos = -1; Fpos = -1;
Spos = N = 0; Spos = N = 0;
Limit = tdp->Limit; Limit = tdp->Limit;
Pretty = tdp->Pretty; NextSame = 0;
Strict = tdp->Strict;
NextSame = false;
Comma = false;
SameRow = 0; SameRow = 0;
Xval = -1; Xval = -1;
Pretty = tdp->Pretty;
Strict = tdp->Strict;
Comma = false;
} // end of TDBJSN standard constructor } // end of TDBJSN standard constructor
TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp) TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
@@ -137,12 +137,12 @@ TDBJSN::TDBJSN(TDBJSN *tdbp) : TDBDOS(NULL, tdbp)
Spos = tdbp->Spos; Spos = tdbp->Spos;
N = tdbp->N; N = tdbp->N;
Limit = tdbp->Limit; Limit = tdbp->Limit;
Pretty = tdbp->Pretty;
Strict = tdbp->Strict;
NextSame = tdbp->NextSame; NextSame = tdbp->NextSame;
Comma = tdbp->Comma;
SameRow = tdbp->SameRow; SameRow = tdbp->SameRow;
Xval = tdbp->Xval; Xval = tdbp->Xval;
Pretty = tdbp->Pretty;
Strict = tdbp->Strict;
Comma = tdbp->Comma;
} // end of TDBJSN copy constructor } // end of TDBJSN copy constructor
// Used for update // Used for update
@@ -221,14 +221,9 @@ bool TDBJSN::OpenDB(PGLOBAL g)
/*******************************************************************/ /*******************************************************************/
/* Table already open replace it at its beginning. */ /* Table already open replace it at its beginning. */
/*******************************************************************/ /*******************************************************************/
for (PJCOL cp = (PJCOL)Columns; cp; cp = (PJCOL)cp->GetNext()) {
cp->Nx = 0;
cp->Arp = NULL;
} // endfor cp
Fpos= -1; Fpos= -1;
Spos = 0; Spos = 0;
NextSame = false; NextSame = 0;
SameRow = 0; SameRow = 0;
} else { } else {
/*******************************************************************/ /*******************************************************************/
@@ -292,7 +287,8 @@ int TDBJSN::ReadDB(PGLOBAL g)
N++; N++;
if (NextSame) { if (NextSame) {
SameRow++; SameRow = NextSame;
NextSame = 0;
return RC_OK; return RC_OK;
} else if ((rc = TDBDOS::ReadDB(g)) == RC_OK) } else if ((rc = TDBDOS::ReadDB(g)) == RC_OK)
if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK)) { if (!IsRead() && ((rc = ReadBuffer(g)) != RC_OK)) {
@@ -333,21 +329,20 @@ int TDBJSN::ReadDB(PGLOBAL g)
} // end of PrepareWriting } // end of PrepareWriting
/* ----------------------------- JSNCOL ------------------------------- */ /* ---------------------------- JSONCOL ------------------------------ */
/***********************************************************************/ /***********************************************************************/
/* JSNCOL public constructor. */ /* JSONCOL public constructor. */
/***********************************************************************/ /***********************************************************************/
JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i) JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
: DOSCOL(g, cdp, tdbp, cprec, i, "DOS") : DOSCOL(g, cdp, tdbp, cprec, i, "DOS")
{ {
Tjp = (TDBJSN *)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp); Tjp = (TDBJSN *)(tdbp->GetOrig() ? tdbp->GetOrig() : tdbp);
Arp = NULL;
Jpath = cdp->GetFmt(); Jpath = cdp->GetFmt();
MulVal = NULL; MulVal = NULL;
Nodes = NULL; Nodes = NULL;
Nod = Nx =0; Nod = 0;
Ival = -1; Xnod = -1;
Xpd = false; Xpd = false;
Parsed = false; Parsed = false;
} // end of JSONCOL constructor } // end of JSONCOL constructor
@@ -359,13 +354,11 @@ JSONCOL::JSONCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp) JSONCOL::JSONCOL(JSONCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp)
{ {
Tjp = col1->Tjp; Tjp = col1->Tjp;
Arp = col1->Arp;
Jpath = col1->Jpath; Jpath = col1->Jpath;
MulVal = col1->MulVal; MulVal = col1->MulVal;
Nodes = col1->Nodes; Nodes = col1->Nodes;
Nod = col1->Nod; Nod = col1->Nod;
Ival = col1->Ival; Xnod = col1->Xnod;
Nx = col1->Nx;
Xpd = col1->Xpd; Xpd = col1->Xpd;
Parsed = col1->Parsed; Parsed = col1->Parsed;
} // end of JSONCOL copy constructor } // end of JSONCOL copy constructor
@@ -387,17 +380,16 @@ bool JSONCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
} // end of SetBuffer } // end of SetBuffer
/***********************************************************************/ /***********************************************************************/
/* Analyse array processing options. */ /* Check whether this object is expanded. */
/***********************************************************************/ /***********************************************************************/
bool JSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b) bool JSONCOL::CheckExpand(PGLOBAL g, int i, PSZ nm, bool b)
{ {
if (Tjp->Xcol && nm && !strcmp(nm, Tjp->Xcol) && if ((Tjp->Xcol && nm && !strcmp(nm, Tjp->Xcol) &&
(Tjp->Xval < 0 || Tjp->Xval == i)) { (Tjp->Xval < 0 || Tjp->Xval == i)) || Xpd) {
Xpd = true; // Expandable object Xpd = true; // Expandable object
Nodes[i].Op = OP_XX; Nodes[i].Op = OP_EXP;
Tjp->Xval = i;
} else if (b) { } else if (b) {
strcpy(g->Message, "Cannot expand more than one array"); strcpy(g->Message, "Cannot expand more than one branch");
return true; return true;
} // endif Xcol } // endif Xcol
@@ -434,7 +426,7 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
// Default specifications // Default specifications
if (CheckExpand(g, i, nm, false)) if (CheckExpand(g, i, nm, false))
return true; return true;
else if (jnp->Op != OP_XX) else if (jnp->Op != OP_EXP)
if (!Value->IsTypeNum()) { if (!Value->IsTypeNum()) {
jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING); jnp->CncVal = AllocateValue(g, (void*)", ", TYPE_STRING);
jnp->Op = OP_CNC; jnp->Op = OP_CNC;
@@ -456,13 +448,13 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
case '*': jnp->Op = OP_MULT; break; case '*': jnp->Op = OP_MULT; break;
case '>': jnp->Op = OP_MAX; break; case '>': jnp->Op = OP_MAX; break;
case '<': jnp->Op = OP_MIN; break; case '<': jnp->Op = OP_MIN; break;
case '#': jnp->Op = OP_NUM; break;
case '!': jnp->Op = OP_SEP; break; // Average case '!': jnp->Op = OP_SEP; break; // Average
case '#': jnp->Op = OP_NUM; break;
case 'x': case 'x':
case 'X': // Expand this array case 'X': // Expand this array
if (!Tjp->Xcol && nm) { if (!Tjp->Xcol && nm) {
Xpd = true; Xpd = true;
jnp->Op = OP_XX; jnp->Op = OP_EXP;
Tjp->Xval = i; Tjp->Xval = i;
Tjp->Xcol = nm; Tjp->Xcol = nm;
} else if (CheckExpand(g, i, nm, true)) } else if (CheckExpand(g, i, nm, true))
@@ -490,6 +482,38 @@ bool JSONCOL::SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm)
return true; return true;
} // endif's } // endif's
// For calculated arrays, a local Value must be used
switch (jnp->Op) {
case OP_NUM:
jnp->Valp = AllocateValue(g, TYPE_INT);
break;
case OP_ADD:
case OP_MULT:
case OP_SEP:
if (!IsTypeChar(Buf_Type))
jnp->Valp = AllocateValue(g, Buf_Type, 0, GetPrecision());
else
jnp->Valp = AllocateValue(g, TYPE_DOUBLE);
break;
case OP_MIN:
case OP_MAX:
jnp->Valp = AllocateValue(g, Buf_Type, Long, GetPrecision());
break;
case OP_CNC:
if (IsTypeChar(Buf_Type))
jnp->Valp = AllocateValue(g, TYPE_STRING, Long, GetPrecision());
else
jnp->Valp = AllocateValue(g, TYPE_STRING, 512);
break;
default:
break;
} // endswitch Op
if (jnp->Valp)
MulVal = AllocateValue(g, jnp->Valp);
return false; return false;
} // end of SetArrayOptions } // end of SetArrayOptions
@@ -533,6 +557,9 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
if (SetArrayOptions(g, p, i, Nodes[i-1].Key)) if (SetArrayOptions(g, p, i, Nodes[i-1].Key))
return true; return true;
} else if (*p == '*') {
// Return JSON
Nodes[i].Op = OP_XX;
} else { } else {
Nodes[i].Key = p; Nodes[i].Key = p;
Nodes[i].Op = OP_EXIST; Nodes[i].Op = OP_EXIST;
@@ -545,60 +572,262 @@ bool JSONCOL::ParseJpath(PGLOBAL g)
return false; return false;
} // end of ParseJpath } // end of ParseJpath
/***********************************************************************/
/* MakeJson: Serialize the json item and set value to it. */
/***********************************************************************/
PVAL JSONCOL::MakeJson(PGLOBAL g, PJSON jsp)
{
if (Value->IsTypeNum()) {
strcpy(g->Message, "Cannot make Json for a numeric column");
Value->Reset();
} else
Value->SetValue_psz(Serialize(g, jsp, NULL, 0));
return Value;
} // end of MakeJson
/***********************************************************************/ /***********************************************************************/
/* SetValue: Set a value from a JVALUE contains. */ /* SetValue: Set a value from a JVALUE contains. */
/***********************************************************************/ /***********************************************************************/
void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n) void JSONCOL::SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n)
{ {
if (val) { if (val) {
if (Nodes[n].Op == OP_NUM) switch (val->GetValType()) {
vp->SetValue(1); case TYPE_STRG:
else { case TYPE_INTG:
again: case TYPE_DBL:
switch (val->GetValType()) { vp->SetValue_pval(val->GetValue());
case TYPE_STRG: break;
case TYPE_INTG: case TYPE_BOOL:
case TYPE_DBL: if (vp->IsTypeNum())
vp->SetValue_pval(val->GetValue()); vp->SetValue(val->GetInteger() ? 1 : 0);
else
vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
break;
case TYPE_JAR:
SetJsonValue(g, vp, val->GetArray()->GetValue(0), n);
break;
case TYPE_JOB:
// if (!vp->IsTypeNum() || !Strict) {
vp->SetValue_psz(val->GetObject()->GetText(g));
break; break;
case TYPE_BOOL: // } // endif Type
if (vp->IsTypeNum())
vp->SetValue(val->GetInteger() ? 1 : 0);
else
vp->SetValue_psz((PSZ)(val->GetInteger() ? "true" : "false"));
break; default:
case TYPE_JAR: vp->Reset();
val = val->GetArray()->GetValue(0); } // endswitch Type
goto again;
case TYPE_JOB:
if (!vp->IsTypeNum()) {
vp->SetValue_psz(val->GetObject()->GetText(g));
break;
} // endif Type
default:
vp->Reset();
} // endswitch Type
} // endelse
} else } else
vp->Reset(); vp->Reset();
} // end of SetJsonValue } // end of SetJsonValue
/***********************************************************************/
/* ReadColumn: */
/***********************************************************************/
void JSONCOL::ReadColumn(PGLOBAL g)
{
if (!Tjp->SameRow || Xnod >= Tjp->SameRow)
Value->SetValue_pval(GetColumnValue(g, Tjp->Row, 0));
} // end of ReadColumn
/***********************************************************************/
/* GetColumnValue: */
/***********************************************************************/
PVAL JSONCOL::GetColumnValue(PGLOBAL g, PJSON row, int i)
{
int n = Nod - 1;
bool expd = false;
PJAR arp;
PJVAL val = NULL;
for (; i < Nod && row; i++) {
if (Nodes[i].Op == OP_NUM) {
Value->SetValue(row->GetType() == TYPE_JAR ? row->size() : 1);
return(Value);
} else if (Nodes[i].Op == OP_XX) {
return MakeJson(g, row);
} else switch (row->GetType()) {
case TYPE_JOB:
if (!Nodes[i].Key) {
// Expected Array was not there
if (i < Nod-1)
continue;
else
val = new(g) JVALUE(row);
} else
val = ((PJOB)row)->GetValue(Nodes[i].Key);
break;
case TYPE_JAR:
arp = (PJAR)row;
if (!Nodes[i].Key) {
if (Nodes[i].Op != OP_NULL) {
if (Nodes[i].Rank) {
val = arp->GetValue(Nodes[i].Rank - 1);
} else if (Nodes[i].Op == OP_EXP) {
return ExpandArray(g, arp, i);
} else
return CalculateArray(g, arp, i);
} else
val = NULL;
} else if (i < Nod-1) {
strcpy(g->Message, "Unexpected array");
val = NULL; // Not an expected array
} else
val = arp->GetValue(0);
break;
case TYPE_JVAL:
val = (PJVAL)row;
break;
default:
sprintf(g->Message, "Invalid row JSON type %d", row->GetType());
val = NULL;
} // endswitch Type
if (i < Nod-1)
row = (val) ? val->GetJson() : NULL;
} // endfor i
SetJsonValue(g, Value, val, n);
return Value;
} // end of GetColumnValue
/***********************************************************************/
/* ExpandArray: */
/***********************************************************************/
PVAL JSONCOL::ExpandArray(PGLOBAL g, PJAR arp, int n)
{
int ars;
PJVAL jvp;
JVALUE jval;
ars = MY_MIN(Tjp->Limit, arp->size());
if (!(jvp = arp->GetValue(Nodes[n].Nx))) {
strcpy(g->Message, "Logical error expanding array");
longjmp(g->jumper[g->jump_level], 666);
} // endif jvp
if (n < Nod - 1 && jvp->GetJson()) {
jval.SetValue(GetColumnValue(g, jvp->GetJson(), n + 1));
jvp = &jval;
} // endif n
if (n >= Tjp->NextSame) {
if (++Nodes[n].Nx == ars) {
Nodes[n].Nx = 0;
Xnod = 0;
} else
Xnod = n;
Tjp->NextSame = Xnod;
} // endif NextSame
SetJsonValue(g, Value, jvp, n);
return Value;
} // end of ExpandArray
/***********************************************************************/
/* CalculateArray: */
/***********************************************************************/
PVAL JSONCOL::CalculateArray(PGLOBAL g, PJAR arp, int n)
{
int i, ars, nv = 0, nextsame = Tjp->NextSame;
bool err;
OPVAL op = Nodes[n].Op;
PVAL val[2], vp = Nodes[n].Valp;
PJVAL jvrp, jvp;
JVALUE jval;
vp->Reset();
ars = MY_MIN(Tjp->Limit, arp->size());
for (i = 0; i < ars; i++) {
jvrp = arp->GetValue(i);
do {
if (n < Nod - 1 && jvrp->GetJson()) {
Tjp->NextSame = nextsame;
jval.SetValue(GetColumnValue(g, jvrp->GetJson(), n + 1));
jvp = &jval;
} else
jvp = jvrp;
if (!nv++) {
SetJsonValue(g, vp, jvp, n);
continue;
} else
SetJsonValue(g, MulVal, jvp, n);
if (!MulVal->IsZero()) {
switch (op) {
case OP_CNC:
if (Nodes[n].CncVal) {
val[0] = Nodes[n].CncVal;
err = vp->Compute(g, val, 1, op);
} // endif CncVal
val[0] = MulVal;
err = vp->Compute(g, val, 1, op);
break;
// case OP_NUM:
case OP_SEP:
val[0] = Nodes[n].Valp;
val[1] = MulVal;
err = vp->Compute(g, val, 2, OP_ADD);
break;
default:
val[0] = Nodes[n].Valp;
val[1] = MulVal;
err = vp->Compute(g, val, 2, op);
} // endswitch Op
if (err)
vp->Reset();
} // endif Zero
} while (Tjp->NextSame > nextsame);
} // endfor i
if (op == OP_SEP) {
// Calculate average
MulVal->SetValue(nv);
val[0] = vp;
val[1] = MulVal;
if (vp->Compute(g, val, 2, OP_DIV))
vp->Reset();
} // endif Op
Tjp->NextSame = nextsame;
return vp;
} // end of CalculateArray
/***********************************************************************/ /***********************************************************************/
/* GetRow: Get the object containing this column. */ /* GetRow: Get the object containing this column. */
/***********************************************************************/ /***********************************************************************/
PJSON JSONCOL::GetRow(PGLOBAL g, int mode) PJSON JSONCOL::GetRow(PGLOBAL g)
{ {
PJVAL val; PJVAL val;
PJAR arp; PJAR arp;
PJSON nwr, row = Tjp->Row; PJSON nwr, row = Tjp->Row;
for (int i = 0; i < Nod-1 && row; i++) { for (int i = 0; i < Nod-1 && row; i++) {
switch (row->GetType()) { if (Nodes[i+1].Op == OP_XX)
break;
else switch (row->GetType()) {
case TYPE_JOB: case TYPE_JOB:
if (!Nodes[i].Key) if (!Nodes[i].Key)
// Expected Array was not there // Expected Array was not there
@@ -609,20 +838,12 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
case TYPE_JAR: case TYPE_JAR:
if (!Nodes[i].Key) { if (!Nodes[i].Key) {
if (Nodes[i].Op != OP_NULL) { if (Nodes[i].Op != OP_NULL) {
Ival = i;
arp = (PJAR)row; arp = (PJAR)row;
if (mode < 2) // First pass if (Nodes[i].Rank)
Arp = arp; val = arp->GetValue(Nodes[i].Rank - 1);
else
if (Nodes[i].Op != OP_XX) { val = arp->GetValue(Nodes[i].Nx);
if (Nodes[i].Rank)
val = arp->GetValue(Nodes[i].Rank - 1);
else
val = arp->GetValue(arp == Arp ? Nx : 0);
} else
val = arp->GetValue(Tjp->SameRow);
} else } else
val = NULL; val = NULL;
@@ -643,15 +864,16 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
if (val) { if (val) {
row = val->GetJson(); row = val->GetJson();
} else if (mode == 1) { // mode write } else {
// Construct missing objects // Construct missing objects
for (i++; row && i < Nod; i++) { for (i++; row && i < Nod; i++) {
if (!Nodes[i].Key) { if (Nodes[i].Op == OP_XX)
break;
else if (!Nodes[i].Key)
// Construct intermediate array // Construct intermediate array
nwr = new(g) JARRAY; nwr = new(g) JARRAY;
} else { else
nwr = new(g) JOBJECT; nwr = new(g) JOBJECT;
} // endif Nodes
if (row->GetType() == TYPE_JOB) { if (row->GetType() == TYPE_JOB) {
((PJOB)row)->SetValue(g, new(g) JVALUE(nwr), Nodes[i-1].Key); ((PJOB)row)->SetValue(g, new(g) JVALUE(nwr), Nodes[i-1].Key);
@@ -667,139 +889,13 @@ PJSON JSONCOL::GetRow(PGLOBAL g, int mode)
} // endfor i } // endfor i
break; break;
} else } // endelse
row = NULL;
} // endfor i } // endfor i
return row; return row;
} // end of GetRow } // end of GetRow
/***********************************************************************/
/* ReadColumn: */
/***********************************************************************/
void JSONCOL::ReadColumn(PGLOBAL g)
{
int mode = 0, n = Nod - 1;
PJSON row;
PJVAL val = NULL;
evenmore:
row = GetRow(g, mode);
more:
if (row) switch (row->GetType()) {
case TYPE_JOB:
if (Nodes[n].Key)
val = row->GetValue(Nodes[n].Key);
else
val = new(g) JVALUE(row);
break;
case TYPE_JAR:
// Multiple column ?
if (Nodes[n].Op != OP_NULL) {
Arp = (PJAR)row;
val = Arp->GetValue(Nodes[n].Rank > 0 ?
Nodes[n].Rank - 1 :
Nodes[n].Op == OP_XX ? Tjp->SameRow : Nx);
Ival = n;
} else
val = NULL;
break;
case TYPE_JVAL:
val = (PJVAL)row;
break;
default:
sprintf(g->Message, "Wrong return value type %d", row->GetType());
Value->Reset();
return;
} // endswitch Type
if (!Nx /*|| (Xpd)*/)
SetJsonValue(g, Value, val, n);
if (Arp) {
// Multiple column
int ars = (Nodes[Ival].Rank > 0) ? 1 : MY_MIN(Tjp->Limit, Arp->size());
if (Nodes[Ival].Op == OP_XX) {
if (ars > Tjp->SameRow + 1)
Tjp->NextSame = true; // More to come
else {
Tjp->NextSame = false;
Arp = NULL;
} // endelse
} else {
if (Nx && val) {
SetJsonValue(g, MulVal, val, Ival);
if (!MulVal->IsZero()) {
PVAL val[2];
bool err;
switch (Nodes[Ival].Op) {
case OP_CNC:
if (Nodes[Ival].CncVal) {
val[0] = Nodes[Ival].CncVal;
err = Value->Compute(g, val, 1, Nodes[Ival].Op);
} // endif CncVal
val[0] = MulVal;
err = Value->Compute(g, val, 1, Nodes[Ival].Op);
break;
case OP_NUM:
case OP_SEP:
val[0] = Value;
val[1] = MulVal;
err = Value->Compute(g, val, 2, OP_ADD);
break;
default:
val[0] = Value;
val[1] = MulVal;
err = Value->Compute(g, val, 2, Nodes[Ival].Op);
} // endswitch Op
if (err)
Value->Reset();
} // endif Zero
} // endif Nx
if (ars > ++Nx) {
if (Ival != n) {
mode = 2;
goto evenmore;
} else
goto more;
} else {
if (Nodes[Ival].Op == OP_SEP) {
// Calculate average
PVAL val[2];
MulVal->SetValue(ars);
val[0] = Value;
val[1] = MulVal;
if (Value->Compute(g, val, 2, OP_DIV))
Value->Reset();
} // endif Op
Arp = NULL;
Nx = 0;
} // endif ars
} // endif Op
} // endif Arp
} // end of ReadColumn
/***********************************************************************/ /***********************************************************************/
/* WriteColumn: */ /* WriteColumn: */
/***********************************************************************/ /***********************************************************************/
@@ -817,10 +913,11 @@ void JSONCOL::WriteColumn(PGLOBAL g)
if (Value->IsNull() && Tjp->Mode == MODE_INSERT) if (Value->IsNull() && Tjp->Mode == MODE_INSERT)
return; return;
char *s;
PJOB objp = NULL; PJOB objp = NULL;
PJAR arp = NULL; PJAR arp = NULL;
PJVAL jvp = NULL; PJVAL jvp = NULL;
PJSON row = GetRow(g, 1); PJSON jsp, row = GetRow(g);
JTYP type = row->GetType(); JTYP type = row->GetType();
switch (row->GetType()) { switch (row->GetType()) {
@@ -832,6 +929,32 @@ void JSONCOL::WriteColumn(PGLOBAL g)
if (row) switch (Buf_Type) { if (row) switch (Buf_Type) {
case TYPE_STRING: case TYPE_STRING:
if (Nodes[Nod-1].Op == OP_XX) {
s = Value->GetCharValue();
if (!(jsp = ParseJson(g, s, (int)strlen(s), 0))) {
strcpy(g->Message, s);
longjmp(g->jumper[g->jump_level], 666);
} // endif jsp
if (arp) {
if (Nod > 1 && Nodes[Nod-2].Rank)
arp->SetValue(g, new(g) JVALUE(jsp), Nodes[Nod-2].Rank-1);
else
arp->AddValue(g, new(g) JVALUE(jsp));
arp->InitArray(g);
} else if (objp) {
if (Nod > 1 && Nodes[Nod-2].Key)
objp->SetValue(g, new(g) JVALUE(jsp), Nodes[Nod-2].Key);
} else if (jvp)
jvp->SetValue(jsp);
break;
} // endif Op
// Passthru
case TYPE_DATE: case TYPE_DATE:
case TYPE_INT: case TYPE_INT:
case TYPE_DOUBLE: case TYPE_DOUBLE:
@@ -1175,11 +1298,6 @@ bool TDBJSON::OpenDB(PGLOBAL g)
/*******************************************************************/ /*******************************************************************/
/* Table already open replace it at its beginning. */ /* Table already open replace it at its beginning. */
/*******************************************************************/ /*******************************************************************/
for (PJCOL cp = (PJCOL)Columns; cp; cp = (PJCOL)cp->GetNext()) {
cp->Nx = 0;
cp->Arp = NULL;
} // endfor cp
Fpos= -1; Fpos= -1;
Spos = 0; Spos = 0;
NextSame = false; NextSame = false;
@@ -1217,7 +1335,8 @@ int TDBJSON::ReadDB(PGLOBAL g)
N++; N++;
if (NextSame) { if (NextSame) {
SameRow++; SameRow = NextSame;
NextSame = false;
rc = RC_OK; rc = RC_OK;
} else if (++Fpos < (signed)Doc->size()) { } else if (++Fpos < (signed)Doc->size()) {
Row = Doc->GetValue(Fpos); Row = Doc->GetValue(Fpos);
@@ -1257,9 +1376,10 @@ int TDBJSON::WriteDB(PGLOBAL g)
return RC_FX; return RC_FX;
} else { // if (Jmode == MODE_VALUE) } else { // if (Jmode == MODE_VALUE)
if (Mode == MODE_INSERT) if (Mode == MODE_INSERT) {
Doc->AddValue(g, (PJVAL)Row); Doc->AddValue(g, (PJVAL)Row);
else if (Doc->SetValue(g, (PJVAL)Row, Fpos)) Row = new(g) JVALUE;
} else if (Doc->SetValue(g, (PJVAL)Row, Fpos))
return RC_FX; return RC_FX;
} // endif Jmode } // endif Jmode

View File

@@ -16,8 +16,6 @@ typedef class JSONDEF *PJDEF;
typedef class TDBJSON *PJTDB; typedef class TDBJSON *PJTDB;
typedef class JSONCOL *PJCOL; typedef class JSONCOL *PJCOL;
class TDBJSN;
/***********************************************************************/ /***********************************************************************/
/* The JSON tree node. Can be an Object or an Array. */ /* The JSON tree node. Can be an Object or an Array. */
/***********************************************************************/ /***********************************************************************/
@@ -25,7 +23,9 @@ typedef struct _jnode {
PSZ Key; // The key used for object PSZ Key; // The key used for object
OPVAL Op; // Operator used for this node OPVAL Op; // Operator used for this node
PVAL CncVal; // To cont value used for OP_CNC PVAL CncVal; // To cont value used for OP_CNC
PVAL Valp; // The internal array VALUE
int Rank; // The rank in array int Rank; // The rank in array
int Nx; // Same row number
} JNODE, *PJNODE; } JNODE, *PJNODE;
/***********************************************************************/ /***********************************************************************/
@@ -77,7 +77,7 @@ class TDBJSN : public TDBDOS {
virtual PTDB CopyOne(PTABS t); virtual PTDB CopyOne(PTABS t);
virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n); virtual PCOL MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n);
virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL colp); virtual PCOL InsertSpecialColumn(PGLOBAL g, PCOL colp);
virtual int RowNumber(PGLOBAL g, BOOL b = FALSE) virtual int RowNumber(PGLOBAL g, bool b = FALSE)
{return (b) ? N : Fpos + 1;} {return (b) ? N : Fpos + 1;}
// Database routines // Database routines
@@ -98,11 +98,11 @@ class TDBJSN : public TDBDOS {
int N; // The current Rownum int N; // The current Rownum
int Limit; // Limit of multiple values int Limit; // Limit of multiple values
int Pretty; // Depends on file structure int Pretty; // Depends on file structure
bool Strict; // Strict syntax checking int NextSame; // Same next row
bool NextSame; // Same next row
bool Comma; // Row has final comma
int SameRow; // Same row nb int SameRow; // Same row nb
int Xval; // Index of expandable array int Xval; // Index of expandable array
bool Strict; // Strict syntax checking
bool Comma; // Row has final comma
}; // end of class TDBJSN }; // end of class TDBJSN
/* -------------------------- JSONCOL class -------------------------- */ /* -------------------------- JSONCOL class -------------------------- */
@@ -130,8 +130,12 @@ class JSONCOL : public DOSCOL {
protected: protected:
bool CheckExpand(PGLOBAL g, int i, PSZ nm, bool b); bool CheckExpand(PGLOBAL g, int i, PSZ nm, bool b);
bool SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm); bool SetArrayOptions(PGLOBAL g, char *p, int i, PSZ nm);
PJSON GetRow(PGLOBAL g, int mode); PVAL GetColumnValue(PGLOBAL g, PJSON row, int i);
PVAL ExpandArray(PGLOBAL g, PJAR arp, int n);
PVAL CalculateArray(PGLOBAL g, PJAR arp, int n);
PVAL MakeJson(PGLOBAL g, PJSON jsp);
void SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n); void SetJsonValue(PGLOBAL g, PVAL vp, PJVAL val, int n);
PJSON GetRow(PGLOBAL g);
// Default constructor not to be used // Default constructor not to be used
JSONCOL(void) {} JSONCOL(void) {}
@@ -139,12 +143,10 @@ class JSONCOL : public DOSCOL {
// Members // Members
TDBJSN *Tjp; // To the JSN table block TDBJSN *Tjp; // To the JSN table block
PVAL MulVal; // To value used by multiple column PVAL MulVal; // To value used by multiple column
PJAR Arp; // The intermediate array
char *Jpath; // The json path char *Jpath; // The json path
JNODE *Nodes ; // The intermediate objects JNODE *Nodes; // The intermediate objects
int Nod; // The number of intermediate objects int Nod; // The number of intermediate objects
int Ival; // Index of multiple values int Xnod; // Index of multiple values
int Nx; // The last read sub-row
bool Xpd; // True for expandable column bool Xpd; // True for expandable column
bool Parsed; // True when parsed bool Parsed; // True when parsed
}; // end of class JSONCOL }; // end of class JSONCOL

View File

@@ -1141,19 +1141,16 @@ int TDBMYSQL::WriteDB(PGLOBAL g)
int rc; int rc;
uint len = Query->GetLength(); uint len = Query->GetLength();
char buf[64]; char buf[64];
bool b, oom = false; bool oom = false;
// Make the Insert command value list // Make the Insert command value list
for (PCOL colp = Columns; colp; colp = colp->GetNext()) { for (PCOL colp = Columns; colp; colp = colp->GetNext()) {
if (!colp->GetValue()->IsNull()) { if (!colp->GetValue()->IsNull()) {
if ((b = colp->GetResultType() == TYPE_STRING || if (colp->GetResultType() == TYPE_STRING ||
colp->GetResultType() == TYPE_DATE)) colp->GetResultType() == TYPE_DATE)
oom |= Query->Append('\''); oom |= Query->Append_quoted(colp->GetValue()->GetCharString(buf));
else
oom |= Query->Append(colp->GetValue()->GetCharString(buf)); oom |= Query->Append(colp->GetValue()->GetCharString(buf));
if (b)
oom |= Query->Append('\'');
} else } else
oom |= Query->Append("NULL"); oom |= Query->Append("NULL");

View File

@@ -355,7 +355,7 @@ bool TDBOCCUR::MakeColumnList(PGLOBAL g)
for (colp = Columns; colp; colp = colp->GetNext()) for (colp = Columns; colp; colp = colp->GetNext())
if (colp->GetAmType() == TYPE_AM_PRX) if (colp->GetAmType() == TYPE_AM_PRX)
if (((PPRXCOL)colp)->Init(g)) if (((PPRXCOL)colp)->Init(g, NULL))
return true; return true;
Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL)); Col = (PCOL*)PlugSubAlloc(g, NULL, Mult * sizeof(PCOL));

View File

@@ -66,8 +66,8 @@
#include "plgdbsem.h" #include "plgdbsem.h"
#include "mycat.h" #include "mycat.h"
#include "xtable.h" #include "xtable.h"
#include "tabodbc.h"
#include "odbccat.h" #include "odbccat.h"
#include "tabodbc.h"
#include "tabmul.h" #include "tabmul.h"
#include "reldef.h" #include "reldef.h"
#include "tabcol.h" #include "tabcol.h"
@@ -93,9 +93,10 @@ bool ExactInfo(void);
/***********************************************************************/ /***********************************************************************/
ODBCDEF::ODBCDEF(void) ODBCDEF::ODBCDEF(void)
{ {
Connect= Tabname= Tabschema= Tabcat= Srcdef= Qchar= Qrystr= Sep= NULL; Connect = Tabname = Tabschema = Username = Password = NULL;
Tabcat = Srcdef = Qchar = Qrystr = Sep = NULL;
Catver = Options = Cto = Qto = Quoted = Maxerr = Maxres = 0; Catver = Options = Cto = Qto = Quoted = Maxerr = Maxres = 0;
Scrollable = Memory = Xsrc = false; Scrollable = Memory = Xsrc = UseCnc = false;
} // end of ODBCDEF constructor } // end of ODBCDEF constructor
/***********************************************************************/ /***********************************************************************/
@@ -117,6 +118,8 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Tabschema = GetStringCatInfo(g, "Schema", Tabschema); Tabschema = GetStringCatInfo(g, "Schema", Tabschema);
Tabcat = GetStringCatInfo(g, "Qualifier", NULL); Tabcat = GetStringCatInfo(g, "Qualifier", NULL);
Tabcat = GetStringCatInfo(g, "Catalog", Tabcat); Tabcat = GetStringCatInfo(g, "Catalog", Tabcat);
Username = GetStringCatInfo(g, "User", NULL);
Password = GetStringCatInfo(g, "Password", NULL);
if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL)))
Read_Only = true; Read_Only = true;
@@ -133,6 +136,7 @@ bool ODBCDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
Cto= GetIntCatInfo("ConnectTimeout", DEFAULT_LOGIN_TIMEOUT); Cto= GetIntCatInfo("ConnectTimeout", DEFAULT_LOGIN_TIMEOUT);
Qto= GetIntCatInfo("QueryTimeout", DEFAULT_QUERY_TIMEOUT); Qto= GetIntCatInfo("QueryTimeout", DEFAULT_QUERY_TIMEOUT);
Scrollable = GetBoolCatInfo("Scrollable", false); Scrollable = GetBoolCatInfo("Scrollable", false);
UseCnc = GetBoolCatInfo("UseDSN", false);
Memory = GetBoolCatInfo("Memory", false); Memory = GetBoolCatInfo("Memory", false);
Pseudo = 2; // FILID is Ok but not ROWID Pseudo = 2; // FILID is Ok but not ROWID
return false; return false;
@@ -190,34 +194,40 @@ TDBODBC::TDBODBC(PODEF tdp) : TDBASE(tdp)
Connect = tdp->Connect; Connect = tdp->Connect;
TableName = tdp->Tabname; TableName = tdp->Tabname;
Schema = tdp->Tabschema; Schema = tdp->Tabschema;
Ops.User = tdp->Username;
Ops.Pwd = tdp->Password;
Catalog = tdp->Tabcat; Catalog = tdp->Tabcat;
Srcdef = tdp->Srcdef; Srcdef = tdp->Srcdef;
Qrystr = tdp->Qrystr; Qrystr = tdp->Qrystr;
Sep = tdp->GetSep(); Sep = tdp->GetSep();
Options = tdp->Options; Options = tdp->Options;
Cto = tdp->Cto; Ops.Cto = tdp->Cto;
Qto = tdp->Qto; Ops.Qto = tdp->Qto;
Quoted = MY_MAX(0, tdp->GetQuoted()); Quoted = MY_MAX(0, tdp->GetQuoted());
Rows = tdp->GetElemt(); Rows = tdp->GetElemt();
Catver = tdp->Catver; Catver = tdp->Catver;
Memory = (tdp->Memory) ? 1 : 0; Memory = (tdp->Memory) ? 1 : 0;
Scrollable = tdp->Scrollable; Scrollable = tdp->Scrollable;
Ops.UseCnc = tdp->UseCnc;
} else { } else {
Connect = NULL; Connect = NULL;
TableName = NULL; TableName = NULL;
Schema = NULL; Schema = NULL;
Ops.User = NULL;
Ops.Pwd = NULL;
Catalog = NULL; Catalog = NULL;
Srcdef = NULL; Srcdef = NULL;
Qrystr = NULL; Qrystr = NULL;
Sep = 0; Sep = 0;
Options = 0; Options = 0;
Cto = DEFAULT_LOGIN_TIMEOUT; Ops.Cto = DEFAULT_LOGIN_TIMEOUT;
Qto = DEFAULT_QUERY_TIMEOUT; Ops.Qto = DEFAULT_QUERY_TIMEOUT;
Quoted = 0; Quoted = 0;
Rows = 0; Rows = 0;
Catver = 0; Catver = 0;
Memory = 0; Memory = 0;
Scrollable = false; Scrollable = false;
Ops.UseCnc = false;
} // endif tdp } // endif tdp
Quote = NULL; Quote = NULL;
@@ -242,6 +252,7 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
Connect = tdbp->Connect; Connect = tdbp->Connect;
TableName = tdbp->TableName; TableName = tdbp->TableName;
Schema = tdbp->Schema; Schema = tdbp->Schema;
Ops = tdbp->Ops;
Catalog = tdbp->Catalog; Catalog = tdbp->Catalog;
Srcdef = tdbp->Srcdef; Srcdef = tdbp->Srcdef;
Qrystr = tdbp->Qrystr; Qrystr = tdbp->Qrystr;
@@ -254,8 +265,6 @@ TDBODBC::TDBODBC(PTDBODBC tdbp) : TDBASE(tdbp)
MulConn = tdbp->MulConn; MulConn = tdbp->MulConn;
DBQ = tdbp->DBQ; DBQ = tdbp->DBQ;
Options = tdbp->Options; Options = tdbp->Options;
Cto = tdbp->Cto;
Qto = tdbp->Qto;
Quoted = tdbp->Quoted; Quoted = tdbp->Quoted;
Rows = tdbp->Rows; Rows = tdbp->Rows;
Fpos = tdbp->Fpos; Fpos = tdbp->Fpos;
@@ -370,7 +379,7 @@ int TDBODBC::Decode(char *txt, char *buf, size_t n)
/***********************************************************************/ /***********************************************************************/
char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt) char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
{ {
char *colist, *tabname, *sql, buf[64]; char *colist, *tabname, *sql, buf[NAM_LEN * 3];
LPCSTR schmp = NULL, catp = NULL; LPCSTR schmp = NULL, catp = NULL;
int len, ncol = 0; int len, ncol = 0;
bool first = true; bool first = true;
@@ -475,6 +484,9 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
if (To_CondFil) if (To_CondFil)
strcat(strcat(sql, " WHERE "), To_CondFil->Body); strcat(strcat(sql, " WHERE "), To_CondFil->Body);
if (trace)
htrc("sql: '%s'\n", sql);
return sql; return sql;
} // end of MakeSQL } // end of MakeSQL
@@ -483,7 +495,7 @@ char *TDBODBC::MakeSQL(PGLOBAL g, bool cnt)
/***********************************************************************/ /***********************************************************************/
char *TDBODBC::MakeInsert(PGLOBAL g) char *TDBODBC::MakeInsert(PGLOBAL g)
{ {
char *stmt, *colist, *valist; char *stmt, *colist, *valist, buf[NAM_LEN * 3];
// char *tk = "`"; // char *tk = "`";
int len = 0; int len = 0;
bool b = FALSE; bool b = FALSE;
@@ -510,10 +522,13 @@ char *TDBODBC::MakeInsert(PGLOBAL g)
} else } else
b = true; b = true;
// Column name can be in UTF-8 encoding
Decode(colp->GetName(), buf, sizeof(buf));
if (Quote) if (Quote)
strcat(strcat(strcat(colist, Quote), colp->GetName()), Quote); strcat(strcat(strcat(colist, Quote), buf), Quote);
else else
strcat(colist, colp->GetName()); strcat(colist, buf);
strcat(valist, "?"); // Parameter marker strcat(valist, "?"); // Parameter marker
} // endfor colp } // endfor colp
@@ -558,8 +573,7 @@ bool TDBODBC::BindParameters(PGLOBAL g)
/***********************************************************************/ /***********************************************************************/
char *TDBODBC::MakeCommand(PGLOBAL g) char *TDBODBC::MakeCommand(PGLOBAL g)
{ {
char *p, name[68], *qc = Ocp->GetQuoteChar(); char *p, *stmt, name[68], *body = NULL, *qc = Ocp->GetQuoteChar();
char *stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1); char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
bool qtd = Quoted > 0; bool qtd = Quoted > 0;
int i = 0, k = 0; int i = 0, k = 0;
@@ -570,6 +584,15 @@ char *TDBODBC::MakeCommand(PGLOBAL g)
qrystr[i] = (Qrystr[i] == '`') ? *qc : tolower(Qrystr[i]); qrystr[i] = (Qrystr[i] == '`') ? *qc : tolower(Qrystr[i]);
} while (Qrystr[i++]); } while (Qrystr[i++]);
if (To_CondFil && (p = strstr(qrystr, " where "))) {
p[7] = 0; // Remove where clause
Qrystr[(p - qrystr) + 7] = 0;
body = To_CondFil->Body;
stmt = (char*)PlugSubAlloc(g, NULL, strlen(qrystr)
+ strlen(body) + 64);
} else
stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
// Check whether the table name is equal to a keyword // Check whether the table name is equal to a keyword
// If so, it must be quoted in the original query // If so, it must be quoted in the original query
strlwr(strcat(strcat(strcpy(name, " "), Name), " ")); strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
@@ -597,6 +620,9 @@ char *TDBODBC::MakeCommand(PGLOBAL g)
stmt[i++] = (Qrystr[k] == '`') ? *qc : Qrystr[k]; stmt[i++] = (Qrystr[k] == '`') ? *qc : Qrystr[k];
} while (Qrystr[k++]); } while (Qrystr[k++]);
if (body)
strcat(stmt, body);
} else { } else {
sprintf(g->Message, "Cannot use this %s command", sprintf(g->Message, "Cannot use this %s command",
(Mode == MODE_UPDATE) ? "UPDATE" : "DELETE"); (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
@@ -698,10 +724,7 @@ int TDBODBC::Cardinality(PGLOBAL g)
char qry[96], tbn[64]; char qry[96], tbn[64];
ODBConn *ocp = new(g) ODBConn(g, this); ODBConn *ocp = new(g) ODBConn(g, this);
ocp->SetLoginTimeout((DWORD)Cto); if (ocp->Open(Connect, &Ops, Options) < 1)
ocp->SetQueryTimeout((DWORD)Qto);
if (ocp->Open(Connect, Options) < 1)
return -1; return -1;
// Table name can be encoded in UTF-8 // Table name can be encoded in UTF-8
@@ -762,9 +785,9 @@ int TDBODBC::GetProgMax(PGLOBAL g)
/***********************************************************************/ /***********************************************************************/
bool TDBODBC::OpenDB(PGLOBAL g) bool TDBODBC::OpenDB(PGLOBAL g)
{ {
bool rc = false; bool rc = true;
if (g->Trace) if (trace)
htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n", htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
this, Tdb_No, Use, Mode); this, Tdb_No, Use, Mode);
@@ -802,14 +825,12 @@ bool TDBODBC::OpenDB(PGLOBAL g)
/* and if so to allocate just a new result set. But this only for */ /* and if so to allocate just a new result set. But this only for */
/* drivers allowing concurency in getting results ??? */ /* drivers allowing concurency in getting results ??? */
/*********************************************************************/ /*********************************************************************/
if (!Ocp) { if (!Ocp)
Ocp = new(g) ODBConn(g, this); Ocp = new(g) ODBConn(g, this);
Ocp->SetLoginTimeout((DWORD)Cto); else if (Ocp->IsOpen())
Ocp->SetQueryTimeout((DWORD)Qto);
} else if (Ocp->IsOpen())
Ocp->Close(); Ocp->Close();
if (Ocp->Open(Connect, Options) < 1) if (Ocp->Open(Connect, &Ops, Options) < 1)
return true; return true;
else if (Quoted) else if (Quoted)
Quote = Ocp->GetQuoteChar(); Quote = Ocp->GetQuoteChar();
@@ -839,12 +860,12 @@ bool TDBODBC::OpenDB(PGLOBAL g)
} // endif Query } // endif Query
} else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) } else if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
Query = MakeCommand(g); rc = false; // wait for CheckCond before calling MakeCommand(g);
else } else
sprintf(g->Message, "Invalid mode %d", Mode); sprintf(g->Message, "Invalid mode %d", Mode);
if (!Query || rc) { if (rc) {
Ocp->Close(); Ocp->Close();
return true; return true;
} // endif rc } // endif rc
@@ -876,6 +897,9 @@ int TDBODBC::ReadDB(PGLOBAL g)
GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex); GetTdb_No(), Mode, To_Key_Col, To_Link, To_Kindex);
if (Mode == MODE_UPDATE || Mode == MODE_DELETE) { if (Mode == MODE_UPDATE || Mode == MODE_DELETE) {
if (!Query && !(Query = MakeCommand(g)))
return RC_FX;
// Send the UPDATE/DELETE command to the remote table // Send the UPDATE/DELETE command to the remote table
if (!Ocp->ExecSQLcommand(Query)) { if (!Ocp->ExecSQLcommand(Query)) {
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows); sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
@@ -945,6 +969,9 @@ int TDBODBC::WriteDB(PGLOBAL g)
int TDBODBC::DeleteDB(PGLOBAL g, int irc) int TDBODBC::DeleteDB(PGLOBAL g, int irc)
{ {
if (irc == RC_FX) { if (irc == RC_FX) {
if (!Query && !(Query = MakeCommand(g)))
return RC_FX;
// Send the DELETE (all) command to the remote table // Send the DELETE (all) command to the remote table
if (!Ocp->ExecSQLcommand(Query)) { if (!Ocp->ExecSQLcommand(Query)) {
sprintf(g->Message, "%s: %d affected rows", TableName, AftRows); sprintf(g->Message, "%s: %d affected rows", TableName, AftRows);
@@ -1158,12 +1185,12 @@ void ODBCCOL::ReadColumn(PGLOBAL g)
} // endif Buf_Type } // endif Buf_Type
if (g->Trace) { if (trace) {
char buf[64]; char buf[64];
htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n", htrc("ODBC Column %s: rows=%d buf=%p type=%d value=%s\n",
Name, tdbp->Rows, Bufp, Buf_Type, Value->GetCharString(buf)); Name, tdbp->Rows, Bufp, Buf_Type, Value->GetCharString(buf));
} // endif Trace } // endif trace
put: put:
if (tdbp->Memory != 2) if (tdbp->Memory != 2)
@@ -1397,7 +1424,7 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
{ {
bool rc = false; bool rc = false;
if (g->Trace) if (trace)
htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n", htrc("ODBC OpenDB: tdbp=%p tdb=R%d use=%dmode=%d\n",
this, Tdb_No, Use, Mode); this, Tdb_No, Use, Mode);
@@ -1415,12 +1442,10 @@ bool TDBXDBC::OpenDB(PGLOBAL g)
/*********************************************************************/ /*********************************************************************/
if (!Ocp) { if (!Ocp) {
Ocp = new(g) ODBConn(g, this); Ocp = new(g) ODBConn(g, this);
Ocp->SetLoginTimeout((DWORD)Cto);
Ocp->SetQueryTimeout((DWORD)Qto);
} else if (Ocp->IsOpen()) } else if (Ocp->IsOpen())
Ocp->Close(); Ocp->Close();
if (Ocp->Open(Connect, Options) < 1) if (Ocp->Open(Connect, &Ops, Options) < 1)
return true; return true;
Use = USE_OPEN; // Do it now in case we are recursively called Use = USE_OPEN; // Do it now in case we are recursively called
@@ -1554,8 +1579,11 @@ TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
Dsn = tdp->GetConnect(); Dsn = tdp->GetConnect();
Schema = tdp->GetTabschema(); Schema = tdp->GetTabschema();
Tab = tdp->GetTabname(); Tab = tdp->GetTabname();
Cto = tdp->Cto; Ops.User = tdp->Username;
Qto = tdp->Qto; Ops.Pwd = tdp->Password;
Ops.Cto = tdp->Cto;
Ops.Qto = tdp->Qto;
Ops.UseCnc = tdp->UseCnc;
} // end of TDBOTB constructor } // end of TDBOTB constructor
/***********************************************************************/ /***********************************************************************/
@@ -1563,7 +1591,7 @@ TDBOTB::TDBOTB(PODEF tdp) : TDBDRV(tdp)
/***********************************************************************/ /***********************************************************************/
PQRYRES TDBOTB::GetResult(PGLOBAL g) PQRYRES TDBOTB::GetResult(PGLOBAL g)
{ {
return ODBCTables(g, Dsn, Schema, Tab, Maxres, Cto, Qto, false); return ODBCTables(g, Dsn, Schema, Tab, Maxres, false, &Ops);
} // end of GetResult } // end of GetResult
/* ---------------------------TDBOCL class --------------------------- */ /* ---------------------------TDBOCL class --------------------------- */
@@ -1573,7 +1601,7 @@ PQRYRES TDBOTB::GetResult(PGLOBAL g)
/***********************************************************************/ /***********************************************************************/
PQRYRES TDBOCL::GetResult(PGLOBAL g) PQRYRES TDBOCL::GetResult(PGLOBAL g)
{ {
return ODBCColumns(g, Dsn, Schema, Tab, NULL, Maxres, Cto, Qto, false); return ODBCColumns(g, Dsn, Schema, Tab, NULL, Maxres, false, &Ops);
} // end of GetResult } // end of GetResult
/* ------------------------ End of Tabodbc --------------------------- */ /* ------------------------ End of Tabodbc --------------------------- */

View File

@@ -50,6 +50,8 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
PSZ Connect; /* ODBC connection string */ PSZ Connect; /* ODBC connection string */
PSZ Tabname; /* External table name */ PSZ Tabname; /* External table name */
PSZ Tabschema; /* External table schema */ PSZ Tabschema; /* External table schema */
PSZ Username; /* User connect name */
PSZ Password; /* Password connect info */
PSZ Tabcat; /* External table catalog */ PSZ Tabcat; /* External table catalog */
PSZ Srcdef; /* The source table SQL definition */ PSZ Srcdef; /* The source table SQL definition */
PSZ Qchar; /* Identifier quoting character */ PSZ Qchar; /* Identifier quoting character */
@@ -65,6 +67,7 @@ class DllExport ODBCDEF : public TABDEF { /* Logical table description */
bool Scrollable; /* Use scrollable cursor */ bool Scrollable; /* Use scrollable cursor */
bool Memory; /* Put result set in memory */ bool Memory; /* Put result set in memory */
bool Xsrc; /* Execution type */ bool Xsrc; /* Execution type */
bool UseCnc; /* Use SQLConnect (!SQLDriverConnect) */
}; // end of ODBCDEF }; // end of ODBCDEF
#if !defined(NODBC) #if !defined(NODBC)
@@ -124,9 +127,12 @@ class TDBODBC : public TDBASE {
// Members // Members
ODBConn *Ocp; // Points to an ODBC connection class ODBConn *Ocp; // Points to an ODBC connection class
ODBCCOL *Cnp; // Points to count(*) column ODBCCOL *Cnp; // Points to count(*) column
ODBCPARM Ops; // Additional parameters
char *Connect; // Points to connection string char *Connect; // Points to connection string
char *TableName; // Points to ODBC table name char *TableName; // Points to ODBC table name
char *Schema; // Points to ODBC table Schema char *Schema; // Points to ODBC table Schema
char *User; // User connect info
char *Pwd; // Password connect info
char *Catalog; // Points to ODBC table Catalog char *Catalog; // Points to ODBC table Catalog
char *Srcdef; // The source table SQL definition char *Srcdef; // The source table SQL definition
char *Query; // Points to SQL statement char *Query; // Points to SQL statement
@@ -151,6 +157,7 @@ class TDBODBC : public TDBASE {
int Nparm; // The number of statement parameters int Nparm; // The number of statement parameters
int Memory; // 0: No 1: Alloc 2: Put 3: Get int Memory; // 0: No 1: Alloc 2: Put 3: Get
bool Scrollable; // Use scrollable cursor bool Scrollable; // Use scrollable cursor
bool UseCnc; // Use SQLConnect (!SQLDriverConnect)
PQRYRES Qrp; // Points to storage result PQRYRES Qrp; // Points to storage result
}; // end of class TDBODBC }; // end of class TDBODBC
@@ -316,8 +323,7 @@ class TDBOTB : public TDBDRV {
char *Dsn; // Points to connection string char *Dsn; // Points to connection string
char *Schema; // Points to schema name or NULL char *Schema; // Points to schema name or NULL
char *Tab; // Points to ODBC table name or pattern char *Tab; // Points to ODBC table name or pattern
int Cto; // Connect timeout ODBCPARM Ops; // Additional parameters
int Qto; // Query timeout
}; // end of class TDBOTB }; // end of class TDBOTB
/***********************************************************************/ /***********************************************************************/

View File

@@ -558,7 +558,7 @@ bool TDBPIVOT::MakePivotColumns(PGLOBAL g)
// Check and initialize the subtable columns // Check and initialize the subtable columns
for (PCOL cp = Columns; cp; cp = cp->GetNext()) for (PCOL cp = Columns; cp; cp = cp->GetNext())
if (cp->GetAmType() == TYPE_AM_SRC) { if (cp->GetAmType() == TYPE_AM_SRC) {
if (((PSRCCOL)cp)->Init(g)) if (((PSRCCOL)cp)->Init(g, NULL))
return TRUE; return TRUE;
} else if (cp->GetAmType() == TYPE_AM_FNC) } else if (cp->GetAmType() == TYPE_AM_FNC)
@@ -874,9 +874,9 @@ SRCCOL::SRCCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int n)
/***********************************************************************/ /***********************************************************************/
/* Initialize the column as pointing to the source column. */ /* Initialize the column as pointing to the source column. */
/***********************************************************************/ /***********************************************************************/
bool SRCCOL::Init(PGLOBAL g) bool SRCCOL::Init(PGLOBAL g, PTDBASE tp)
{ {
if (PRXCOL::Init(g)) if (PRXCOL::Init(g, tp))
return true; return true;
AddStatus(BUF_READ); // All is done here AddStatus(BUF_READ); // All is done here

View File

@@ -180,9 +180,10 @@ class SRCCOL : public PRXCOL {
virtual int GetAmType(void) {return TYPE_AM_SRC;} virtual int GetAmType(void) {return TYPE_AM_SRC;}
// Methods // Methods
using PRXCOL::Init;
virtual void Reset(void) {} virtual void Reset(void) {}
void SetColumn(void); void SetColumn(void);
bool Init(PGLOBAL g); virtual bool Init(PGLOBAL g, PTDBASE tp);
bool CompareLast(void); bool CompareLast(void);
protected: protected:

View File

@@ -266,7 +266,7 @@ bool TDBTBL::InitTableList(PGLOBAL g)
// Real initialization will be done later. // Real initialization will be done later.
for (colp = Columns; colp; colp = colp->GetNext()) for (colp = Columns; colp; colp = colp->GetNext())
if (!colp->IsSpecial()) if (!colp->IsSpecial())
if (((PPRXCOL)colp)->Init(g) && !Accept) if (((PPRXCOL)colp)->Init(g, NULL) && !Accept)
return TRUE; return TRUE;
if (Tablist) if (Tablist)
@@ -352,7 +352,9 @@ bool TDBTBL::TestFil(PGLOBAL g, PCFIL filp, PTABLE tabp)
/***********************************************************************/ /***********************************************************************/
int TDBTBL::Cardinality(PGLOBAL g) int TDBTBL::Cardinality(PGLOBAL g)
{ {
if (Cardinal < 0) { if (!g)
return 0; // Cannot make the table list
else if (Cardinal < 0) {
int tsz; int tsz;
if (!Tablist && InitTableList(g)) if (!Tablist && InitTableList(g))
@@ -468,7 +470,7 @@ bool TDBTBL::OpenDB(PGLOBAL g)
for (PCOL cp = Columns; cp; cp = cp->GetNext()) for (PCOL cp = Columns; cp; cp = cp->GetNext())
if (cp->GetAmType() == TYPE_AM_TABID) if (cp->GetAmType() == TYPE_AM_TABID)
cp->COLBLK::Reset(); cp->COLBLK::Reset();
else if (((PPRXCOL)cp)->Init(g) && !Accept) else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
return TRUE; return TRUE;
if (trace) if (trace)
@@ -523,7 +525,7 @@ int TDBTBL::ReadDB(PGLOBAL g)
if (cp->GetAmType() == TYPE_AM_TABID || if (cp->GetAmType() == TYPE_AM_TABID ||
cp->GetAmType() == TYPE_AM_SRVID) cp->GetAmType() == TYPE_AM_SRVID)
cp->COLBLK::Reset(); cp->COLBLK::Reset();
else if (((PPRXCOL)cp)->Init(g) && !Accept) else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
return RC_FX; return RC_FX;
if (trace) if (trace)
@@ -716,7 +718,7 @@ bool TDBTBM::OpenDB(PGLOBAL g)
for (PCOL cp = Columns; cp; cp = cp->GetNext()) for (PCOL cp = Columns; cp; cp = cp->GetNext())
if (cp->GetAmType() == TYPE_AM_TABID) if (cp->GetAmType() == TYPE_AM_TABID)
cp->COLBLK::Reset(); cp->COLBLK::Reset();
else if (((PPRXCOL)cp)->Init(g) && !Accept) else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
return TRUE; return TRUE;
if (trace) if (trace)
@@ -807,7 +809,7 @@ int TDBTBM::ReadNextRemote(PGLOBAL g)
for (PCOL cp = Columns; cp; cp = cp->GetNext()) for (PCOL cp = Columns; cp; cp = cp->GetNext())
if (cp->GetAmType() == TYPE_AM_TABID) if (cp->GetAmType() == TYPE_AM_TABID)
cp->COLBLK::Reset(); cp->COLBLK::Reset();
else if (((PPRXCOL)cp)->Init(g) && !Accept) else if (((PPRXCOL)cp)->Init(g, NULL) && !Accept)
return RC_FX; return RC_FX;
if (trace) if (trace)

View File

@@ -54,7 +54,8 @@
#include "tabutil.h" #include "tabutil.h"
#include "ha_connect.h" #include "ha_connect.h"
extern "C" int zconv; //extern "C" int zconv;
int GetConvSize(void);
/************************************************************************/ /************************************************************************/
/* Used by MYSQL tables to get MySQL parameters from the calling proxy */ /* Used by MYSQL tables to get MySQL parameters from the calling proxy */
@@ -132,6 +133,7 @@ PQRYRES TabColumns(PGLOBAL g, THD *thd, const char *db,
char *fld, *colname, *chset, *fmt, v; char *fld, *colname, *chset, *fmt, v;
int i, n, ncol = sizeof(buftyp) / sizeof(int); int i, n, ncol = sizeof(buftyp) / sizeof(int);
int prec, len, type, scale; int prec, len, type, scale;
int zconv = GetConvSize();
bool mysql; bool mysql;
TABLE_SHARE *s = NULL; TABLE_SHARE *s = NULL;
Field* *field; Field* *field;
@@ -668,6 +670,22 @@ PRXCOL::PRXCOL(PRXCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
Colnum = col1->Colnum; Colnum = col1->Colnum;
} // end of PRXCOL copy constructor } // end of PRXCOL copy constructor
/***********************************************************************/
/* Convert an UTF-8 name to latin characters. */
/***********************************************************************/
char *PRXCOL::Decode(PGLOBAL g, const char *cnm)
{
char *buf= (char*)PlugSubAlloc(g, NULL, strlen(cnm) + 1);
uint dummy_errors;
uint32 len= copy_and_convert(buf, strlen(cnm) + 1,
&my_charset_latin1,
cnm, strlen(cnm),
&my_charset_utf8_general_ci,
&dummy_errors);
buf[len]= '\0';
return buf;
} // end of Decode
/***********************************************************************/ /***********************************************************************/
/* PRXCOL initialization routine. */ /* PRXCOL initialization routine. */
/* Look for the matching column in the object table. */ /* Look for the matching column in the object table. */
@@ -683,6 +701,9 @@ bool PRXCOL::Init(PGLOBAL g, PTDBASE tp)
if (Colp) { if (Colp) {
MODE mode = To_Tdb->GetMode(); MODE mode = To_Tdb->GetMode();
// Needed for MYSQL subtables
((XCOLBLK*)Colp)->Name = Decode(g, Colp->GetName());
// May not have been done elsewhere // May not have been done elsewhere
Colp->InitValue(g); Colp->InitValue(g);
To_Val = Colp->GetValue(); To_Val = Colp->GetValue();

View File

@@ -108,15 +108,18 @@ class DllExport PRXCOL : public COLBLK {
virtual int GetAmType(void) {return TYPE_AM_PRX;} virtual int GetAmType(void) {return TYPE_AM_PRX;}
// Methods // Methods
using COLBLK::Init;
virtual void Reset(void); virtual void Reset(void);
virtual bool IsSpecial(void) {return Pseudo;} virtual bool IsSpecial(void) {return Pseudo;}
virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check) virtual bool SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
{return false;} {return false;}
virtual void ReadColumn(PGLOBAL g); virtual void ReadColumn(PGLOBAL g);
virtual void WriteColumn(PGLOBAL g); virtual void WriteColumn(PGLOBAL g);
virtual bool Init(PGLOBAL g, PTDBASE tp = NULL); virtual bool Init(PGLOBAL g, PTDBASE tp);
protected: protected:
char *Decode(PGLOBAL g, const char *cnm);
// Default constructor not to be used // Default constructor not to be used
PRXCOL(void) {} PRXCOL(void) {}
@@ -144,4 +147,8 @@ class TDBTBC : public TDBCAT {
PSZ Tab; // Table name PSZ Tab; // Table name
}; // end of class TDBMCL }; // end of class TDBMCL
class XCOLBLK : public COLBLK {
friend class PRXCOL;
}; // end of class XCOLBLK
#endif // TABUTIL #endif // TABUTIL

View File

@@ -183,7 +183,7 @@ bool TDBXCL::OpenDB(PGLOBAL g)
/*********************************************************************/ /*********************************************************************/
for (PCOL cp = Columns; cp; cp = cp->GetNext()) for (PCOL cp = Columns; cp; cp = cp->GetNext())
if (!cp->IsSpecial()) if (!cp->IsSpecial())
if (((PPRXCOL)cp)->Init(g)) if (((PPRXCOL)cp)->Init(g, NULL))
return TRUE; return TRUE;
/*********************************************************************/ /*********************************************************************/

View File

@@ -88,6 +88,7 @@ class XCLCOL : public PRXCOL {
XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i); XCLCOL(PGLOBAL g, PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i);
// Methods // Methods
using PRXCOL::Init;
virtual void Reset(void) {} // Evaluated only by TDBXCL virtual void Reset(void) {} // Evaluated only by TDBXCL
virtual void ReadColumn(PGLOBAL g); virtual void ReadColumn(PGLOBAL g);
virtual bool Init(PGLOBAL g, PTDBASE tp = NULL); virtual bool Init(PGLOBAL g, PTDBASE tp = NULL);

View File

@@ -163,6 +163,7 @@ class TYPBLK : public VALBLK {
virtual void Reset(int n) {Typp[n] = 0;} virtual void Reset(int n) {Typp[n] = 0;}
// Methods // Methods
using VALBLK::SetValue;
virtual void SetValue(PSZ sp, int n); virtual void SetValue(PSZ sp, int n);
virtual void SetValue(char *sp, uint len, int n); virtual void SetValue(char *sp, uint len, int n);
virtual void SetValue(short sval, int n) virtual void SetValue(short sval, int n)
@@ -233,6 +234,7 @@ class CHRBLK : public VALBLK {
virtual bool IsCi(void) {return Ci;} virtual bool IsCi(void) {return Ci;}
// Methods // Methods
using VALBLK::SetValue;
virtual void SetValue(PSZ sp, int n); virtual void SetValue(PSZ sp, int n);
virtual void SetValue(char *sp, uint len, int n); virtual void SetValue(char *sp, uint len, int n);
virtual void SetValue(PVAL valp, int n); virtual void SetValue(PVAL valp, int n);
@@ -286,6 +288,7 @@ class STRBLK : public VALBLK {
virtual void Reset(int n) {Strp[n] = NULL;} virtual void Reset(int n) {Strp[n] = NULL;}
// Methods // Methods
using VALBLK::SetValue;
virtual void SetValue(PSZ sp, int n); virtual void SetValue(PSZ sp, int n);
virtual void SetValue(char *sp, uint len, int n); virtual void SetValue(char *sp, uint len, int n);
virtual void SetValue(PVAL valp, int n); virtual void SetValue(PVAL valp, int n);
@@ -322,6 +325,7 @@ class DATBLK : public TYPBLK<int> {
virtual char *GetCharString(char *p, int n); virtual char *GetCharString(char *p, int n);
// Methods // Methods
using TYPBLK<int>::SetValue;
virtual void SetValue(PSZ sp, int n); virtual void SetValue(PSZ sp, int n);
protected: protected:
@@ -345,6 +349,8 @@ class PTRBLK : public STRBLK {
// Implementation // Implementation
// Methods // Methods
using STRBLK::SetValue;
using STRBLK::CompVal;
virtual void SetValue(PSZ p, int n) {Strp[n] = p;} virtual void SetValue(PSZ p, int n) {Strp[n] = p;}
virtual int CompVal(int i1, int i2); virtual int CompVal(int i1, int i2);

View File

@@ -436,6 +436,9 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns)
bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned(); bool un = (uns < 0) ? false : (uns > 0) ? true : valp->IsUnsigned();
PVAL vp; PVAL vp;
if (!valp)
return NULL;
if (newtype == TYPE_VOID) // Means allocate a value of the same type if (newtype == TYPE_VOID) // Means allocate a value of the same type
newtype = valp->GetType(); newtype = valp->GetType();
@@ -443,8 +446,8 @@ PVAL AllocateValue(PGLOBAL g, PVAL valp, int newtype, int uns)
case TYPE_STRING: case TYPE_STRING:
p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen()); p = (PSZ)PlugSubAlloc(g, NULL, 1 + valp->GetValLen());
if ((sp = valp->GetCharString(p)) != p) if ((sp = valp->GetCharString(p)) != p && sp)
strcpy (p, sp); strcpy(p, sp);
vp = new(g) TYPVAL<PSZ>(g, p, valp->GetValLen(), valp->GetValPrec()); vp = new(g) TYPVAL<PSZ>(g, p, valp->GetValLen(), valp->GetValPrec());
break; break;
@@ -1216,12 +1219,12 @@ TYPVAL<PSZ>::TYPVAL(PSZ s) : VALUE(TYPE_STRING)
TYPVAL<PSZ>::TYPVAL(PGLOBAL g, PSZ s, int n, int c) TYPVAL<PSZ>::TYPVAL(PGLOBAL g, PSZ s, int n, int c)
: VALUE(TYPE_STRING) : VALUE(TYPE_STRING)
{ {
Len = (g) ? n : strlen(s); Len = (g) ? n : (s) ? strlen(s) : 0;
if (!s) { if (!s) {
if (g) { if (g) {
if ((Strp = (char *)PlgDBSubAlloc(g, NULL, Len + 1))) if ((Strp = (char *)PlgDBSubAlloc(g, NULL, Len + 1)))
Strp[Len] = '\0'; memset(Strp, 0, Len + 1);
else else
Len = 0; Len = 0;

View File

@@ -391,6 +391,7 @@ class DllExport XHUGE : public XLOAD {
XHUGE(void) : XLOAD() {} XHUGE(void) : XLOAD() {}
// Methods // Methods
using XLOAD::Close;
virtual bool Open(PGLOBAL g, char *filename, int id, MODE mode); virtual bool Open(PGLOBAL g, char *filename, int id, MODE mode);
virtual bool Seek(PGLOBAL g, int low, int high, int origin); virtual bool Seek(PGLOBAL g, int low, int high, int origin);
virtual bool Read(PGLOBAL g, void *buf, int n, int size); virtual bool Read(PGLOBAL g, void *buf, int n, int size);

View File

@@ -346,6 +346,31 @@ bool STRING::Append(char c)
return false; return false;
} // end of Append } // end of Append
/***********************************************************************/
/* Append a quoted PSZ to a STRING. */
/***********************************************************************/
bool STRING::Append_quoted(PSZ s)
{
bool b = Append('\'');
if (s) for (char *p = s; !b && *p; p++)
switch (*p) {
case '\'':
case '\\':
case '\t':
case '\n':
case '\r':
case '\b':
case '\f': b |= Append('\\');
// passthru
default:
b |= Append(*p);
break;
} // endswitch *p
return (b |= Append('\''));
} // end of Append_quoted
/***********************************************************************/ /***********************************************************************/
/* Resize to given length but only when last suballocated. */ /* Resize to given length but only when last suballocated. */
/* New size should be greater than string length. */ /* New size should be greater than string length. */

View File

@@ -138,6 +138,7 @@ class DllExport STRING : public BLOCK {
bool Append(STRING &str); bool Append(STRING &str);
bool Append(char c); bool Append(char c);
bool Resize(uint n); bool Resize(uint n);
bool Append_quoted(PSZ s);
inline void Trim(void) {(void)Resize(Length + 1);} inline void Trim(void) {(void)Resize(Length + 1);}
inline void Chop(void) {if (Length) Strp[--Length] = 0;} inline void Chop(void) {if (Length) Strp[--Length] = 0;}
inline void RepLast(char c) {if (Length) Strp[Length-1] = c;} inline void RepLast(char c) {if (Length) Strp[Length-1] = c;}

View File

@@ -3055,6 +3055,12 @@ func_start:
/* 2. Allocate a new page to the index */ /* 2. Allocate a new page to the index */
new_block = btr_page_alloc(cursor->index, hint_page_no, direction, new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
btr_page_get_level(page, mtr), mtr, mtr); btr_page_get_level(page, mtr), mtr, mtr);
/* Play safe, if new page is not allocated */
if (!new_block) {
return(rec);
}
new_page = buf_block_get_frame(new_block); new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block); new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, cursor->index, btr_page_create(new_block, new_page_zip, cursor->index,

View File

@@ -2368,15 +2368,15 @@ btr_cur_pess_upd_restore_supremum(
Check if the total length of the modified blob for the row is within 10% Check if the total length of the modified blob for the row is within 10%
of the total redo log size. This constraint on the blob length is to of the total redo log size. This constraint on the blob length is to
avoid overwriting the redo logs beyond the last checkpoint lsn. avoid overwriting the redo logs beyond the last checkpoint lsn.
@return DB_SUCCESS or DB_TOO_BIG_RECORD. */ @return DB_SUCCESS or DB_TOO_BIG_FOR_REDO. */
static static
dberr_t dberr_t
btr_check_blob_limit(const big_rec_t* big_rec_vec) btr_check_blob_limit(const big_rec_t* big_rec_vec)
{ {
const ib_uint64_t redo_size = srv_n_log_files * srv_log_file_size const ib_uint64_t redo_size = srv_n_log_files * srv_log_file_size
* UNIV_PAGE_SIZE; * UNIV_PAGE_SIZE;
const ulint redo_10p = redo_size / 10; const ib_uint64_t redo_10p = redo_size / 10;
ulint total_blob_len = 0; ib_uint64_t total_blob_len = 0;
dberr_t err = DB_SUCCESS; dberr_t err = DB_SUCCESS;
/* Calculate the total number of bytes for blob data */ /* Calculate the total number of bytes for blob data */
@@ -2386,11 +2386,11 @@ btr_check_blob_limit(const big_rec_t* big_rec_vec)
if (total_blob_len > redo_10p) { if (total_blob_len > redo_10p) {
ib_logf(IB_LOG_LEVEL_ERROR, "The total blob data" ib_logf(IB_LOG_LEVEL_ERROR, "The total blob data"
" length (" ULINTPF ") is greater than" " length (" UINT64PF ") is greater than"
" 10%% of the total redo log size (" UINT64PF " 10%% of the total redo log size (" UINT64PF
"). Please increase total redo log size.", "). Please increase total redo log size.",
total_blob_len, redo_size); total_blob_len, redo_size);
err = DB_TOO_BIG_RECORD; err = DB_TOO_BIG_FOR_REDO;
} }
return(err); return(err);
@@ -4453,7 +4453,7 @@ Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The extern flags in rec will have to be set beforehand. them in rec. The extern flags in rec will have to be set beforehand.
The fields are stored on pages allocated from leaf node The fields are stored on pages allocated from leaf node
file segment of the index tree. file segment of the index tree.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ @return DB_SUCCESS or DB_OUT_OF_FILE_SPACE or DB_TOO_BIG_FOR_REDO */
UNIV_INTERN UNIV_INTERN
dberr_t dberr_t
btr_store_big_rec_extern_fields( btr_store_big_rec_extern_fields(

View File

@@ -2427,10 +2427,10 @@ too_big:
dict_mem_index_free(new_index); dict_mem_index_free(new_index);
dict_mem_index_free(index); dict_mem_index_free(index);
return(DB_TOO_BIG_RECORD); return(DB_TOO_BIG_RECORD);
} else { } else if (current_thd != NULL) {
/* Avoid the warning to be printed
during recovery. */
ib_warn_row_too_big(table); ib_warn_row_too_big(table);
} }
} }

View File

@@ -319,6 +319,9 @@ dict_mem_table_col_rename_low(
ut_ad(from_len <= NAME_LEN); ut_ad(from_len <= NAME_LEN);
ut_ad(to_len <= NAME_LEN); ut_ad(to_len <= NAME_LEN);
char from[NAME_LEN];
strncpy(from, s, NAME_LEN);
if (from_len == to_len) { if (from_len == to_len) {
/* The easy case: simply replace the column name in /* The easy case: simply replace the column name in
table->col_names. */ table->col_names. */
@@ -386,14 +389,53 @@ dict_mem_table_col_rename_low(
foreign = *it; foreign = *it;
for (unsigned f = 0; f < foreign->n_fields; f++) { if (foreign->foreign_index == NULL) {
/* These can point straight to /* We may go here when we set foreign_key_checks to 0,
table->col_names, because the foreign key and then try to rename a column and modify the
constraints will be freed at the same time corresponding foreign key constraint. The index
when the table object is freed. */ would have been dropped, we have to find an equivalent
foreign->foreign_col_names[f] one */
= dict_index_get_nth_field( for (unsigned f = 0; f < foreign->n_fields; f++) {
foreign->foreign_index, f)->name; if (strcmp(foreign->foreign_col_names[f], from)
== 0) {
char** rc = const_cast<char**>(
foreign->foreign_col_names
+ f);
if (to_len <= strlen(*rc)) {
memcpy(*rc, to, to_len + 1);
} else {
*rc = static_cast<char*>(
mem_heap_dup(
foreign->heap,
to,
to_len + 1));
}
}
}
dict_index_t* new_index = dict_foreign_find_index(
foreign->foreign_table, NULL,
foreign->foreign_col_names,
foreign->n_fields, NULL, true, false);
/* There must be an equivalent index in this case. */
ut_ad(new_index != NULL);
foreign->foreign_index = new_index;
} else {
for (unsigned f = 0; f < foreign->n_fields; f++) {
/* These can point straight to
table->col_names, because the foreign key
constraints will be freed at the same time
when the table object is freed. */
foreign->foreign_col_names[f]
= dict_index_get_nth_field(
foreign->foreign_index,
f)->name;
}
} }
} }
@@ -403,6 +445,8 @@ dict_mem_table_col_rename_low(
foreign = *it; foreign = *it;
ut_ad(foreign->referenced_index != NULL);
for (unsigned f = 0; f < foreign->n_fields; f++) { for (unsigned f = 0; f < foreign->n_fields; f++) {
/* foreign->referenced_col_names[] need to be /* foreign->referenced_col_names[] need to be
copies, because the constraint may become copies, because the constraint may become

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