merge
This commit is contained in:
commit
5a8b8b6493
@ -75,4 +75,40 @@ CALL p1 ();
|
||||
ERROR HY000: Trigger does not exist
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Bug#54375: Error in stored procedure leaves connection
|
||||
# in different default schema
|
||||
#
|
||||
SET @@SQL_MODE = 'STRICT_ALL_TABLES';
|
||||
DROP DATABASE IF EXISTS db1;
|
||||
CREATE DATABASE db1;
|
||||
USE db1;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (c1 int NOT NULL PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES (1);
|
||||
CREATE FUNCTION f1 (
|
||||
some_value int
|
||||
)
|
||||
RETURNS smallint
|
||||
DETERMINISTIC
|
||||
BEGIN
|
||||
INSERT INTO t1 SET c1 = some_value;
|
||||
RETURN(LAST_INSERT_ID());
|
||||
END$$
|
||||
DROP DATABASE IF EXISTS db2;
|
||||
CREATE DATABASE db2;
|
||||
USE db2;
|
||||
SELECT DATABASE();
|
||||
DATABASE()
|
||||
db2
|
||||
SELECT db1.f1(1);
|
||||
ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
|
||||
SELECT DATABASE();
|
||||
DATABASE()
|
||||
db2
|
||||
USE test;
|
||||
DROP FUNCTION db1.f1;
|
||||
DROP TABLE db1.t1;
|
||||
DROP DATABASE db1;
|
||||
DROP DATABASE db2;
|
||||
End of 5.1 tests
|
||||
|
@ -1,20 +0,0 @@
|
||||
# Check for IBM i 6.1 or later
|
||||
--disable_query_log
|
||||
system uname -rv > $MYSQLTEST_VARDIR/tmp/version;
|
||||
--disable_warnings
|
||||
drop table if exists uname_vr;
|
||||
--enable_warnings
|
||||
create temporary table uname_vr (r int, v int);
|
||||
--disable_warnings
|
||||
eval LOAD DATA INFILE "$MYSQLTEST_VARDIR/tmp/version" into table uname_vr fields terminated by ' ';
|
||||
--enable_warnings
|
||||
let $ok = `select count(*) from uname_vr where v = 5 and r = 4`;
|
||||
drop table uname_vr;
|
||||
remove_file $MYSQLTEST_VARDIR/tmp/version;
|
||||
--enable_query_log
|
||||
if (!$ok)
|
||||
{
|
||||
skip "Need IBM i 5.4 or later";
|
||||
}
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
# Check for IBM i 6.1 or later
|
||||
--disable_query_log
|
||||
system uname -rv > $MYSQLTEST_VARDIR/tmp/version;
|
||||
--disable_warnings
|
||||
drop table if exists uname_vr;
|
||||
--enable_warnings
|
||||
create temporary table uname_vr (r int, v int);
|
||||
--disable_warnings
|
||||
eval LOAD DATA INFILE "$MYSQLTEST_VARDIR/tmp/version" into table uname_vr fields terminated by ' ';
|
||||
--enable_warnings
|
||||
let $ok = `select count(*) from uname_vr where v > 5`;
|
||||
drop table uname_vr;
|
||||
remove_file $MYSQLTEST_VARDIR/tmp/version;
|
||||
--enable_query_log
|
||||
if (!$ok)
|
||||
{
|
||||
skip "Need IBM i 6.1 or later";
|
||||
}
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
if (!`SELECT count(*) FROM information_schema.engines WHERE
|
||||
(support = 'YES' OR support = 'DEFAULT') AND
|
||||
engine = 'ibmdb2i'`)
|
||||
{
|
||||
skip Need ibmdb2i engine;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
create schema `A12345_@$#`;
|
||||
create table `A12345_@$#`.t1 (i int) engine=ibmdb2i;
|
||||
show create table `A12345_@$#`.t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`i` int(11) DEFAULT NULL
|
||||
) ENGINE=IBMDB2I DEFAULT CHARSET=latin1
|
||||
select * from `A12345_@$#`.t1;
|
||||
i
|
||||
drop table `A12345_@$#`.t1;
|
||||
drop schema `A12345_@$#`;
|
@ -1,4 +0,0 @@
|
||||
create table t1 (c char(10) collate utf8_swedish_ci, index(c)) engine=ibmdb2i;
|
||||
drop table t1;
|
||||
create table t1 (c char(10) collate ucs2_swedish_ci, index(c)) engine=ibmdb2i;
|
||||
drop table t1;
|
@ -1,4 +0,0 @@
|
||||
create table t1 (c char(1) character set armscii8) engine=ibmdb2i;
|
||||
ERROR HY000: Can't create table 'test.t1' (errno: 2504)
|
||||
create table t1 (c char(1) character set eucjpms ) engine=ibmdb2i;
|
||||
ERROR HY000: Can't create table 'test.t1' (errno: 2504)
|
@ -1,18 +0,0 @@
|
||||
create table ABC (i int) engine=ibmdb2i;
|
||||
drop table ABC;
|
||||
create table `1234567890ABC` (i int) engine=ibmdb2i;
|
||||
drop table `1234567890ABC`;
|
||||
create table `!@#$%` (i int) engine=ibmdb2i;
|
||||
drop table `!@#$%`;
|
||||
create table `ABCD#########` (i int) engine=ibmdb2i;
|
||||
drop table `ABCD#########`;
|
||||
create table `_` (i int) engine=ibmdb2i;
|
||||
drop table `_`;
|
||||
create table `abc##def` (i int) engine=ibmdb2i;
|
||||
drop table `abc##def`;
|
||||
set names utf8;
|
||||
create table İ (s1 int) engine=ibmdb2i;
|
||||
drop table İ;
|
||||
create table İİ (s1 int) engine=ibmdb2i;
|
||||
drop table İİ;
|
||||
set names latin1;
|
@ -1,33 +0,0 @@
|
||||
drop table if exists t1;
|
||||
create table t1 (c char(10), index(c)) collate ucs2_czech_ci engine=ibmdb2i;
|
||||
insert into t1 values ("ch"),("h"),("i");
|
||||
select * from t1 order by c;
|
||||
c
|
||||
h
|
||||
ch
|
||||
i
|
||||
drop table t1;
|
||||
create table t1 (c char(10), index(c)) collate utf8_czech_ci engine=ibmdb2i;
|
||||
insert into t1 values ("ch"),("h"),("i");
|
||||
select * from t1 order by c;
|
||||
c
|
||||
h
|
||||
ch
|
||||
i
|
||||
drop table t1;
|
||||
create table t1 (c char(10), index(c)) collate ucs2_danish_ci engine=ibmdb2i;
|
||||
insert into t1 values("abc"),("abcd"),("aaaa");
|
||||
select c from t1 order by c;
|
||||
c
|
||||
abc
|
||||
abcd
|
||||
aaaa
|
||||
drop table t1;
|
||||
create table t1 (c char(10), index(c)) collate utf8_danish_ci engine=ibmdb2i;
|
||||
insert into t1 values("abc"),("abcd"),("aaaa");
|
||||
select c from t1 order by c;
|
||||
c
|
||||
abc
|
||||
abcd
|
||||
aaaa
|
||||
drop table t1;
|
@ -1,7 +0,0 @@
|
||||
drop table if exists t1;
|
||||
create table t1 (c char(10), index(c)) charset macce engine=ibmdb2i;
|
||||
insert into t1 values ("test");
|
||||
select * from t1 order by c;
|
||||
c
|
||||
test
|
||||
drop table t1;
|
@ -1,20 +0,0 @@
|
||||
set ibmdb2i_create_index_option=1;
|
||||
drop schema if exists test1;
|
||||
create schema test1;
|
||||
use test1;
|
||||
CREATE TABLE t1 (f int primary key, index(f)) engine=ibmdb2i;
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (f char(10) collate utf8_bin primary key, index(f)) engine=ibmdb2i;
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (f char(10) collate latin1_swedish_ci primary key, index(f)) engine=ibmdb2i;
|
||||
drop table t1;
|
||||
CREATE TABLE t1 (f char(10) collate latin1_swedish_ci primary key, i int, index i(i,f)) engine=ibmdb2i;
|
||||
drop table t1;
|
||||
create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i;
|
||||
select * from fd;
|
||||
SQSSEQ
|
||||
*HEX
|
||||
*HEX
|
||||
*HEX
|
||||
*HEX
|
||||
drop table fd;
|
@ -1,9 +0,0 @@
|
||||
create table ABC (i int) engine=ibmdb2i;
|
||||
insert into ABC values(1);
|
||||
create table abc (i int) engine=ibmdb2i;
|
||||
insert into abc values (2);
|
||||
select * from ABC;
|
||||
i
|
||||
1
|
||||
drop table ABC;
|
||||
drop table abc;
|
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@
|
||||
source suite/ibmdb2i/include/have_ibmdb2i.inc;
|
||||
source include/have_case_sensitive_file_system.inc;
|
||||
|
||||
create schema `A12345_@$#`;
|
||||
create table `A12345_@$#`.t1 (i int) engine=ibmdb2i;
|
||||
show create table `A12345_@$#`.t1;
|
||||
select * from `A12345_@$#`.t1;
|
||||
drop table `A12345_@$#`.t1;
|
||||
drop schema `A12345_@$#`;
|
@ -1,9 +0,0 @@
|
||||
source suite/ibmdb2i/include/have_ibmdb2i.inc;
|
||||
source suite/ibmdb2i/include/have_i61.inc;
|
||||
|
||||
|
||||
create table t1 (c char(10) collate utf8_swedish_ci, index(c)) engine=ibmdb2i;
|
||||
drop table t1;
|
||||
|
||||
create table t1 (c char(10) collate ucs2_swedish_ci, index(c)) engine=ibmdb2i;
|
||||
drop table t1;
|
@ -1,8 +0,0 @@
|
||||
--source suite/ibmdb2i/include/have_ibmdb2i.inc
|
||||
--source suite/ibmdb2i/include/have_i54.inc
|
||||
|
||||
--error 1005
|
||||
create table t1 (c char(1) character set armscii8) engine=ibmdb2i;
|
||||
|
||||
--error 1005
|
||||
create table t1 (c char(1) character set eucjpms ) engine=ibmdb2i;
|
@ -1,28 +0,0 @@
|
||||
source suite/ibmdb2i/include/have_ibmdb2i.inc;
|
||||
|
||||
# Test RCDFMT generation for a variety of kinds of table names
|
||||
create table ABC (i int) engine=ibmdb2i;
|
||||
drop table ABC;
|
||||
|
||||
create table `1234567890ABC` (i int) engine=ibmdb2i;
|
||||
drop table `1234567890ABC`;
|
||||
|
||||
create table `!@#$%` (i int) engine=ibmdb2i;
|
||||
drop table `!@#$%`;
|
||||
|
||||
create table `ABCD#########` (i int) engine=ibmdb2i;
|
||||
drop table `ABCD#########`;
|
||||
|
||||
create table `_` (i int) engine=ibmdb2i;
|
||||
drop table `_`;
|
||||
|
||||
create table `abc##def` (i int) engine=ibmdb2i;
|
||||
drop table `abc##def`;
|
||||
|
||||
set names utf8;
|
||||
create table İ (s1 int) engine=ibmdb2i;
|
||||
drop table İ;
|
||||
|
||||
create table İİ (s1 int) engine=ibmdb2i;
|
||||
drop table İİ;
|
||||
set names latin1;
|
@ -1,26 +0,0 @@
|
||||
source suite/ibmdb2i/include/have_ibmdb2i.inc;
|
||||
source suite/ibmdb2i/include/have_i61.inc;
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
|
||||
create table t1 (c char(10), index(c)) collate ucs2_czech_ci engine=ibmdb2i;
|
||||
insert into t1 values ("ch"),("h"),("i");
|
||||
select * from t1 order by c;
|
||||
drop table t1;
|
||||
|
||||
create table t1 (c char(10), index(c)) collate utf8_czech_ci engine=ibmdb2i;
|
||||
insert into t1 values ("ch"),("h"),("i");
|
||||
select * from t1 order by c;
|
||||
drop table t1;
|
||||
|
||||
create table t1 (c char(10), index(c)) collate ucs2_danish_ci engine=ibmdb2i;
|
||||
insert into t1 values("abc"),("abcd"),("aaaa");
|
||||
select c from t1 order by c;
|
||||
drop table t1;
|
||||
|
||||
create table t1 (c char(10), index(c)) collate utf8_danish_ci engine=ibmdb2i;
|
||||
insert into t1 values("abc"),("abcd"),("aaaa");
|
||||
select c from t1 order by c;
|
||||
drop table t1;
|
@ -1,11 +0,0 @@
|
||||
source suite/ibmdb2i/include/have_ibmdb2i.inc;
|
||||
source suite/ibmdb2i/include/have_i61.inc;
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
|
||||
create table t1 (c char(10), index(c)) charset macce engine=ibmdb2i;
|
||||
insert into t1 values ("test");
|
||||
select * from t1 order by c;
|
||||
drop table t1;
|
@ -1,47 +0,0 @@
|
||||
source suite/ibmdb2i/include/have_ibmdb2i.inc;
|
||||
|
||||
# Confirm that ibmdb2i_create_index_option causes additional *HEX sorted indexes to be created for all non-binary keys.
|
||||
|
||||
set ibmdb2i_create_index_option=1;
|
||||
--disable_warnings
|
||||
drop schema if exists test1;
|
||||
create schema test1;
|
||||
use test1;
|
||||
--enable_warnings
|
||||
|
||||
--disable_abort_on_error
|
||||
--error 0,255
|
||||
exec system "DLTF QGPL/FDOUT" > /dev/null;
|
||||
--enable_abort_on_error
|
||||
|
||||
#No additional index because no string fields in key
|
||||
CREATE TABLE t1 (f int primary key, index(f)) engine=ibmdb2i;
|
||||
--error 255
|
||||
exec system "DSPFD FILE(\"test1\"/PRIM0001) TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
--error 255
|
||||
exec system "DSPFD FILE(\"test1\"/\"f___H_t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
drop table t1;
|
||||
|
||||
#No additional index because binary sorting
|
||||
CREATE TABLE t1 (f char(10) collate utf8_bin primary key, index(f)) engine=ibmdb2i;
|
||||
--error 255
|
||||
exec system "DSPFD FILE(\"test1\"/PRIM0001) TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
--error 255
|
||||
exec system "DSPFD FILE(\"test1\"/\"f___H_t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
drop table t1;
|
||||
|
||||
CREATE TABLE t1 (f char(10) collate latin1_swedish_ci primary key, index(f)) engine=ibmdb2i;
|
||||
exec system "DSPFD FILE(\"test1\"/PRIM0001) TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
exec system "DSPFD FILE(\"test1\"/\"f___H_t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
drop table t1;
|
||||
|
||||
CREATE TABLE t1 (f char(10) collate latin1_swedish_ci primary key, i int, index i(i,f)) engine=ibmdb2i;
|
||||
exec system "DSPFD FILE(\"test1\"/PRIM0001) TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
exec system "DSPFD FILE(\"test1\"/\"i___H_t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
drop table t1;
|
||||
|
||||
|
||||
create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i;
|
||||
system system "CPYF FROMFILE(QGPL/FDOUT) TOFILE(\"test1\"/\"fd\") mbropt(*replace) fmtopt(*drop *map)" > /dev/null;
|
||||
select * from fd;
|
||||
drop table fd;
|
@ -1,10 +0,0 @@
|
||||
source suite/ibmdb2i/include/have_ibmdb2i.inc;
|
||||
source include/have_case_sensitive_file_system.inc;
|
||||
|
||||
create table ABC (i int) engine=ibmdb2i;
|
||||
insert into ABC values(1);
|
||||
create table abc (i int) engine=ibmdb2i;
|
||||
insert into abc values (2);
|
||||
select * from ABC;
|
||||
drop table ABC;
|
||||
drop table abc;
|
@ -1,44 +0,0 @@
|
||||
source suite/ibmdb2i/include/have_ibmdb2i.inc;
|
||||
source suite/ibmdb2i/include/have_i61.inc;
|
||||
--disable_warnings
|
||||
drop table if exists t1, ffd, fd;
|
||||
--enable_warnings
|
||||
|
||||
--disable_abort_on_error
|
||||
--error 0,255
|
||||
exec system "DLTF QGPL/FFDOUT" > /dev/null;
|
||||
--error 0,255
|
||||
exec system "DLTF QGPL/FDOUT" > /dev/null;
|
||||
--enable_abort_on_error
|
||||
let $count= query_get_value(select count(*) from information_schema.COLLATIONS where COLLATION_NAME <> "binary", count(*),1);
|
||||
|
||||
while ($count)
|
||||
{
|
||||
let $collation = query_get_value(select COLLATION_NAME from information_schema.COLLATIONS where COLLATION_NAME <> "binary" order by COLLATION_NAME desc, COLLATION_NAME, $count);
|
||||
error 0,1005,2504,2028;
|
||||
eval CREATE TABLE t1 ($collation integer, c char(10), v varchar(20), index(c), index(v)) collate $collation engine=ibmdb2i;
|
||||
if (!$mysql_errno)
|
||||
{
|
||||
insert into t1 (c,v) values ("abc","def"),("abcd", "def"),("abcde","defg"),("aaaa","bbbb");
|
||||
insert into t1 select * from t1;
|
||||
explain select c,v from t1 force index(c) where c like "ab%";
|
||||
explain select c,v from t1 force index(v) where v like "de%";
|
||||
drop table t1;
|
||||
eval create table t1 ($collation char(10) primary key) collate $collation engine=ibmdb2i;
|
||||
system system "DSPFFD FILE(\"test\"/\"t1\") OUTPUT(*OUTFILE) OUTFILE(QGPL/FFDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
system system "DSPFD FILE(\"test\"/\"t1\") TYPE(*SEQ) OUTPUT(*OUTFILE) OUTFILE(QGPL/FDOUT) OUTMBR(*FIRST *ADD)" > /dev/null;
|
||||
drop table t1;
|
||||
}
|
||||
dec $count;
|
||||
}
|
||||
|
||||
create table ffd (WHCHD1 CHAR(20), WHCSID decimal(5,0)) engine=ibmdb2i;
|
||||
system system "CPYF FROMFILE(QGPL/FFDOUT) TOFILE(\"test\"/\"ffd\") mbropt(*replace) fmtopt(*drop *map)" > /dev/null;
|
||||
create table fd (SQSSEQ CHAR(10)) engine=ibmdb2i;
|
||||
system system "CPYF FROMFILE(QGPL/FDOUT) TOFILE(\"test\"/\"fd\") mbropt(*replace) fmtopt(*drop *map)" > /dev/null;
|
||||
create temporary table intermed (row integer key auto_increment, cs char(30), ccsid integer);
|
||||
insert into intermed (cs, ccsid) select * from ffd;
|
||||
create temporary table intermed2 (row integer key auto_increment, srtseq char(10));
|
||||
insert into intermed2 (srtseq) select * from fd;
|
||||
select ccsid, cs, srtseq from intermed inner join intermed2 on intermed.row = intermed2.row;
|
||||
drop table ffd, fd;
|
@ -101,4 +101,41 @@ CALL p1 ();
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo #
|
||||
--echo # Bug#54375: Error in stored procedure leaves connection
|
||||
--echo # in different default schema
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
SET @@SQL_MODE = 'STRICT_ALL_TABLES';
|
||||
DROP DATABASE IF EXISTS db1;
|
||||
CREATE DATABASE db1;
|
||||
USE db1;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (c1 int NOT NULL PRIMARY KEY);
|
||||
INSERT INTO t1 VALUES (1);
|
||||
DELIMITER $$;
|
||||
CREATE FUNCTION f1 (
|
||||
some_value int
|
||||
)
|
||||
RETURNS smallint
|
||||
DETERMINISTIC
|
||||
BEGIN
|
||||
INSERT INTO t1 SET c1 = some_value;
|
||||
RETURN(LAST_INSERT_ID());
|
||||
END$$
|
||||
DELIMITER ;$$
|
||||
DROP DATABASE IF EXISTS db2;
|
||||
CREATE DATABASE db2;
|
||||
--enable_warnings
|
||||
USE db2;
|
||||
SELECT DATABASE();
|
||||
--error ER_DUP_ENTRY
|
||||
SELECT db1.f1(1);
|
||||
SELECT DATABASE();
|
||||
USE test;
|
||||
DROP FUNCTION db1.f1;
|
||||
DROP TABLE db1.t1;
|
||||
DROP DATABASE db1;
|
||||
DROP DATABASE db2;
|
||||
--echo End of 5.1 tests
|
||||
|
@ -1510,7 +1510,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
|
||||
If the DB has changed, the pointer has changed too, but the
|
||||
original thd->db will then have been freed
|
||||
*/
|
||||
if (cur_db_changed && !thd->killed)
|
||||
if (cur_db_changed && thd->killed != THD::KILL_CONNECTION)
|
||||
{
|
||||
/*
|
||||
Force switching back to the saved current database, because it may be
|
||||
|
@ -1,39 +0,0 @@
|
||||
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
CHECK_INCLUDE_FILES(qlgusr.h HAVE_PASE_ENVIRONMENT)
|
||||
IF(HAVE_PASE_ENVIRONMENT)
|
||||
|
||||
INCLUDE_DIRECTORIES(
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_BINARY_DIR}/include
|
||||
${CMAKE_SOURCE_DIR}/regex
|
||||
${CMAKE_SOURCE_DIR}/sql
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
/afs/rchland.ibm.com/lande/shadow/dev2000/osxpf/v5r4m0f.xpf/cur/cmvc/base.pgm/my.xpf/apis
|
||||
/afs/rchland.ibm.com/lande/shadow/dev2000/osxpf/v5r4m0.xpf/bld/cmvc/base.pgm/lg.xpf
|
||||
/afs/rchland.ibm.com/lande/shadow/dev2000/osxpf/v5r4m0.xpf/bld/cmvc/base.pgm/tq.xpf
|
||||
)
|
||||
|
||||
|
||||
SET (IBMDB2I_SOURCES ha_ibmdb2i.cc db2i_ileBridge.cc db2i_conversion.cc
|
||||
db2i_blobCollection.cc db2i_file.cc db2i_charsetSupport.cc
|
||||
db2i_collationSupport.cc db2i_errors.cc db2i_constraints.cc
|
||||
db2i_rir.cc db2i_sqlStatementStream.cc db2i_ioBuffers.cc db2i_myconv.cc)
|
||||
|
||||
|
||||
MYSQL_ADD_PLUGIN(ibmdb2i ${IBMDB2I_SOURCES} STORAGE_ENGINE LINK_LIBRARIES iconv)
|
||||
|
||||
ENDIF(HAVE_PASE_ENVIRONMENT)
|
@ -1,52 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2007, 2008, IBM Corporation.
|
||||
# All rights reserved.
|
||||
#
|
||||
#
|
||||
|
||||
#called from the top level Makefile
|
||||
|
||||
MYSQLDATAdir = $(localstatedir)
|
||||
MYSQLSHAREdir = $(pkgdatadir)
|
||||
MYSQLBASEdir= $(prefix)
|
||||
MYSQLLIBdir= $(pkglibdir)
|
||||
pkgplugindir = $(pkglibdir)/plugin
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include \
|
||||
-I$(top_srcdir)/regex \
|
||||
-I$(top_srcdir)/sql \
|
||||
-I$(srcdir) \
|
||||
-I$ /afs/rchland.ibm.com/lande/shadow/dev2000/osxpf/v5r4m0f.xpf/cur/cmvc/base.pgm/my.xpf/apis \
|
||||
-I$ /afs/rchland.ibm.com/lande/shadow/dev2000/osxpf/v5r4m0.xpf/bld/cmvc/base.pgm/lg.xpf \
|
||||
-I$ /afs/rchland.ibm.com/lande/shadow/dev2000/osxpf/v5r4m0.xpf/bld/cmvc/base.pgm/tq.xpf
|
||||
WRAPLIBS=
|
||||
|
||||
LDADD =
|
||||
|
||||
DEFS = @DEFS@
|
||||
|
||||
noinst_HEADERS = ha_ibmdb2i.h db2i_collationSupport.h db2i_file.h \
|
||||
db2i_ioBuffers.h db2i_blobCollection.h \
|
||||
db2i_global.h db2i_misc.h db2i_charsetSupport.h db2i_errors.h \
|
||||
db2i_iconv.h db2i_myconv.h db2i_safeString.h db2i_sqlStatementStream.h \
|
||||
db2i_ileBridge.h db2i_validatedPointer.h
|
||||
|
||||
EXTRA_LTLIBRARIES = ha_ibmdb2i.la
|
||||
pkgplugin_LTLIBRARIES = @plugin_ibmdb2i_shared_target@
|
||||
ha_ibmdb2i_la_LIBADD = -liconv
|
||||
ha_ibmdb2i_la_LDFLAGS = -module -rpath $(MYSQLLIBdir)
|
||||
ha_ibmdb2i_la_CXXFLAGS= $(AM_CXXFLAGS) -DMYSQL_DYNAMIC_PLUGIN
|
||||
ha_ibmdb2i_la_CFLAGS = $(AM_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
|
||||
ha_ibmdb2i_la_SOURCES = ha_ibmdb2i.cc db2i_ileBridge.cc db2i_conversion.cc \
|
||||
db2i_blobCollection.cc db2i_file.cc db2i_charsetSupport.cc \
|
||||
db2i_collationSupport.cc db2i_errors.cc db2i_constraints.cc \
|
||||
db2i_rir.cc db2i_sqlStatementStream.cc db2i_ioBuffers.cc \
|
||||
db2i_myconv.cc
|
||||
|
||||
EXTRA_LIBRARIES = libibmdb2i.a
|
||||
noinst_LIBRARIES = @plugin_ibmdb2i_static_target@
|
||||
libibmdb2i_a_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
libibmdb2i_a_CFLAGS = $(AM_CFLAGS)
|
||||
libibmdb2i_a_SOURCES= $(ha_ibmdb2i_la_SOURCES)
|
||||
|
||||
|
||||
EXTRA_DIST = CMakeLists.txt plug.in
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "db2i_blobCollection.h"
|
||||
|
||||
/**
|
||||
Return the size to use when allocating space for blob reads.
|
||||
|
||||
@param fieldIndex The field to allocate for
|
||||
@param[out] shouldProtect Indicates whether storage protection should be
|
||||
applied to the space, because the size returned is
|
||||
smaller than the maximum possible size.
|
||||
*/
|
||||
|
||||
uint32
|
||||
BlobCollection::getSizeToAllocate(int fieldIndex, bool& shouldProtect)
|
||||
{
|
||||
Field* field = table->getMySQLTable()->field[fieldIndex];
|
||||
uint fieldLength = field->max_display_length();
|
||||
|
||||
if (fieldLength <= MAX_FULL_ALLOCATE_BLOB_LENGTH)
|
||||
{
|
||||
shouldProtect = false;
|
||||
return fieldLength;
|
||||
}
|
||||
|
||||
shouldProtect = true;
|
||||
|
||||
uint curMaxSize = table->getBlobFieldActualSize(fieldIndex);
|
||||
|
||||
uint defaultAllocSize = min(defaultAllocation, fieldLength);
|
||||
|
||||
return max(defaultAllocSize, curMaxSize);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
BlobCollection::generateBuffer(int fieldIndex)
|
||||
{
|
||||
DBUG_ASSERT(table->db2Field(fieldIndex).isBlob());
|
||||
|
||||
bool protect;
|
||||
buffers[table->getBlobIdFromField(fieldIndex)].Malloc(getSizeToAllocate(fieldIndex, protect), protect);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
Realloc the read buffer associated with a blob field.
|
||||
|
||||
This is used when the previous allocation for a blob field is found to be
|
||||
too small (this is discovered when QMY_READ trips over the protected boundary
|
||||
page).
|
||||
|
||||
@param fieldIndex The field to be reallocated
|
||||
@param size The size of buffer to allocate for this field.
|
||||
*/
|
||||
|
||||
ValidatedPointer<char>&
|
||||
BlobCollection::reallocBuffer(int fieldIndex, size_t size)
|
||||
{
|
||||
ProtectedBuffer& buf = buffers[table->getBlobIdFromField(fieldIndex)];
|
||||
if (size <= buf.allocLen())
|
||||
return buf.ptr();
|
||||
|
||||
table->updateBlobFieldActualSize(fieldIndex, size);
|
||||
|
||||
DBUG_PRINT("BlobCollection::reallocBuffer",("PERF: reallocing %d to %d: ", fieldIndex, size));
|
||||
|
||||
bool protect;
|
||||
buf.Free();
|
||||
buf.Malloc(getSizeToAllocate(fieldIndex, protect), protect);
|
||||
return buf.ptr();
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DB2I_BLOBCOLLECTION_H
|
||||
#define DB2I_BLOBCOLLECTION_H
|
||||
|
||||
#include "db2i_global.h"
|
||||
#include "db2i_file.h"
|
||||
|
||||
/**
|
||||
@class ProtectedBuffer
|
||||
@brief Implements memory management for (optionally) protected buffers.
|
||||
|
||||
Buffers created with the protection option will have a guard page set on the
|
||||
page following requested allocation size. The side effect is that the actual
|
||||
allocation is up to 2*4096-1 bytes larger than the size requested by the
|
||||
using code.
|
||||
*/
|
||||
|
||||
class ProtectedBuffer
|
||||
{
|
||||
public:
|
||||
ProtectedBuffer() : protectBuf(false)
|
||||
{;}
|
||||
|
||||
void Malloc(size_t size, bool protect = false)
|
||||
{
|
||||
protectBuf = protect;
|
||||
bufptr.alloc(size + (protectBuf ? 0x1fff : 0x0));
|
||||
if ((void*)bufptr != NULL)
|
||||
{
|
||||
len = size;
|
||||
if (protectBuf)
|
||||
mprotect(protectedPage(), 0x1000, PROT_NONE);
|
||||
#ifndef DBUG_OFF
|
||||
// Prevents a problem with DBUG_PRINT over-reading in recent versions of
|
||||
// MySQL
|
||||
*((char*)protectedPage()-1) = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Free()
|
||||
{
|
||||
if ((void*)bufptr != NULL)
|
||||
{
|
||||
if (protectBuf)
|
||||
mprotect(protectedPage(), 0x1000, PROT_READ | PROT_WRITE);
|
||||
bufptr.dealloc();
|
||||
}
|
||||
}
|
||||
|
||||
~ProtectedBuffer()
|
||||
{
|
||||
Free();
|
||||
}
|
||||
|
||||
ValidatedPointer<char>& ptr() {return bufptr;}
|
||||
bool isProtected() const {return protectBuf;}
|
||||
size_t allocLen() const {return len;}
|
||||
private:
|
||||
void* protectedPage()
|
||||
{
|
||||
return (void*)(((address64_t)(void*)bufptr + len + 0x1000) & ~0xfff);
|
||||
}
|
||||
|
||||
ValidatedPointer<char> bufptr;
|
||||
size_t len;
|
||||
bool protectBuf;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class BlobCollection
|
||||
@brief Manages memory allocation for reading blobs associated with a table.
|
||||
|
||||
Allocations are done on-demand and are protected with a guard page if less
|
||||
than the max possible size is allocated.
|
||||
*/
|
||||
class BlobCollection
|
||||
{
|
||||
public:
|
||||
BlobCollection(db2i_table* db2Table, uint32 defaultAllocSize) :
|
||||
defaultAllocation(defaultAllocSize), table(db2Table)
|
||||
{
|
||||
buffers = new ProtectedBuffer[table->getBlobCount()];
|
||||
}
|
||||
|
||||
~BlobCollection()
|
||||
{
|
||||
delete[] buffers;
|
||||
}
|
||||
|
||||
ValidatedPointer<char>& getBufferPtr(int fieldIndex)
|
||||
{
|
||||
int blobIndex = table->getBlobIdFromField(fieldIndex);
|
||||
if ((char*)buffers[blobIndex].ptr() == NULL)
|
||||
generateBuffer(fieldIndex);
|
||||
|
||||
return buffers[blobIndex].ptr();
|
||||
}
|
||||
|
||||
ValidatedPointer<char>& reallocBuffer(int fieldIndex, size_t size);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
uint32 getSizeToAllocate(int fieldIndex, bool& shouldProtect);
|
||||
void generateBuffer(int fieldIndex);
|
||||
|
||||
db2i_table* table; // The table being read
|
||||
ProtectedBuffer* buffers; // The buffers
|
||||
uint32 defaultAllocation;
|
||||
/* The default size to use when first allocating a buffer */
|
||||
};
|
||||
|
||||
#endif
|
@ -1,826 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "db2i_charsetSupport.h"
|
||||
#include "as400_types.h"
|
||||
#include "as400_protos.h"
|
||||
#include "db2i_ileBridge.h"
|
||||
#include "qlgusr.h"
|
||||
#include "db2i_errors.h"
|
||||
|
||||
|
||||
/*
|
||||
The following arrays define a mapping between IANA-style text descriptors and
|
||||
IBM i CCSID text descriptors. The mapping is a 1-to-1 correlation between
|
||||
corresponding array slots.
|
||||
*/
|
||||
#define MAX_IANASTRING 23
|
||||
static const char ianaStringType[MAX_IANASTRING][10] =
|
||||
{
|
||||
{"ascii"},
|
||||
{"Big5"}, //big5
|
||||
{"cp1250"},
|
||||
{"cp1251"},
|
||||
{"cp1256"},
|
||||
{"cp850"},
|
||||
{"cp852"},
|
||||
{"cp866"},
|
||||
{"IBM943"}, //cp932
|
||||
{"EUC-KR"}, //euckr
|
||||
{"IBM1381"}, //gb2312
|
||||
{"IBM1386"}, //gbk
|
||||
{"greek"},
|
||||
{"hebrew"},
|
||||
{"latin1"},
|
||||
{"latin2"},
|
||||
{"latin5"},
|
||||
{"macce"},
|
||||
{"tis620"},
|
||||
{"Shift_JIS"}, //sjis
|
||||
{"ucs2"},
|
||||
{"EUC-JP"}, //ujis
|
||||
{"utf8"}
|
||||
};
|
||||
static const char ccsidType[MAX_IANASTRING][6] =
|
||||
{
|
||||
{"367"}, //ascii
|
||||
{"950"}, //big5
|
||||
{"1250"}, //cp1250
|
||||
{"1251"}, //cp1251
|
||||
{"1256"}, //cp1256
|
||||
{"850"}, //cp850
|
||||
{"852"}, //cp852
|
||||
{"866"}, //cp866
|
||||
{"943"}, //cp932
|
||||
{"970"}, //euckr
|
||||
{"1381"}, //gb2312
|
||||
{"1386"}, //gbk
|
||||
{"813"}, //greek
|
||||
{"916"}, //hebrew
|
||||
{"923"}, //latin1
|
||||
{"912"}, //latin2
|
||||
{"920"}, //latin5
|
||||
{"1282"}, //macce
|
||||
{"874"}, //tis620
|
||||
{"943"}, //sjis
|
||||
{"13488"},//ucs2
|
||||
{"5050"}, //ujis
|
||||
{"1208"} //utf8
|
||||
};
|
||||
|
||||
static _ILEpointer *QlgCvtTextDescToDesc_sym;
|
||||
|
||||
/* We keep a cache of the mapping for text descriptions obtained via
|
||||
QlgTextDescToDesc. The following structures implement this cache. */
|
||||
static HASH textDescMapHash;
|
||||
static MEM_ROOT textDescMapMemroot;
|
||||
static pthread_mutex_t textDescMapHashMutex;
|
||||
struct TextDescMap
|
||||
{
|
||||
struct HashKey
|
||||
{
|
||||
int32 inType;
|
||||
int32 outType;
|
||||
char inDesc[Qlg_MaxDescSize];
|
||||
} hashKey;
|
||||
char outDesc[Qlg_MaxDescSize];
|
||||
};
|
||||
|
||||
/* We keep a cache of the mapping for open iconv descriptors. The following
|
||||
structures implement this cache. */
|
||||
static HASH iconvMapHash;
|
||||
static MEM_ROOT iconvMapMemroot;
|
||||
static pthread_mutex_t iconvMapHashMutex;
|
||||
struct IconvMap
|
||||
{
|
||||
struct HashKey
|
||||
{
|
||||
uint32 direction; // These are uint32s to avoid garbage data in the key from compiler padding
|
||||
uint32 db2CCSID;
|
||||
const CHARSET_INFO* myCharset;
|
||||
} hashKey;
|
||||
iconv_t iconvDesc;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Initialize the static structures used by this module.
|
||||
|
||||
This must only be called once per plugin instantiation.
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
int32 initCharsetSupport()
|
||||
{
|
||||
DBUG_ENTER("initCharsetSupport");
|
||||
|
||||
int actmark = _ILELOAD("QSYS/QLGUSR", ILELOAD_LIBOBJ);
|
||||
if ( actmark == -1 )
|
||||
{
|
||||
DBUG_PRINT("initCharsetSupport", ("conversion srvpgm activation failed"));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
QlgCvtTextDescToDesc_sym = (ILEpointer*)malloc_aligned(sizeof(ILEpointer));
|
||||
if (_ILESYM(QlgCvtTextDescToDesc_sym, actmark, "QlgCvtTextDescToDesc") == -1)
|
||||
{
|
||||
DBUG_PRINT("initCharsetSupport",
|
||||
("resolve of QlgCvtTextDescToDesc failed"));
|
||||
DBUG_RETURN(errno);
|
||||
}
|
||||
|
||||
VOID(pthread_mutex_init(&textDescMapHashMutex,MY_MUTEX_INIT_FAST));
|
||||
my_hash_init(&textDescMapHash, &my_charset_bin, 10, offsetof(TextDescMap, hashKey), sizeof(TextDescMap::hashKey), 0, 0, HASH_UNIQUE);
|
||||
|
||||
VOID(pthread_mutex_init(&iconvMapHashMutex,MY_MUTEX_INIT_FAST));
|
||||
my_hash_init(&iconvMapHash, &my_charset_bin, 10, offsetof(IconvMap, hashKey), sizeof(IconvMap::hashKey), 0, 0, HASH_UNIQUE);
|
||||
|
||||
init_alloc_root(&textDescMapMemroot, 2048, 0);
|
||||
init_alloc_root(&iconvMapMemroot, 256, 0);
|
||||
|
||||
initMyconv();
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Cleanup the static structures used by this module.
|
||||
|
||||
This must only be called once per plugin instantiation and only if
|
||||
initCharsetSupport() was successful.
|
||||
*/
|
||||
void doneCharsetSupport()
|
||||
{
|
||||
cleanupMyconv();
|
||||
|
||||
free_root(&textDescMapMemroot, 0);
|
||||
free_root(&iconvMapMemroot, 0);
|
||||
|
||||
pthread_mutex_destroy(&textDescMapHashMutex);
|
||||
my_hash_free(&textDescMapHash);
|
||||
pthread_mutex_destroy(&iconvMapHashMutex);
|
||||
my_hash_free(&iconvMapHash);
|
||||
free_aligned(QlgCvtTextDescToDesc_sym);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert a text description from one type to another.
|
||||
|
||||
This function is just a wrapper for the IBM i QlgTextDescToDesc function plus
|
||||
some overrides for conversions that the API does not handle correctly and
|
||||
support for caching the computed conversion.
|
||||
|
||||
@param inType The type of descriptor pointed to by "in".
|
||||
@param outType The type of descriptor requested for "out".
|
||||
@param in The descriptor to be convereted.
|
||||
@param[out] out The equivalent descriptor
|
||||
@param hashKey The hash key to be used for caching the conversion result.
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
static int32 getNewTextDesc(const int32 inType,
|
||||
const int32 outType,
|
||||
const char* in,
|
||||
char* out,
|
||||
const TextDescMap::HashKey* hashKey)
|
||||
{
|
||||
DBUG_ENTER("db2i_charsetSupport::getNewTextDesc");
|
||||
const arg_type_t signature[] = { ARG_INT32, ARG_INT32, ARG_MEMPTR, ARG_INT32, ARG_MEMPTR, ARG_INT32, ARG_INT32, ARG_END };
|
||||
struct ArgList
|
||||
{
|
||||
ILEarglist_base base;
|
||||
int32 CRDIInType;
|
||||
int32 CRDIOutType;
|
||||
ILEpointer CRDIDesc;
|
||||
int32 CRDIDescSize;
|
||||
ILEpointer CRDODesc;
|
||||
int32 CRDODescSize;
|
||||
int32 CTDCCSID;
|
||||
} *arguments;
|
||||
|
||||
if ((inType == Qlg_TypeIANA) && (outType == Qlg_TypeAix41))
|
||||
{
|
||||
// Override non-standard charsets
|
||||
if (unlikely(strcmp("IBM1381", in) == 0))
|
||||
{
|
||||
strcpy(out, "IBM-1381");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
else if ((inType == Qlg_TypeAS400CCSID) && (outType == Qlg_TypeAix41))
|
||||
{
|
||||
// Override non-standard charsets
|
||||
if (strcmp("1148", in) == 0)
|
||||
{
|
||||
strcpy(out, "IBM-1148");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (unlikely(strcmp("1153", in) == 0))
|
||||
{
|
||||
strcpy(out, "IBM-1153");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
|
||||
char argBuf[sizeof(ArgList)+15];
|
||||
arguments = (ArgList*)roundToQuadWordBdy(argBuf);
|
||||
|
||||
arguments->CRDIInType = inType;
|
||||
arguments->CRDIOutType = outType;
|
||||
arguments->CRDIDesc.s.addr = (address64_t) in;
|
||||
arguments->CRDIDescSize = Qlg_MaxDescSize;
|
||||
arguments->CRDODesc.s.addr = (address64_t) out;
|
||||
arguments->CRDODescSize = Qlg_MaxDescSize;
|
||||
arguments->CTDCCSID = 819;
|
||||
_ILECALL(QlgCvtTextDescToDesc_sym,
|
||||
&arguments->base,
|
||||
signature,
|
||||
RESULT_INT32);
|
||||
if (unlikely(arguments->base.result.s_int32.r_int32 < 0))
|
||||
{
|
||||
if (arguments->base.result.s_int32.r_int32 == Qlg_InDescriptorNotFound)
|
||||
{
|
||||
DBUG_RETURN(DB2I_ERR_UNSUPP_CHARSET);
|
||||
}
|
||||
else
|
||||
{
|
||||
getErrTxt(DB2I_ERR_ILECALL,"QlgCvtTextDescToDesc",arguments->base.result.s_int32.r_int32);
|
||||
DBUG_RETURN(DB2I_ERR_ILECALL);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the conversion information into a cache entry
|
||||
TextDescMap* mapping = (TextDescMap*)alloc_root(&textDescMapMemroot, sizeof(TextDescMap));
|
||||
if (unlikely(!mapping))
|
||||
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
|
||||
memcpy(&(mapping->hashKey), hashKey, sizeof(hashKey));
|
||||
strcpy(mapping->outDesc, out);
|
||||
pthread_mutex_lock(&textDescMapHashMutex);
|
||||
my_hash_insert(&textDescMapHash, (const uchar*)mapping);
|
||||
pthread_mutex_unlock(&textDescMapHashMutex);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert a text description from one type to another.
|
||||
|
||||
This function takes a text description in one representation and converts
|
||||
it into another representation. Although the OS provides some facilities for
|
||||
doing this, the support is not complete, nor does MySQL always use standard
|
||||
identifiers. Therefore, there are a lot of hardcoded overrides required.
|
||||
There is probably some room for optimization here, but this should not be
|
||||
called frequently under most circumstances.
|
||||
|
||||
@param inType The type of descriptor pointed to by "in".
|
||||
@param outType The type of descriptor requested for "out".
|
||||
@param in The descriptor to be convereted.
|
||||
@param[out] out The equivalent descriptor
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
static int32 convertTextDesc(const int32 inType, const int32 outType, const char* inDesc, char* outDesc)
|
||||
{
|
||||
DBUG_ENTER("db2i_charsetSupport::convertTextDesc");
|
||||
const char* inDescOverride;
|
||||
|
||||
if (inType == Qlg_TypeIANA)
|
||||
{
|
||||
// Override non-standard charsets
|
||||
if (strcmp("big5", inDesc) == 0)
|
||||
inDescOverride = "Big5";
|
||||
else if (strcmp("cp932", inDesc) == 0)
|
||||
inDescOverride = "IBM943";
|
||||
else if (strcmp("euckr", inDesc) == 0)
|
||||
inDescOverride = "EUC-KR";
|
||||
else if (strcmp("gb2312", inDesc) == 0)
|
||||
inDescOverride = "IBM1381";
|
||||
else if (strcmp("gbk", inDesc) == 0)
|
||||
inDescOverride = "IBM1386";
|
||||
else if (strcmp("sjis", inDesc) == 0)
|
||||
inDescOverride = "Shift_JIS";
|
||||
else if (strcmp("ujis", inDesc) == 0)
|
||||
inDescOverride = "EUC-JP";
|
||||
else
|
||||
inDescOverride = inDesc;
|
||||
|
||||
// Hardcode non-standard charsets
|
||||
if (outType == Qlg_TypeAix41)
|
||||
{
|
||||
if (strcmp("Big5", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"big5");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (strcmp("IBM1386", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"GBK");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (strcmp("Shift_JIS", inDescOverride) == 0 ||
|
||||
strcmp("IBM943", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"IBM-943");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (strcmp("tis620", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"TIS-620");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (strcmp("ucs2", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"UCS-2");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (strcmp("cp1250", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"IBM-1250");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (strcmp("cp1251", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"IBM-1251");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (strcmp("cp1256", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"IBM-1256");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (strcmp("macce", inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,"IBM-1282");
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
else if (outType == Qlg_TypeAS400CCSID)
|
||||
{
|
||||
// See if we can fast path the convert
|
||||
for (int loopCnt = 0; loopCnt < MAX_IANASTRING; ++loopCnt)
|
||||
{
|
||||
if (strcmp((char*)ianaStringType[loopCnt],inDescOverride) == 0)
|
||||
{
|
||||
strcpy(outDesc,ccsidType[loopCnt]);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
inDescOverride = inDesc;
|
||||
|
||||
// We call getNewTextDesc for all other conversions and cache the result.
|
||||
TextDescMap *mapping;
|
||||
TextDescMap::HashKey hashKey;
|
||||
hashKey.inType= inType;
|
||||
hashKey.outType= outType;
|
||||
uint32 len = strlen(inDescOverride);
|
||||
memcpy(hashKey.inDesc, inDescOverride, len);
|
||||
memset(hashKey.inDesc+len, 0, sizeof(hashKey.inDesc) - len);
|
||||
|
||||
if (!(mapping=(TextDescMap *) my_hash_search(&textDescMapHash,
|
||||
(const uchar*)&hashKey,
|
||||
sizeof(hashKey))))
|
||||
{
|
||||
DBUG_RETURN(getNewTextDesc(inType, outType, inDescOverride, outDesc, &hashKey));
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(outDesc, mapping->outDesc);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Convert an IANA character set name into a DB2 for i CCSID value.
|
||||
|
||||
@param parmIANADesc An IANA character set name
|
||||
@param[out] db2Ccsid The equivalent CCSID value
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
int32 convertIANAToDb2Ccsid(const char* parmIANADesc, uint16* db2Ccsid)
|
||||
{
|
||||
int32 rc;
|
||||
uint16 aixCcsid;
|
||||
char aixCcsidString[Qlg_MaxDescSize];
|
||||
int aixEncodingScheme;
|
||||
int db2EncodingScheme;
|
||||
rc = convertTextDesc(Qlg_TypeIANA, Qlg_TypeAS400CCSID, parmIANADesc, aixCcsidString);
|
||||
if (unlikely(rc))
|
||||
{
|
||||
if (rc == DB2I_ERR_UNSUPP_CHARSET)
|
||||
getErrTxt(DB2I_ERR_UNSUPP_CHARSET, parmIANADesc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
aixCcsid = atoi(aixCcsidString);
|
||||
rc = getEncodingScheme(aixCcsid, aixEncodingScheme);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
switch(aixEncodingScheme) { // Select on encoding scheme
|
||||
case 0x1100: // EDCDIC SBCS
|
||||
case 0x2100: // ASCII SBCS
|
||||
case 0x4100: // AIX SBCS
|
||||
case 0x4105: // MS Windows
|
||||
case 0x5100: // ISO 7 bit ASCII
|
||||
db2EncodingScheme = 0x1100;
|
||||
break;
|
||||
case 0x1200: // EDCDIC DBCS
|
||||
case 0x2200: // ASCII DBCS
|
||||
db2EncodingScheme = 0x1200;
|
||||
break;
|
||||
case 0x1301: // EDCDIC Mixed
|
||||
case 0x2300: // ASCII Mixed
|
||||
case 0x4403: // EUC (ISO 2022)
|
||||
db2EncodingScheme = 0x1301;
|
||||
break;
|
||||
case 0x7200: // UCS2
|
||||
db2EncodingScheme = 0x7200;
|
||||
break;
|
||||
case 0x7807: // UTF-8
|
||||
db2EncodingScheme = 0x7807;
|
||||
break;
|
||||
case 0x7500: // UTF-32
|
||||
db2EncodingScheme = 0x7500;
|
||||
break;
|
||||
default: // Unknown
|
||||
{
|
||||
getErrTxt(DB2I_ERR_UNKNOWN_ENCODING,aixEncodingScheme);
|
||||
return DB2I_ERR_UNKNOWN_ENCODING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (aixEncodingScheme == db2EncodingScheme)
|
||||
{
|
||||
*db2Ccsid = aixCcsid;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = getAssociatedCCSID(aixCcsid, db2EncodingScheme, db2Ccsid); // EDCDIC SBCS
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Obtain the encoding scheme of a CCSID.
|
||||
|
||||
@param inCcsid An IBM i CCSID
|
||||
@param[out] outEncodingScheme The associated encoding scheme
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
int32 getEncodingScheme(const uint16 inCcsid, int32& outEncodingScheme)
|
||||
{
|
||||
DBUG_ENTER("db2i_charsetSupport::getEncodingScheme");
|
||||
|
||||
static bool ptrInited = FALSE;
|
||||
static char ptrSpace[sizeof(ILEpointer) + 15];
|
||||
static ILEpointer* ptrToPtr = (ILEpointer*)roundToQuadWordBdy(ptrSpace);
|
||||
int rc;
|
||||
|
||||
if (!ptrInited)
|
||||
{
|
||||
rc = _RSLOBJ2(ptrToPtr, RSLOBJ_TS_PGM, "QTQGESP", "QSYS");
|
||||
|
||||
if (rc)
|
||||
{
|
||||
getErrTxt(DB2I_ERR_RESOLVE_OBJ,"QTQGESP","QSYS","*PGM",errno);
|
||||
DBUG_RETURN(DB2I_ERR_RESOLVE_OBJ);
|
||||
}
|
||||
ptrInited = TRUE;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(inCcsid != 0);
|
||||
|
||||
int GESPCCSID = inCcsid;
|
||||
int GESPLen = 32;
|
||||
int GESPNbrVal = 0;
|
||||
int32 GESPES;
|
||||
int GESPCSCPL[32];
|
||||
int GESPFB[3];
|
||||
void* ILEArgv[7];
|
||||
ILEArgv[0] = &GESPCCSID;
|
||||
ILEArgv[1] = &GESPLen;
|
||||
ILEArgv[2] = &GESPNbrVal;
|
||||
ILEArgv[3] = &GESPES;
|
||||
ILEArgv[4] = &GESPCSCPL;
|
||||
ILEArgv[5] = &GESPFB;
|
||||
ILEArgv[6] = NULL;
|
||||
|
||||
rc = _PGMCALL(ptrToPtr, (void**)&ILEArgv, 0);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
getErrTxt(DB2I_ERR_PGMCALL,"QTQGESP","QSYS",rc);
|
||||
DBUG_RETURN(DB2I_ERR_PGMCALL);
|
||||
}
|
||||
if (GESPFB[0] != 0 ||
|
||||
GESPFB[1] != 0 ||
|
||||
GESPFB[2] != 0)
|
||||
{
|
||||
getErrTxt(DB2I_ERR_QTQGESP,GESPFB[0],GESPFB[1],GESPFB[2]);
|
||||
DBUG_RETURN(DB2I_ERR_QTQGESP);
|
||||
}
|
||||
outEncodingScheme = GESPES;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Get the best fit equivalent CCSID. (Wrapper for QTQGRDC API)
|
||||
|
||||
@param inCcsid An IBM i CCSID
|
||||
@param inEncodingScheme The encoding scheme
|
||||
@param[out] outCcsid The equivalent CCSID
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
int32 getAssociatedCCSID(const uint16 inCcsid, const int inEncodingScheme, uint16* outCcsid)
|
||||
{
|
||||
DBUG_ENTER("db2i_charsetSupport::getAssociatedCCSID");
|
||||
static bool ptrInited = FALSE;
|
||||
static char ptrSpace[sizeof(ILEpointer) + 15];
|
||||
static ILEpointer* ptrToPtr = (ILEpointer*)roundToQuadWordBdy(ptrSpace);
|
||||
int rc;
|
||||
|
||||
// Override non-standard charsets
|
||||
if ((inCcsid == 923) && (inEncodingScheme == 0x1100))
|
||||
{
|
||||
*outCcsid = 1148;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if ((inCcsid == 1250) && (inEncodingScheme == 0x1100))
|
||||
{
|
||||
*outCcsid = 1153;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (!ptrInited)
|
||||
{
|
||||
rc = _RSLOBJ2(ptrToPtr, RSLOBJ_TS_PGM, "QTQGRDC", "QSYS");
|
||||
|
||||
if (rc)
|
||||
{
|
||||
getErrTxt(DB2I_ERR_RESOLVE_OBJ,"QTQGRDC","QSYS","*PGM",errno);
|
||||
DBUG_RETURN(DB2I_ERR_RESOLVE_OBJ);
|
||||
}
|
||||
ptrInited = TRUE;
|
||||
}
|
||||
|
||||
int GRDCCCSID = inCcsid;
|
||||
int GRDCES = inEncodingScheme;
|
||||
int GRDCSel = 0;
|
||||
int GRDCAssCCSID;
|
||||
int GRDCFB[3];
|
||||
void* ILEArgv[7];
|
||||
ILEArgv[0] = &GRDCCCSID;
|
||||
ILEArgv[1] = &GRDCES;
|
||||
ILEArgv[2] = &GRDCSel;
|
||||
ILEArgv[3] = &GRDCAssCCSID;
|
||||
ILEArgv[4] = &GRDCFB;
|
||||
ILEArgv[5] = NULL;
|
||||
|
||||
rc = _PGMCALL(ptrToPtr, (void**)&ILEArgv, 0);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
getErrTxt(DB2I_ERR_PGMCALL,"QTQGRDC","QSYS",rc);
|
||||
DBUG_RETURN(DB2I_ERR_PGMCALL);
|
||||
}
|
||||
if (GRDCFB[0] != 0 ||
|
||||
GRDCFB[1] != 0 ||
|
||||
GRDCFB[2] != 0)
|
||||
{
|
||||
getErrTxt(DB2I_ERR_QTQGRDC,GRDCFB[0],GRDCFB[1],GRDCFB[2]);
|
||||
DBUG_RETURN(DB2I_ERR_QTQGRDC);
|
||||
}
|
||||
|
||||
*outCcsid = GRDCAssCCSID;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Open an iconv conversion between a MySQL charset and the respective IBM i CCSID
|
||||
|
||||
@param direction The direction of the conversion
|
||||
@param mysqlCSName Name of the MySQL character set
|
||||
@param db2CCSID The IBM i CCSID
|
||||
@param hashKey The key to use for inserting the opened conversion into the cache
|
||||
@param[out] newConversion The iconv descriptor
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
static int32 openNewConversion(enum_conversionDirection direction,
|
||||
const char* mysqlCSName,
|
||||
uint16 db2CCSID,
|
||||
IconvMap::HashKey* hashKey,
|
||||
iconv_t& newConversion)
|
||||
{
|
||||
DBUG_ENTER("db2i_charsetSupport::openNewConversion");
|
||||
|
||||
char mysqlAix41Desc[Qlg_MaxDescSize];
|
||||
char db2Aix41Desc[Qlg_MaxDescSize];
|
||||
char db2CcsidString[6] = "";
|
||||
int32 rc;
|
||||
|
||||
/*
|
||||
First we have to convert the MySQL IANA-like name and the DB2 CCSID into
|
||||
there equivalent iconv descriptions.
|
||||
*/
|
||||
rc = convertTextDesc(Qlg_TypeIANA, Qlg_TypeAix41, mysqlCSName, mysqlAix41Desc);
|
||||
if (unlikely(rc))
|
||||
{
|
||||
if (rc == DB2I_ERR_UNSUPP_CHARSET)
|
||||
getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
CHARSET_INFO *cs= &my_charset_bin;
|
||||
(uint)(cs->cset->long10_to_str)(cs,db2CcsidString,sizeof(db2CcsidString), 10, db2CCSID);
|
||||
rc = convertTextDesc(Qlg_TypeAS400CCSID, Qlg_TypeAix41, db2CcsidString, db2Aix41Desc);
|
||||
if (unlikely(rc))
|
||||
{
|
||||
if (rc == DB2I_ERR_UNSUPP_CHARSET)
|
||||
getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
/* Call iconv to open the conversion. */
|
||||
if (direction == toDB2)
|
||||
{
|
||||
newConversion = iconv_open(db2Aix41Desc, mysqlAix41Desc);
|
||||
}
|
||||
else
|
||||
{
|
||||
newConversion = iconv_open(mysqlAix41Desc, db2Aix41Desc);
|
||||
}
|
||||
|
||||
if (unlikely(newConversion == (iconv_t) -1))
|
||||
{
|
||||
getErrTxt(DB2I_ERR_UNSUPP_CHARSET, mysqlCSName);
|
||||
DBUG_RETURN(DB2I_ERR_UNSUPP_CHARSET);
|
||||
}
|
||||
|
||||
/* Insert the new conversion into the cache. */
|
||||
IconvMap* mapping = (IconvMap*)alloc_root(&iconvMapMemroot, sizeof(IconvMap));
|
||||
if (!mapping)
|
||||
{
|
||||
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(IconvMap));
|
||||
DBUG_RETURN( HA_ERR_OUT_OF_MEM);
|
||||
}
|
||||
memcpy(&(mapping->hashKey), hashKey, sizeof(mapping->hashKey));
|
||||
mapping->iconvDesc = newConversion;
|
||||
pthread_mutex_lock(&iconvMapHashMutex);
|
||||
my_hash_insert(&iconvMapHash, (const uchar*)mapping);
|
||||
pthread_mutex_unlock(&iconvMapHashMutex);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Open an iconv conversion between a MySQL charset and the respective IBM i CCSID
|
||||
|
||||
@param direction The direction of the conversion
|
||||
@param cs The MySQL character set
|
||||
@param db2CCSID The IBM i CCSID
|
||||
@param[out] newConversion The iconv descriptor
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
int32 getConversion(enum_conversionDirection direction, const CHARSET_INFO* cs, uint16 db2CCSID, iconv_t& conversion)
|
||||
{
|
||||
DBUG_ENTER("db2i_charsetSupport::getConversion");
|
||||
|
||||
int32 rc;
|
||||
|
||||
/* Build the hash key */
|
||||
IconvMap::HashKey hashKey;
|
||||
hashKey.direction= direction;
|
||||
hashKey.myCharset= cs;
|
||||
hashKey.db2CCSID= db2CCSID;
|
||||
|
||||
/* Look for the conversion in the cache and add it if it is not there. */
|
||||
IconvMap *mapping;
|
||||
if (!(mapping= (IconvMap *) my_hash_search(&iconvMapHash,
|
||||
(const uchar*)&hashKey,
|
||||
sizeof(hashKey))))
|
||||
{
|
||||
DBUG_PRINT("getConversion", ("Hash miss for direction=%d, cs=%s, ccsid=%d", direction, cs->name, db2CCSID));
|
||||
rc= openNewConversion(direction, cs->csname, db2CCSID, &hashKey, conversion);
|
||||
if (rc)
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
conversion= mapping->iconvDesc;
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/**
|
||||
Fast-path conversion from ASCII to EBCDIC for use in converting
|
||||
identifiers to be sent to the QMY APIs.
|
||||
|
||||
@param input ASCII data
|
||||
@param[out] ouput EBCDIC data
|
||||
@param ilen Size of input buffer and output buffer
|
||||
*/
|
||||
int convToEbcdic(const char* input, char* output, size_t ilen)
|
||||
{
|
||||
static bool inited = FALSE;
|
||||
static iconv_t ic;
|
||||
|
||||
if (ilen == 0)
|
||||
return 0;
|
||||
|
||||
if (!inited)
|
||||
{
|
||||
ic = iconv_open( "IBM-037", "ISO8859-1" );
|
||||
inited = TRUE;
|
||||
}
|
||||
size_t substitutedChars;
|
||||
size_t olen = ilen;
|
||||
if (iconv( ic, (char**)&input, &ilen, &output, &olen, &substitutedChars ) == -1)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Fast-path conversion from EBCDIC to ASCII for use in converting
|
||||
data received from the QMY APIs.
|
||||
|
||||
@param input EBCDIC data
|
||||
@param[out] ouput ASCII data
|
||||
@param ilen Size of input buffer and output buffer
|
||||
*/
|
||||
int convFromEbcdic(const char* input, char* output, size_t ilen)
|
||||
{
|
||||
static bool inited = FALSE;
|
||||
static iconv_t ic;
|
||||
|
||||
if (ilen == 0)
|
||||
return 0;
|
||||
|
||||
if (!inited)
|
||||
{
|
||||
ic = iconv_open("ISO8859-1", "IBM-037");
|
||||
inited = TRUE;
|
||||
}
|
||||
|
||||
size_t substitutedChars;
|
||||
size_t olen = ilen;
|
||||
if (iconv( ic, (char**)&input, &ilen, &output, &olen, &substitutedChars) == -1)
|
||||
return errno;
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DB2I_CHARSETSUPPORT_H
|
||||
#define DB2I_CHARSETSUPPORT_H
|
||||
|
||||
#include "db2i_global.h"
|
||||
#include "mysql_priv.h"
|
||||
#include <mysql/plugin.h>
|
||||
#include "db2i_iconv.h"
|
||||
|
||||
/**
|
||||
@enum enum_conversionDirection
|
||||
|
||||
Conversion directions for getConversion()
|
||||
*/
|
||||
enum enum_conversionDirection
|
||||
{
|
||||
toMySQL,
|
||||
toDB2
|
||||
};
|
||||
|
||||
int initCharsetSupport();
|
||||
void doneCharsetSupport();
|
||||
int32 convertIANAToDb2Ccsid(const char* parmIANADesc, uint16* db2Ccsid);
|
||||
int32 getEncodingScheme(const uint16 inCcsid, int32& outEncodingScheme);
|
||||
int32 getAssociatedCCSID(const uint16 inCcsid, const int inEncodingScheme, uint16* outCcsid);
|
||||
int convToEbcdic(const char* input, char* output, size_t ilen);
|
||||
int convFromEbcdic(const char* input, char* output, size_t ilen);
|
||||
int32 getConversion(enum_conversionDirection direction, const CHARSET_INFO* cs, uint16 db2CCSID, iconv_t& conversion);
|
||||
|
||||
#endif
|
@ -1,355 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "db2i_collationSupport.h"
|
||||
#include "db2i_errors.h"
|
||||
|
||||
|
||||
/*
|
||||
The following arrays define a mapping between MySQL collation names and
|
||||
corresponding IBM i sort sequences. The mapping is a 1-to-1 correlation
|
||||
between corresponding array slots but is incomplete without case-sensitivity
|
||||
markers dynamically added to the mySqlSortSequence names.
|
||||
*/
|
||||
#define MAX_COLLATION 87
|
||||
static const char* mySQLCollation[MAX_COLLATION] =
|
||||
{
|
||||
{"ascii_general"},
|
||||
{"ascii"},
|
||||
{"big5_chinese"},
|
||||
{"big5"},
|
||||
{"cp1250_croatian"},
|
||||
{"cp1250_general"},
|
||||
{"cp1250_polish"},
|
||||
{"cp1250"},
|
||||
{"cp1251_bulgarian"},
|
||||
{"cp1251_general"},
|
||||
{"cp1251"},
|
||||
{"cp1256_general"},
|
||||
{"cp1256"},
|
||||
{"cp850_general"},
|
||||
{"cp850"},
|
||||
{"cp852_general"},
|
||||
{"cp852"},
|
||||
{"cp932_japanese"},
|
||||
{"cp932"},
|
||||
{"euckr_korean"},
|
||||
{"euckr"},
|
||||
{"gb2312_chinese"},
|
||||
{"gb2312"},
|
||||
{"gbk_chinese"},
|
||||
{"gbk"},
|
||||
{"greek_general"},
|
||||
{"greek"},
|
||||
{"hebrew_general"},
|
||||
{"hebrew"},
|
||||
{"latin1_danish"},
|
||||
{"latin1_general"},
|
||||
{"latin1_german1"},
|
||||
{"latin1_spanish"},
|
||||
{"latin1_swedish"},
|
||||
{"latin1"},
|
||||
{"latin2_croatian"},
|
||||
{"latin2_general"},
|
||||
{"latin2_hungarian"},
|
||||
{"latin2"},
|
||||
{"latin5_turkish"},
|
||||
{"latin5"},
|
||||
{"macce_general"},
|
||||
{"macce"},
|
||||
{"sjis_japanese"},
|
||||
{"sjis"},
|
||||
{"tis620_thai"},
|
||||
{"tis620"},
|
||||
{"ucs2_czech"},
|
||||
{"ucs2_danish"},
|
||||
{"ucs2_esperanto"},
|
||||
{"ucs2_estonian"},
|
||||
{"ucs2_general"},
|
||||
{"ucs2_hungarian"},
|
||||
{"ucs2_icelandic"},
|
||||
{"ucs2_latvian"},
|
||||
{"ucs2_lithuanian"},
|
||||
{"ucs2_persian"},
|
||||
{"ucs2_polish"},
|
||||
{"ucs2_romanian"},
|
||||
{"ucs2_slovak"},
|
||||
{"ucs2_slovenian"},
|
||||
{"ucs2_spanish"},
|
||||
{"ucs2_swedish"},
|
||||
{"ucs2_turkish"},
|
||||
{"ucs2_unicode"},
|
||||
{"ucs2"},
|
||||
{"ujis_japanese"},
|
||||
{"ujis"},
|
||||
{"utf8_czech"},
|
||||
{"utf8_danish"},
|
||||
{"utf8_esperanto"},
|
||||
{"utf8_estonian"},
|
||||
{"utf8_general"},
|
||||
{"utf8_hungarian"},
|
||||
{"utf8_icelandic"},
|
||||
{"utf8_latvian"},
|
||||
{"utf8_lithuanian"},
|
||||
{"utf8_persian"},
|
||||
{"utf8_polish"},
|
||||
{"utf8_romanian"},
|
||||
{"utf8_slovak"},
|
||||
{"utf8_slovenian"},
|
||||
{"utf8_spanish"},
|
||||
{"utf8_swedish"},
|
||||
{"utf8_turkish"},
|
||||
{"utf8_unicode"},
|
||||
{"utf8"}
|
||||
};
|
||||
|
||||
|
||||
static const char* mySqlSortSequence[MAX_COLLATION] =
|
||||
{
|
||||
{"QALA101F4"},
|
||||
{"QBLA101F4"},
|
||||
{"QACHT04B0"},
|
||||
{"QBCHT04B0"},
|
||||
{"QALA20481"},
|
||||
{"QCLA20481"},
|
||||
{"QDLA20481"},
|
||||
{"QELA20481"},
|
||||
{"QACYR0401"},
|
||||
{"QBCYR0401"},
|
||||
{"QCCYR0401"},
|
||||
{"QAARA01A4"},
|
||||
{"QBARA01A4"},
|
||||
{"QCLA101F4"},
|
||||
{"QDLA101F4"},
|
||||
{"QALA20366"},
|
||||
{"QBLA20366"},
|
||||
{"QAJPN04B0"},
|
||||
{"QBJPN04B0"},
|
||||
{"QAKOR04B0"},
|
||||
{"QBKOR04B0"},
|
||||
{"QACHS04B0"},
|
||||
{"QBCHS04B0"},
|
||||
{"QCCHS04B0"},
|
||||
{"QDCHS04B0"},
|
||||
{"QAELL036B"},
|
||||
{"QBELL036B"},
|
||||
{"QAHEB01A8"},
|
||||
{"QBHEB01A8"},
|
||||
{"QALA1047C"},
|
||||
{"QBLA1047C"},
|
||||
{"QCLA1047C"},
|
||||
{"QDLA1047C"},
|
||||
{"QELA1047C"},
|
||||
{"QFLA1047C"},
|
||||
{"QCLA20366"},
|
||||
{"QELA20366"},
|
||||
{"QFLA20366"},
|
||||
{"QGLA20366"},
|
||||
{"QATRK0402"},
|
||||
{"QBTRK0402"},
|
||||
{"QHLA20366"},
|
||||
{"QILA20366"},
|
||||
{"QCJPN04B0"},
|
||||
{"QDJPN04B0"},
|
||||
{"QATHA0346"},
|
||||
{"QBTHA0346"},
|
||||
{"ACS_CZ"},
|
||||
{"ADA_DK"},
|
||||
{"AEO"},
|
||||
{"AET"},
|
||||
{"QAUCS04B0"},
|
||||
{"AHU"},
|
||||
{"AIS"},
|
||||
{"ALV"},
|
||||
{"ALT"},
|
||||
{"AFA"},
|
||||
{"APL"},
|
||||
{"ARO"},
|
||||
{"ASK"},
|
||||
{"ASL"},
|
||||
{"AES"},
|
||||
{"ASW"},
|
||||
{"ATR"},
|
||||
{"AEN"},
|
||||
{"*HEX"},
|
||||
{"QEJPN04B0"},
|
||||
{"QFJPN04B0"},
|
||||
{"ACS_CZ"},
|
||||
{"ADA_DK"},
|
||||
{"AEO"},
|
||||
{"AET"},
|
||||
{"QAUCS04B0"},
|
||||
{"AHU"},
|
||||
{"AIS"},
|
||||
{"ALV"},
|
||||
{"ALT"},
|
||||
{"AFA"},
|
||||
{"APL"},
|
||||
{"ARO"},
|
||||
{"ASK"},
|
||||
{"ASL"},
|
||||
{"AES"},
|
||||
{"ASW"},
|
||||
{"ATR"},
|
||||
{"AEN"},
|
||||
{"*HEX"}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Get the IBM i sort sequence that corresponds to the given MySQL collation.
|
||||
|
||||
@param fieldCharSet The collated character set
|
||||
@param[out] rtnSortSequence The corresponding sort sequence
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
static int32 getAssociatedSortSequence(const CHARSET_INFO *fieldCharSet, const char** rtnSortSequence)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::getAssociatedSortSequence");
|
||||
|
||||
if (strcmp(fieldCharSet->csname,"binary") != 0)
|
||||
{
|
||||
int collationSearchLen = strlen(fieldCharSet->name);
|
||||
if (fieldCharSet->state & MY_CS_BINSORT)
|
||||
collationSearchLen -= 4;
|
||||
else
|
||||
collationSearchLen -= 3;
|
||||
|
||||
uint16 loopCnt = 0;
|
||||
for (loopCnt; loopCnt < MAX_COLLATION; ++loopCnt)
|
||||
{
|
||||
if ((strlen(mySQLCollation[loopCnt]) == collationSearchLen) &&
|
||||
(strncmp((char*)mySQLCollation[loopCnt], fieldCharSet->name, collationSearchLen) == 0))
|
||||
break;
|
||||
}
|
||||
if (loopCnt == MAX_COLLATION) // Did not find associated sort sequence
|
||||
{
|
||||
getErrTxt(DB2I_ERR_SRTSEQ);
|
||||
DBUG_RETURN(DB2I_ERR_SRTSEQ);
|
||||
}
|
||||
*rtnSortSequence = mySqlSortSequence[loopCnt];
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Update sort sequence information for a key.
|
||||
|
||||
This function accumulates information about a key as it is called for each
|
||||
field composing the key. The caller should invoke the function for each field
|
||||
and (with the exception of the charset parm) preserve the values for the
|
||||
parms across invocations, until a particular key has been evaluated. Once
|
||||
the last field in the key has been evaluated, the fileSortSequence and
|
||||
fileSortSequenceLibrary parms will contain the correct information for
|
||||
creating the corresponding DB2 key.
|
||||
|
||||
@param charset The character set under consideration
|
||||
@param[in, out] fileSortSequenceType The type of the current key's sort seq
|
||||
@param[in, out] fileSortSequence The IBM i identifier for the DB2 sort sequence
|
||||
that corresponds
|
||||
|
||||
@return 0 if successful. Failure otherwise
|
||||
*/
|
||||
int32 updateAssociatedSortSequence(const CHARSET_INFO* charset,
|
||||
char* fileSortSequenceType,
|
||||
char* fileSortSequence,
|
||||
char* fileSortSequenceLibrary)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::updateAssociatedSortSequence");
|
||||
DBUG_ASSERT(charset);
|
||||
if (strcmp(charset->csname,"binary") != 0)
|
||||
{
|
||||
char newSortSequence[11] = "";
|
||||
char newSortSequenceType = ' ';
|
||||
const char* foundSortSequence;
|
||||
int rc = getAssociatedSortSequence(charset, &foundSortSequence);
|
||||
if (rc) DBUG_RETURN (rc);
|
||||
switch(foundSortSequence[0])
|
||||
{
|
||||
case '*': // Binary
|
||||
strcat(newSortSequence,foundSortSequence);
|
||||
newSortSequenceType = 'B';
|
||||
break;
|
||||
case 'Q': // Non-ICU sort sequence
|
||||
strcat(newSortSequence,foundSortSequence);
|
||||
if ((charset->state & MY_CS_BINSORT) != 0)
|
||||
{
|
||||
strcat(newSortSequence,"U");
|
||||
}
|
||||
else if ((charset->state & MY_CS_CSSORT) != 0)
|
||||
{
|
||||
strcat(newSortSequence,"U");
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(newSortSequence,"S");
|
||||
}
|
||||
newSortSequenceType = 'N';
|
||||
break;
|
||||
default: // ICU sort sequence
|
||||
{
|
||||
if ((charset->state & MY_CS_CSSORT) == 0)
|
||||
{
|
||||
if (osVersion.v >= 6)
|
||||
strcat(newSortSequence,"I34"); // ICU 3.4
|
||||
else
|
||||
strcat(newSortSequence,"I26"); // ICU 2.6.1
|
||||
}
|
||||
strcat(newSortSequence,foundSortSequence);
|
||||
newSortSequenceType = 'I';
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (*fileSortSequenceType == ' ') // If no sort sequence has been set yet
|
||||
{
|
||||
// Set associated sort sequence
|
||||
strcpy(fileSortSequence,newSortSequence);
|
||||
strcpy(fileSortSequenceLibrary,"QSYS");
|
||||
*fileSortSequenceType = newSortSequenceType;
|
||||
}
|
||||
else if (strcmp(fileSortSequence,newSortSequence) != 0)
|
||||
{
|
||||
// Only one sort sequence/collation is supported for each DB2 index.
|
||||
getErrTxt(DB2I_ERR_MIXED_COLLATIONS);
|
||||
DBUG_RETURN(DB2I_ERR_MIXED_COLLATIONS);
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DB2I_COLLATIONSUPPORT_H
|
||||
#define DB2I_COLLATIONSUPPORT_H
|
||||
|
||||
#include "db2i_global.h"
|
||||
#include "mysql_priv.h"
|
||||
|
||||
int32 updateAssociatedSortSequence(const CHARSET_INFO* charset,
|
||||
char* fileSortSequenceType,
|
||||
char* fileSortSequence,
|
||||
char* fileSortSequenceLibrary);
|
||||
|
||||
#endif
|
@ -1,672 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "ha_ibmdb2i.h"
|
||||
#include "db2i_safeString.h"
|
||||
|
||||
// This function is called when building the CREATE TABLE information for
|
||||
// foreign key constraints. It converts a constraint, table, schema, or
|
||||
// field name from EBCDIC to ASCII. If the DB2 name is quoted, it removes
|
||||
// those quotes. It then adds the appropriate quotes for a MySQL identifier.
|
||||
|
||||
static void convNameForCreateInfo(THD *thd, SafeString& info, char* fromName, int len)
|
||||
{
|
||||
int quote;
|
||||
char cquote; // Quote character
|
||||
char convName[MAX_DB2_FILENAME_LENGTH]; // Converted name
|
||||
|
||||
memset(convName, 0, sizeof(convName));
|
||||
convFromEbcdic(fromName, convName, len);
|
||||
quote = get_quote_char_for_identifier(thd, convName, len);
|
||||
cquote = (char) quote;
|
||||
if (quote != EOF)
|
||||
info.strcat(cquote);
|
||||
if (convName[0] == '"') // If DB2 name was quoted, remove quotes
|
||||
{
|
||||
if (strstr(convName, "\"\""))
|
||||
stripExtraQuotes(convName+1, len-1);
|
||||
info.strncat((char*)(convName+1), len-2);
|
||||
}
|
||||
else // DB2 name was not quoted
|
||||
info.strncat(convName, len);
|
||||
if (quote != EOF)
|
||||
info.strcat(cquote);
|
||||
}
|
||||
|
||||
/**
|
||||
Evaluate the parse tree to build foreign key constraint clauses
|
||||
|
||||
@parm lex The parse tree
|
||||
@parm appendHere The DB2 string to receive the constraint clauses
|
||||
@parm path The path to the table under consideration
|
||||
@parm fields Pointer to the table's list of field pointers
|
||||
@parm[in, out] fileSortSequenceType The sort sequence type associated with the table
|
||||
@parm[in, out] fileSortSequence The sort sequence associated with the table
|
||||
@parm[in, out] fileSortSequenceLibrary The sort sequence library associated with the table
|
||||
|
||||
@return 0 if successful; HA_ERR_CANNOT_ADD_FOREIGN otherwise
|
||||
*/
|
||||
int ha_ibmdb2i::buildDB2ConstraintString(LEX* lex,
|
||||
String& appendHere,
|
||||
const char* path,
|
||||
Field** fields,
|
||||
char* fileSortSequenceType,
|
||||
char* fileSortSequence,
|
||||
char* fileSortSequenceLibrary)
|
||||
{
|
||||
List_iterator<Key> keyIter(lex->alter_info.key_list);
|
||||
char colName[MAX_DB2_COLNAME_LENGTH+1];
|
||||
|
||||
Key* curKey;
|
||||
|
||||
while (curKey = keyIter++)
|
||||
{
|
||||
if (curKey->type == Key::FOREIGN_KEY)
|
||||
{
|
||||
appendHere.append(STRING_WITH_LEN(", "));
|
||||
|
||||
Foreign_key* fk = (Foreign_key*)curKey;
|
||||
|
||||
char db2LibName[MAX_DB2_SCHEMANAME_LENGTH+1];
|
||||
if (fk->name.str)
|
||||
{
|
||||
char db2FKName[MAX_DB2_FILENAME_LENGTH+1];
|
||||
appendHere.append(STRING_WITH_LEN("CONSTRAINT "));
|
||||
if (fk->ref_table->db.str)
|
||||
{
|
||||
convertMySQLNameToDB2Name(fk->ref_table->db.str, db2LibName, sizeof(db2LibName));
|
||||
}
|
||||
else
|
||||
{
|
||||
db2i_table::getDB2LibNameFromPath(path, db2LibName);
|
||||
}
|
||||
if (lower_case_table_names == 1)
|
||||
my_casedn_str(files_charset_info, db2LibName);
|
||||
appendHere.append(db2LibName);
|
||||
|
||||
appendHere.append('.');
|
||||
|
||||
convertMySQLNameToDB2Name(fk->name.str, db2FKName, sizeof(db2FKName));
|
||||
appendHere.append(db2FKName);
|
||||
}
|
||||
|
||||
appendHere.append(STRING_WITH_LEN(" FOREIGN KEY ("));
|
||||
|
||||
bool firstTime = true;
|
||||
|
||||
List_iterator<Key_part_spec> column(fk->columns);
|
||||
Key_part_spec* curColumn;
|
||||
|
||||
while (curColumn = column++)
|
||||
{
|
||||
if (!firstTime)
|
||||
{
|
||||
appendHere.append(',');
|
||||
}
|
||||
firstTime = false;
|
||||
|
||||
convertMySQLNameToDB2Name(curColumn->field_name.str, colName, sizeof(colName));
|
||||
appendHere.append(colName);
|
||||
|
||||
// DB2 requires that the sort sequence on the child table match the parent table's
|
||||
// sort sequence. We ensure that happens by updating the sort sequence according
|
||||
// to the constrained fields.
|
||||
Field** field = fields;
|
||||
do
|
||||
{
|
||||
if (strcmp((*field)->field_name, curColumn->field_name.str) == 0)
|
||||
{
|
||||
int rc = updateAssociatedSortSequence((*field)->charset(),
|
||||
fileSortSequenceType,
|
||||
fileSortSequence,
|
||||
fileSortSequenceLibrary);
|
||||
|
||||
if (unlikely(rc)) return rc;
|
||||
}
|
||||
} while (*(++field));
|
||||
}
|
||||
|
||||
firstTime = true;
|
||||
|
||||
appendHere.append(STRING_WITH_LEN(") REFERENCES "));
|
||||
|
||||
if (fk->ref_table->db.str)
|
||||
{
|
||||
convertMySQLNameToDB2Name(fk->ref_table->db.str, db2LibName, sizeof(db2LibName));
|
||||
}
|
||||
else
|
||||
{
|
||||
db2i_table::getDB2LibNameFromPath(path, db2LibName);
|
||||
}
|
||||
if (lower_case_table_names == 1)
|
||||
my_casedn_str(files_charset_info, db2LibName);
|
||||
appendHere.append(db2LibName);
|
||||
appendHere.append('.');
|
||||
|
||||
char db2FileName[MAX_DB2_FILENAME_LENGTH+1];
|
||||
convertMySQLNameToDB2Name(fk->ref_table->table.str, db2FileName, sizeof(db2FileName));
|
||||
if (lower_case_table_names)
|
||||
my_casedn_str(files_charset_info, db2FileName);
|
||||
appendHere.append(db2FileName);
|
||||
|
||||
|
||||
if (!fk->ref_columns.is_empty())
|
||||
{
|
||||
List_iterator<Key_part_spec> ref(fk->ref_columns);
|
||||
Key_part_spec* curRef;
|
||||
appendHere.append(STRING_WITH_LEN(" ("));
|
||||
|
||||
|
||||
while (curRef = ref++)
|
||||
{
|
||||
if (!firstTime)
|
||||
{
|
||||
appendHere.append(',');
|
||||
}
|
||||
firstTime = false;
|
||||
|
||||
convertMySQLNameToDB2Name(curRef->field_name.str, colName, sizeof(colName));
|
||||
appendHere.append(colName);
|
||||
}
|
||||
|
||||
appendHere.append(STRING_WITH_LEN(") "));
|
||||
}
|
||||
|
||||
if (fk->delete_opt != Foreign_key::FK_OPTION_UNDEF)
|
||||
{
|
||||
appendHere.append(STRING_WITH_LEN("ON DELETE "));
|
||||
switch (fk->delete_opt)
|
||||
{
|
||||
case Foreign_key::FK_OPTION_RESTRICT:
|
||||
appendHere.append(STRING_WITH_LEN("RESTRICT ")); break;
|
||||
case Foreign_key::FK_OPTION_CASCADE:
|
||||
appendHere.append(STRING_WITH_LEN("CASCADE ")); break;
|
||||
case Foreign_key::FK_OPTION_SET_NULL:
|
||||
appendHere.append(STRING_WITH_LEN("SET NULL ")); break;
|
||||
case Foreign_key::FK_OPTION_NO_ACTION:
|
||||
appendHere.append(STRING_WITH_LEN("NO ACTION ")); break;
|
||||
case Foreign_key::FK_OPTION_DEFAULT:
|
||||
appendHere.append(STRING_WITH_LEN("SET DEFAULT ")); break;
|
||||
default:
|
||||
return HA_ERR_CANNOT_ADD_FOREIGN; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fk->update_opt != Foreign_key::FK_OPTION_UNDEF)
|
||||
{
|
||||
appendHere.append(STRING_WITH_LEN("ON UPDATE "));
|
||||
switch (fk->update_opt)
|
||||
{
|
||||
case Foreign_key::FK_OPTION_RESTRICT:
|
||||
appendHere.append(STRING_WITH_LEN("RESTRICT ")); break;
|
||||
case Foreign_key::FK_OPTION_NO_ACTION:
|
||||
appendHere.append(STRING_WITH_LEN("NO ACTION ")); break;
|
||||
default:
|
||||
return HA_ERR_CANNOT_ADD_FOREIGN; break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
Get the foreign key information in the form of a character string so
|
||||
that it can be inserted into a CREATE TABLE statement. This is used by
|
||||
the SHOW CREATE TABLE statement. The string will later be freed by the
|
||||
free_foreign_key_create_info() method.
|
||||
************************************************************************/
|
||||
|
||||
char* ha_ibmdb2i::get_foreign_key_create_info(void)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::get_foreign_key_create_info");
|
||||
int rc = 0;
|
||||
char* infoBuffer = NULL; // Pointer to string returned to MySQL
|
||||
uint32 constraintSpaceLength;// Length of space passed to DB2
|
||||
ValidatedPointer<char> constraintSpace; // Space pointer passed to DB2
|
||||
uint32 neededLen; // Length returned from DB2
|
||||
uint32 cstCnt; // Number of foreign key constraints from DB2
|
||||
uint32 fld; //
|
||||
constraint_hdr* cstHdr; // Pointer to constraint header structure
|
||||
FK_constraint* FKCstDef; // Pointer to constraint definition structure
|
||||
cst_name* fieldName; // Pointer to field name structure
|
||||
char* tempPtr; // Temp pointer for traversing constraint space
|
||||
char convName[128];
|
||||
|
||||
/* Allocate space to retrieve the DB2 constraint information. */
|
||||
|
||||
if (!(share = get_share(table_share->path.str, table)))
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
constraintSpaceLength = 5000; // Try allocating 5000 bytes and see if enough.
|
||||
|
||||
initBridge();
|
||||
|
||||
constraintSpace.alloc(constraintSpaceLength);
|
||||
rc = bridge()->expectErrors(QMY_ERR_NEED_MORE_SPACE)
|
||||
->constraints(db2Table->dataFile()->getMasterDefnHandle(),
|
||||
constraintSpace,
|
||||
constraintSpaceLength,
|
||||
&neededLen,
|
||||
&cstCnt);
|
||||
|
||||
if (unlikely(rc == QMY_ERR_NEED_MORE_SPACE))
|
||||
{
|
||||
constraintSpaceLength = neededLen; // Get length of space that's needed
|
||||
constraintSpace.realloc(constraintSpaceLength);
|
||||
rc = bridge()->expectErrors(QMY_ERR_NEED_MORE_SPACE)
|
||||
->constraints(db2Table->dataFile()->getMasterDefnHandle(),
|
||||
constraintSpace,
|
||||
constraintSpaceLength,
|
||||
&neededLen,
|
||||
&cstCnt);
|
||||
}
|
||||
|
||||
/* If constraint information was returned by DB2, build a text string */
|
||||
/* to return to MySQL. */
|
||||
|
||||
if ((rc == 0) && (cstCnt > 0))
|
||||
{
|
||||
THD* thd = ha_thd();
|
||||
infoBuffer = (char*) my_malloc(MAX_FOREIGN_LEN + 1, MYF(MY_WME));
|
||||
if (infoBuffer == NULL)
|
||||
{
|
||||
free_share(share);
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
SafeString info(infoBuffer, MAX_FOREIGN_LEN + 1);
|
||||
|
||||
/* Loop through the DB2 constraints and build a text string for each foreign */
|
||||
/* key constraint that is found. */
|
||||
|
||||
tempPtr = constraintSpace;
|
||||
cstHdr = (constraint_hdr_t*)(void*)constraintSpace; // Address first constraint definition
|
||||
for (int i = 0; i < cstCnt && !info.overflowed(); ++i)
|
||||
{
|
||||
if (cstHdr->CstType[0] == QMY_CST_FK) // If this is a foreign key constraint
|
||||
{
|
||||
tempPtr = (char*)(tempPtr + cstHdr->CstDefOff);
|
||||
FKCstDef = (FK_constraint_t*)tempPtr;
|
||||
|
||||
/* Process the constraint name. */
|
||||
|
||||
info.strncat(STRING_WITH_LEN(",\n CONSTRAINT "));
|
||||
convNameForCreateInfo(thd, info,
|
||||
FKCstDef->CstName.Name, FKCstDef->CstName.Len);
|
||||
|
||||
/* Process the names of the foreign keys. */
|
||||
|
||||
info.strncat(STRING_WITH_LEN(" FOREIGN KEY ("));
|
||||
tempPtr = (char*)(tempPtr + FKCstDef->KeyColOff);
|
||||
fieldName= (cst_name_t*)tempPtr;
|
||||
for (fld = 0; fld < FKCstDef->KeyCnt; ++fld)
|
||||
{
|
||||
convNameForCreateInfo(thd, info, fieldName->Name, fieldName->Len);
|
||||
if ((fld + 1) < FKCstDef->KeyCnt)
|
||||
{
|
||||
info.strncat(STRING_WITH_LEN(", "));
|
||||
fieldName = fieldName + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the schema-name and name of the referenced table. */
|
||||
|
||||
info.strncat(STRING_WITH_LEN(") REFERENCES "));
|
||||
convNameForCreateInfo(thd, info,
|
||||
FKCstDef->RefSchema.Name, FKCstDef->RefSchema.Len);
|
||||
info.strcat('.');
|
||||
convNameForCreateInfo(thd, info,
|
||||
FKCstDef->RefTable.Name, FKCstDef->RefTable.Len);
|
||||
info.strncat(STRING_WITH_LEN(" ("));
|
||||
|
||||
/* Process the names of the referenced keys. */
|
||||
|
||||
tempPtr = (char*)FKCstDef;
|
||||
tempPtr = (char*)(tempPtr + FKCstDef->RefColOff);
|
||||
fieldName= (cst_name_t*)tempPtr;
|
||||
for (fld = 0; fld < FKCstDef->RefCnt; ++fld)
|
||||
{
|
||||
convNameForCreateInfo(thd, info, fieldName->Name, fieldName->Len);
|
||||
if ((fld + 1) < FKCstDef->RefCnt)
|
||||
{
|
||||
info.strncat(STRING_WITH_LEN(", "));
|
||||
fieldName = fieldName + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process the ON UPDATE and ON DELETE rules. */
|
||||
|
||||
info.strncat(STRING_WITH_LEN(") ON UPDATE "));
|
||||
switch(FKCstDef->UpdMethod)
|
||||
{
|
||||
case QMY_NOACTION: info.strncat(STRING_WITH_LEN("NO ACTION")); break;
|
||||
case QMY_RESTRICT: info.strncat(STRING_WITH_LEN("RESTRICT")); break;
|
||||
default: break;
|
||||
}
|
||||
info.strncat(STRING_WITH_LEN(" ON DELETE "));
|
||||
switch(FKCstDef->DltMethod)
|
||||
{
|
||||
case QMY_CASCADE: info.strncat(STRING_WITH_LEN("CASCADE")); break;
|
||||
case QMY_SETDFT: info.strncat(STRING_WITH_LEN("SET DEFAULT")); break;
|
||||
case QMY_SETNULL: info.strncat(STRING_WITH_LEN("SET NULL")); break;
|
||||
case QMY_NOACTION: info.strncat(STRING_WITH_LEN("NO ACTION")); break;
|
||||
case QMY_RESTRICT: info.strncat(STRING_WITH_LEN("RESTRICT")); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Address the next constraint, if any. */
|
||||
|
||||
if ((i+1) < cstCnt)
|
||||
{
|
||||
tempPtr = (char*)cstHdr + cstHdr->CstLen;
|
||||
cstHdr = (constraint_hdr_t*)(tempPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup and return */
|
||||
free_share(share);
|
||||
|
||||
DBUG_RETURN(infoBuffer);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Free the foreign key create info (for a table) that was acquired by the
|
||||
get_foreign_key_create_info() method.
|
||||
***********************************************************************/
|
||||
|
||||
void ha_ibmdb2i::free_foreign_key_create_info(char* info)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::free_foreign_key_create_info");
|
||||
|
||||
if (info)
|
||||
{
|
||||
my_free(info);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
This method returns to MySQL a list, with one entry in the list describing
|
||||
each foreign key constraint.
|
||||
***********************************************************************/
|
||||
|
||||
int ha_ibmdb2i::get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::get_foreign_key_list");
|
||||
int rc = 0;
|
||||
uint32 constraintSpaceLength; // Length of space passed to DB2
|
||||
ValidatedPointer<char> constraintSpace; // Space pointer passed to DB2
|
||||
uint16 rtnCode; // Return code from DB2
|
||||
uint32 neededLen; // Bytes needed to contain DB2 constraint info
|
||||
uint32 cstCnt; // Number of constraints returned by DB2
|
||||
uint32 fld;
|
||||
constraint_hdr* cstHdr; // Pointer to a cst header structure
|
||||
FK_constraint* FKCstDef; // Pointer to definition of foreign key constraint
|
||||
cst_name* fieldName; // Pointer to field name structure
|
||||
const char *method;
|
||||
ulong methodLen;
|
||||
char* tempPtr; // Temp pointer for traversing constraint space
|
||||
char convName[128];
|
||||
|
||||
if (!(share = get_share(table_share->path.str, table)))
|
||||
DBUG_RETURN(0);
|
||||
|
||||
// Allocate space to retrieve the DB2 constraint information.
|
||||
constraintSpaceLength = 5000; // Try allocating 5000 bytes and see if enough.
|
||||
|
||||
constraintSpace.alloc(constraintSpaceLength);
|
||||
rc = bridge()->expectErrors(QMY_ERR_NEED_MORE_SPACE)
|
||||
->constraints(db2Table->dataFile()->getMasterDefnHandle(),
|
||||
constraintSpace,
|
||||
constraintSpaceLength,
|
||||
&neededLen,
|
||||
&cstCnt);
|
||||
|
||||
if (unlikely(rc == QMY_ERR_NEED_MORE_SPACE))
|
||||
{
|
||||
constraintSpaceLength = neededLen; // Get length of space that's needed
|
||||
constraintSpace.realloc(constraintSpaceLength);
|
||||
rc = bridge()->expectErrors(QMY_ERR_NEED_MORE_SPACE)
|
||||
->constraints(db2Table->dataFile()->getMasterDefnHandle(),
|
||||
constraintSpace,
|
||||
constraintSpaceLength,
|
||||
&neededLen,
|
||||
&cstCnt);
|
||||
}
|
||||
|
||||
/* If constraint information was returned by DB2, build a text string */
|
||||
/* to return to MySQL. */
|
||||
if ((rc == 0) && (cstCnt > 0))
|
||||
{
|
||||
tempPtr = constraintSpace;
|
||||
cstHdr = (constraint_hdr_t*)(void*)constraintSpace; // Address first constraint definition
|
||||
for (int i = 0; i < cstCnt; ++i)
|
||||
{
|
||||
if (cstHdr->CstType[0] == QMY_CST_FK) // If this is a foreign key constraint
|
||||
{
|
||||
FOREIGN_KEY_INFO f_key_info;
|
||||
LEX_STRING *name= 0;
|
||||
tempPtr = (char*)(tempPtr + cstHdr->CstDefOff);
|
||||
FKCstDef = (FK_constraint_t*)tempPtr;
|
||||
|
||||
/* Process the constraint name. */
|
||||
|
||||
convFromEbcdic(FKCstDef->CstName.Name, convName,FKCstDef->CstName.Len);
|
||||
if (convName[0] == '"') // If quoted, exclude quotes.
|
||||
f_key_info.foreign_id = thd_make_lex_string(thd, 0,
|
||||
convName + 1, (uint) (FKCstDef->CstName.Len - 2), 1);
|
||||
else // Not quoted
|
||||
f_key_info.foreign_id = thd_make_lex_string(thd, 0,
|
||||
convName, (uint) FKCstDef->CstName.Len, 1);
|
||||
|
||||
/* Process the names of the foreign keys. */
|
||||
|
||||
|
||||
tempPtr = (char*)(tempPtr + FKCstDef->KeyColOff);
|
||||
fieldName = (cst_name_t*)tempPtr;
|
||||
for (fld = 0; fld < FKCstDef->KeyCnt; ++fld)
|
||||
{
|
||||
convFromEbcdic(fieldName->Name, convName, fieldName->Len);
|
||||
if (convName[0] == '"') // If quoted, exclude quotes.
|
||||
name = thd_make_lex_string(thd, name,
|
||||
convName + 1, (uint) (fieldName->Len - 2), 1);
|
||||
else
|
||||
name = thd_make_lex_string(thd, name, convName, (uint) fieldName->Len, 1);
|
||||
f_key_info.foreign_fields.push_back(name);
|
||||
if ((fld + 1) < FKCstDef->KeyCnt)
|
||||
fieldName = fieldName + 1;
|
||||
}
|
||||
|
||||
/* Process the schema and name of the referenced table. */
|
||||
|
||||
convFromEbcdic(FKCstDef->RefSchema.Name, convName, FKCstDef->RefSchema.Len);
|
||||
if (convName[0] == '"') // If quoted, exclude quotes.
|
||||
f_key_info.referenced_db = thd_make_lex_string(thd, 0,
|
||||
convName + 1, (uint) (FKCstDef->RefSchema.Len -2), 1);
|
||||
else
|
||||
f_key_info.referenced_db = thd_make_lex_string(thd, 0,
|
||||
convName, (uint) FKCstDef->RefSchema.Len, 1);
|
||||
convFromEbcdic(FKCstDef->RefTable.Name, convName, FKCstDef->RefTable.Len);
|
||||
if (convName[0] == '"') // If quoted, exclude quotes.
|
||||
f_key_info.referenced_table = thd_make_lex_string(thd, 0,
|
||||
convName +1, (uint) (FKCstDef->RefTable.Len -2), 1);
|
||||
else
|
||||
f_key_info.referenced_table = thd_make_lex_string(thd, 0,
|
||||
convName, (uint) FKCstDef->RefTable.Len, 1);
|
||||
|
||||
/* Process the names of the referenced keys. */
|
||||
|
||||
tempPtr = (char*)FKCstDef;
|
||||
tempPtr = (char*)(tempPtr + FKCstDef->RefColOff);
|
||||
fieldName= (cst_name_t*)tempPtr;
|
||||
for (fld = 0; fld < FKCstDef->RefCnt; ++fld)
|
||||
{
|
||||
convFromEbcdic(fieldName->Name, convName, fieldName->Len);
|
||||
if (convName[0] == '"') // If quoted, exclude quotes.
|
||||
name = thd_make_lex_string(thd, name,
|
||||
convName + 1, (uint) (fieldName->Len -2), 1);
|
||||
else
|
||||
name = thd_make_lex_string(thd, name, convName, (uint) fieldName->Len, 1);
|
||||
f_key_info.referenced_fields.push_back(name);
|
||||
if ((fld + 1) < FKCstDef->RefCnt)
|
||||
fieldName = fieldName + 1;
|
||||
}
|
||||
|
||||
/* Process the ON UPDATE and ON DELETE rules. */
|
||||
|
||||
switch(FKCstDef->UpdMethod)
|
||||
{
|
||||
case QMY_NOACTION:
|
||||
{
|
||||
method = "NO ACTION";
|
||||
methodLen=9;
|
||||
}
|
||||
break;
|
||||
case QMY_RESTRICT:
|
||||
{
|
||||
method = "RESTRICT";
|
||||
methodLen = 8;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
f_key_info.update_method = thd_make_lex_string(
|
||||
thd, f_key_info.update_method, method, methodLen, 1);
|
||||
switch(FKCstDef->DltMethod)
|
||||
{
|
||||
case QMY_CASCADE:
|
||||
{
|
||||
method = "CASCADE";
|
||||
methodLen = 7;
|
||||
}
|
||||
break;
|
||||
case QMY_SETDFT:
|
||||
{
|
||||
method = "SET DEFAULT";
|
||||
methodLen = 11;
|
||||
}
|
||||
break;
|
||||
case QMY_SETNULL:
|
||||
{
|
||||
method = "SET NULL";
|
||||
methodLen = 8;
|
||||
}
|
||||
break;
|
||||
case QMY_NOACTION:
|
||||
{
|
||||
method = "NO ACTION";
|
||||
methodLen = 9;
|
||||
}
|
||||
break;
|
||||
case QMY_RESTRICT:
|
||||
{
|
||||
method = "RESTRICT";
|
||||
methodLen = 8;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
f_key_info.delete_method = thd_make_lex_string(
|
||||
thd, f_key_info.delete_method, method, methodLen, 1);
|
||||
f_key_info.referenced_key_name= thd_make_lex_string(thd, 0, (char *)"", 1, 1);
|
||||
FOREIGN_KEY_INFO *pf_key_info = (FOREIGN_KEY_INFO *)
|
||||
thd_memdup(thd, &f_key_info, sizeof(FOREIGN_KEY_INFO));
|
||||
f_key_list->push_back(pf_key_info);
|
||||
}
|
||||
|
||||
/* Address the next constraint, if any. */
|
||||
|
||||
if ((i+1) < cstCnt)
|
||||
{
|
||||
tempPtr = (char*)cstHdr + cstHdr->CstLen;
|
||||
cstHdr = (constraint_hdr_t*)(tempPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup and return. */
|
||||
|
||||
free_share(share);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Checks if the table is referenced by a foreign key.
|
||||
Returns: 0 if not referenced (or error occurs),
|
||||
> 0 if is referenced
|
||||
***********************************************************************/
|
||||
|
||||
uint ha_ibmdb2i::referenced_by_foreign_key(void)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::referenced_by_foreign_key");
|
||||
|
||||
int rc = 0;
|
||||
FILE_HANDLE queryFile = 0;
|
||||
uint32 resultRowLen;
|
||||
uint32 count = 0;
|
||||
|
||||
const char* libName = db2Table->getDB2LibName(db2i_table::ASCII_SQL);
|
||||
const char* fileName = db2Table->getDB2TableName(db2i_table::ASCII_SQL);
|
||||
|
||||
String query(128);
|
||||
query.append(STRING_WITH_LEN(" SELECT COUNT(*) FROM SYSIBM.SQLFOREIGNKEYS WHERE PKTABLE_SCHEM = '"));
|
||||
query.append(libName+1, strlen(libName)-2); // parent library name
|
||||
query.append(STRING_WITH_LEN("' AND PKTABLE_NAME = '"));
|
||||
query.append(fileName+1, strlen(fileName)-2); // parent file name
|
||||
query.append(STRING_WITH_LEN("'"));
|
||||
|
||||
SqlStatementStream sqlStream(query);
|
||||
|
||||
rc = bridge()->prepOpen(sqlStream.getPtrToData(),
|
||||
&queryFile,
|
||||
&resultRowLen);
|
||||
if (rc == 0)
|
||||
{
|
||||
IOReadBuffer rowBuffer(1, resultRowLen);
|
||||
rc = bridge()->read(queryFile, rowBuffer.ptr(), QMY_READ_ONLY, QMY_NONE, QMY_FIRST);
|
||||
if (!rc) count = *((uint32*)rowBuffer.getRowN(0));
|
||||
bridge()->deallocateFile(queryFile);
|
||||
}
|
||||
DBUG_RETURN(count);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,297 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "db2i_errors.h"
|
||||
#include "db2i_ileBridge.h"
|
||||
#include "db2i_charsetSupport.h"
|
||||
#include "mysql_priv.h"
|
||||
#include "stdarg.h"
|
||||
|
||||
#define MAX_MSGSTRING 109
|
||||
|
||||
/*
|
||||
The following strings are associated with errors that can be produced
|
||||
within the storage engine proper.
|
||||
*/
|
||||
static const char* engineErrors[MAX_MSGSTRING] =
|
||||
{
|
||||
{""},
|
||||
{"Error opening codeset conversion from %.64s to %.64s (errno = %d)"},
|
||||
{"Invalid %-.10s name '%-.128s'"},
|
||||
{"Unsupported move from '%-.128s' to '%-.128s' on RENAME TABLE statement"},
|
||||
{"The %-.64s character set is not supported."},
|
||||
{"Auto_increment is not allowed for a partitioned table"},
|
||||
{"Character set conversion error due to unknown encoding scheme %d"},
|
||||
{""},
|
||||
{"Table '%-.128s' was not found by the storage engine"},
|
||||
{"Could not resolve to %-.128s in library %-.10s type %-.10s (errno = %d)"},
|
||||
{"Error on _PGMCALL for program %-.10s in library %-.10s (error = %d)"},
|
||||
{"Error on _ILECALL for API '%.128s' (error = %d)"},
|
||||
{"Error in iconv() function during character set conversion (errno = %d)"},
|
||||
{"Error from Get Encoding Scheme (QTQGESP) API: %d, %d, %d"},
|
||||
{"Error from Get Related Default CCSID (QTQGRDC) API: %d, %d, %d"},
|
||||
{"Data out of range for column '%.192s'"},
|
||||
{"Schema name '%.128s' exceeds maximum length of %d characters"},
|
||||
{"Multiple collations not supported in a single index or constraint"},
|
||||
{"Sort sequence was not found"},
|
||||
{"One or more characters in column %.128s were substituted during conversion"},
|
||||
{"A decimal column exceeded the maximum precision. Data may be truncated."},
|
||||
{"Some data returned by DB2 for table %s could not be converted for MySQL"},
|
||||
{""},
|
||||
{"Column %.128s contains characters that cannot be converted"},
|
||||
{"An invalid name was specified for ibmdb2i_rdb_name."},
|
||||
{"A duplicate key was encountered for index '%.128s'"},
|
||||
{"A table with the same name exists but has incompatible column definitions."},
|
||||
{"The created table was discovered as an existing DB2 object."},
|
||||
{"Some attribute(s) defined for column '%.128s' may not be honored by accesses from DB2."},
|
||||
};
|
||||
|
||||
/*
|
||||
The following strings are associated with errors that can be returned
|
||||
by the operating system via the QMY_* APIs. Most are very uncommon and
|
||||
indicate a bug somewhere.
|
||||
*/
|
||||
static const char* systemErrors[MAX_MSGSTRING] =
|
||||
{
|
||||
{"Thread ID is too long"},
|
||||
{"Error creating a SPACE memory object"},
|
||||
{"Error creating a FILE memory object"},
|
||||
{"Error creating a SPACE synchronization token"},
|
||||
{"Error creating a FILE synchronization token"},
|
||||
{"See message %-.7s in joblog for job %-.6s/%-.10s/%-.10s."},
|
||||
{"Error unlocking a synchronization token when closing a connection"},
|
||||
{"Invalid action specified for an 'object lock' request"},
|
||||
{"Invalid action specified for a savepoint request"},
|
||||
{"Partial keys are not supported with an ICU sort sequence"},
|
||||
{"Error retrieving an ICU sort key"},
|
||||
{"Error converting single-byte sort sequence to UCS-2"},
|
||||
{"An unsupported collation was specified"},
|
||||
{"Validation failed for referenced table of foreign key constraint"},
|
||||
{"Error extracting table for constraint information"},
|
||||
{"Error extracting referenced table for constraint information"},
|
||||
{"Invalid action specified for a 'commitment control' request"},
|
||||
{"Invalid commitment control isolation level specified on 'open' request"},
|
||||
{"Invalid file handle"},
|
||||
{" "},
|
||||
{"Invalid option specified for returning data on 'read' request"},
|
||||
{"Invalid orientation specified for 'read' request"},
|
||||
{"Invalid option type specified for 'read' request"},
|
||||
{"Invalid isolation level for starting commitment control"},
|
||||
{"Error unlocking a synchronization token in module QMYALC"},
|
||||
{"Length of space for returned format is not long enough"},
|
||||
{"SQL XA transactions are currently unsupported by this interface"},
|
||||
{"The associated QSQSRVR job was killed or ended unexpectedly."},
|
||||
{"Error unlocking a synchronization token in module QMYSEI"},
|
||||
{"Error unlocking a synchronization token in module QMYSPO"},
|
||||
{"Error converting input CCSID from short form to long form"},
|
||||
{" "},
|
||||
{"Error getting associated CCSID for CCSID conversion"},
|
||||
{"Error converting a string from one CCSID to another"},
|
||||
{"Error unlocking a synchronization token"},
|
||||
{"Error destroying a synchronization token"},
|
||||
{"Error locking a synchronization token"},
|
||||
{"Error recreating a synchronization token"},
|
||||
{"A space handle was not specified for a constraint request"},
|
||||
{"An SQL cursor was specified for a delete request"},
|
||||
{" "},
|
||||
{"Error on delete request because current UFCB for connection is not open"},
|
||||
{"An SQL cursor was specified for an object initialization request"},
|
||||
{"An SQL cursor was specified for an object override request"},
|
||||
{"A space handle was not specified for an object override request"},
|
||||
{"An SQL cursor was specified for an information request"},
|
||||
{"An SQL cursor was specified for an object lock request"},
|
||||
{"An SQL cursor was specified for an optimize request"},
|
||||
{"A data handle was not specified for a read request"},
|
||||
{"A row number handle was not specified for a read request"},
|
||||
{"A key handle was not specified for a read request"},
|
||||
{"An SQL cursor was specified for an row estimation request"},
|
||||
{"A space handle was not specified for a row estimation request"},
|
||||
{"An SQL cursor was specified for a release record request"},
|
||||
{"A statement handle was not specified for an 'execute immediate' request"},
|
||||
{"A statement handle was not specified for a 'prepare open' request"},
|
||||
{"An SQL cursor was specified for an update request"},
|
||||
{"The UFCB was not open for read"},
|
||||
{"Error on update request because current UFCB for connection is not open"},
|
||||
{"A data handle was not specified for an update request"},
|
||||
{"An SQL cursor was specified for a write request"},
|
||||
{"A data handle was not specified for a write request"},
|
||||
{"An unknown function was specified on a process request"},
|
||||
{"A share definition was not specified for an 'allocate share' request"},
|
||||
{"A share handle was not specified for an 'allocate share' request"},
|
||||
{"A use count handle was not specified for an 'allocate share' request"},
|
||||
{"A 'records per key' handle was not specified for an information request"},
|
||||
{"Error resolving LOB addresss"},
|
||||
{"Length of a LOB space is too small"},
|
||||
{"An unknown function was specified for a server request"},
|
||||
{"Object authorization failed. See message %-.7s in joblog for job %-.6s/%-.10s/%-.10s. for more information."},
|
||||
{" "},
|
||||
{"Error locking mutex on server"},
|
||||
{"Error unlocking mutex on server"},
|
||||
{"Error checking for RDB name in RDB Directory"},
|
||||
{"Error creating mutex on server"},
|
||||
{"A table with that name already exists"},
|
||||
{" "},
|
||||
{"Error unlocking mutex"},
|
||||
{"Error connecting to server job"},
|
||||
{"Error connecting to server job"},
|
||||
{" "},
|
||||
{"Function check occurred while registering parameter spaces. See joblog."},
|
||||
{" "},
|
||||
{" "},
|
||||
{"End of block"},
|
||||
{"The file has changed and might not be compatible with the MySQL table definition"},
|
||||
{"Error giving pipe to server job"},
|
||||
{"There are open object locks when attempting to deallocate"},
|
||||
{"There is no open lock"},
|
||||
{" "},
|
||||
{" "},
|
||||
{"The maximum value for the auto_increment data type was exceeded"},
|
||||
{"Error occurred closing the pipe "},
|
||||
{"Error occurred taking a descriptor for the pipe"},
|
||||
{"Error writing to pipe "},
|
||||
{"Server was interrupted "},
|
||||
{"No pipe descriptor exists for reuse "},
|
||||
{"Error occurred during an SQL prepare statement "},
|
||||
{"Error occurred during an SQL open "},
|
||||
{" "},
|
||||
{" "},
|
||||
{" "},
|
||||
{" "},
|
||||
{" "},
|
||||
{" "},
|
||||
{"An unspecified error was returned from the system."},
|
||||
{" "}
|
||||
};
|
||||
|
||||
/**
|
||||
This function builds the text string for an error code, and substitutes
|
||||
a variable number of replacement variables into the string.
|
||||
*/
|
||||
void getErrTxt(int errCode, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args,errCode);
|
||||
char* buffer = db2i_ileBridge::getBridgeForThread()->getErrorStorage();
|
||||
const char* msg;
|
||||
|
||||
if (errCode >= QMY_ERR_MIN && errCode <= QMY_ERR_SQ_OPEN)
|
||||
msg = systemErrors[errCode - QMY_ERR_MIN];
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(errCode >= DB2I_FIRST_ERR && errCode <= DB2I_LAST_ERR);
|
||||
msg = engineErrors[errCode - DB2I_FIRST_ERR];
|
||||
}
|
||||
|
||||
(void) my_vsnprintf (buffer, MYSQL_ERRMSG_SIZE, msg, args);
|
||||
va_end(args);
|
||||
fprintf(stderr,"ibmdb2i error %d: %s\n",errCode,buffer);
|
||||
DBUG_PRINT("error", ("ibmdb2i error %d: %s",errCode,buffer));
|
||||
}
|
||||
|
||||
static inline void trimSpace(char* str)
|
||||
{
|
||||
char* end = strchr(str, ' ');
|
||||
if (end) *end = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Generate the error text specific to an API error returned by a QMY_* API.
|
||||
|
||||
@parm errCode The error value
|
||||
@parm errInfo The structure containing the message and job identifiers.
|
||||
*/
|
||||
void reportSystemAPIError(int errCode, const Qmy_Error_output *errInfo)
|
||||
{
|
||||
if (errCode >= QMY_ERR_MIN && errCode <= QMY_ERR_SQ_OPEN)
|
||||
{
|
||||
switch(errCode)
|
||||
{
|
||||
case QMY_ERR_MSGID:
|
||||
case QMY_ERR_NOT_AUTH:
|
||||
{
|
||||
DBUG_ASSERT(errInfo);
|
||||
char jMsg[8]; // Error message ID
|
||||
char jName[11]; // Job name
|
||||
char jUser[11]; // Job user
|
||||
char jNbr[7]; // Job number
|
||||
memset(jMsg, 0, sizeof(jMsg));
|
||||
memset(jName, 0, sizeof(jMsg));
|
||||
memset(jUser, 0, sizeof(jMsg));
|
||||
memset(jMsg, 0, sizeof(jMsg));
|
||||
|
||||
convFromEbcdic(errInfo->MsgId,jMsg,sizeof(jMsg)-1);
|
||||
convFromEbcdic(errInfo->JobName,jName,sizeof(jName)-1);
|
||||
trimSpace(jName);
|
||||
convFromEbcdic(errInfo->JobUser,jUser,sizeof(jUser)-1);
|
||||
trimSpace(jUser);
|
||||
convFromEbcdic(errInfo->JobNbr,jNbr,sizeof(jNbr)-1);
|
||||
getErrTxt(errCode,jMsg,jNbr,jUser,jName);
|
||||
}
|
||||
break;
|
||||
case QMY_ERR_RTNFMT:
|
||||
{
|
||||
getErrTxt(QMY_ERR_LVLID_MISMATCH);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
getErrTxt(errCode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Generate a warning for the specified error.
|
||||
*/
|
||||
void warning(THD *thd, int errCode, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args,errCode);
|
||||
char buffer[MYSQL_ERRMSG_SIZE];
|
||||
const char* msg;
|
||||
|
||||
DBUG_ASSERT(errCode >= DB2I_FIRST_ERR && errCode <= DB2I_LAST_ERR);
|
||||
msg = engineErrors[errCode - DB2I_FIRST_ERR];
|
||||
|
||||
(void) my_vsnprintf (buffer, MYSQL_ERRMSG_SIZE, msg, args);
|
||||
va_end(args);
|
||||
DBUG_PRINT("warning", ("ibmdb2i warning %d: %s",errCode,buffer));
|
||||
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, errCode, buffer);
|
||||
}
|
||||
|
||||
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DB2I_ERRORS_H
|
||||
#define DB2I_ERRORS_H
|
||||
|
||||
#include "qmyse.h"
|
||||
class THD;
|
||||
|
||||
/**
|
||||
@enum DB2I_errors
|
||||
|
||||
@brief These are the errors that can be returned by the storage engine proper
|
||||
and that are specific to the engine. Refer to db2i_errors.cc for text
|
||||
descriptions of the errors.
|
||||
*/
|
||||
|
||||
enum DB2I_errors
|
||||
{
|
||||
DB2I_FIRST_ERR = 2500,
|
||||
DB2I_ERR_ICONV_OPEN,
|
||||
DB2I_ERR_INVALID_NAME,
|
||||
DB2I_ERR_RENAME_MOVE,
|
||||
DB2I_ERR_UNSUPP_CHARSET,
|
||||
DB2I_ERR_PART_AUTOINC,
|
||||
DB2I_ERR_UNKNOWN_ENCODING,
|
||||
DB2I_ERR_RESERVED,
|
||||
DB2I_ERR_TABLE_NOT_FOUND,
|
||||
DB2I_ERR_RESOLVE_OBJ,
|
||||
DB2I_ERR_PGMCALL,
|
||||
DB2I_ERR_ILECALL,
|
||||
DB2I_ERR_ICONV,
|
||||
DB2I_ERR_QTQGESP,
|
||||
DB2I_ERR_QTQGRDC,
|
||||
DB2I_ERR_INVALID_COL_VALUE,
|
||||
DB2I_ERR_TOO_LONG_SCHEMA,
|
||||
DB2I_ERR_MIXED_COLLATIONS,
|
||||
DB2I_ERR_SRTSEQ,
|
||||
DB2I_ERR_SUB_CHARS,
|
||||
DB2I_ERR_PRECISION,
|
||||
DB2I_ERR_INVALID_DATA,
|
||||
DB2I_ERR_RESERVED2,
|
||||
DB2I_ERR_ILL_CHAR,
|
||||
DB2I_ERR_BAD_RDB_NAME,
|
||||
DB2I_ERR_UNKNOWN_IDX,
|
||||
DB2I_ERR_DISCOVERY_MISMATCH,
|
||||
DB2I_ERR_WARN_CREATE_DISCOVER,
|
||||
DB2I_ERR_WARN_COL_ATTRS,
|
||||
DB2I_LAST_ERR = DB2I_ERR_WARN_COL_ATTRS
|
||||
};
|
||||
|
||||
void getErrTxt(int errcode, ...);
|
||||
void reportSystemAPIError(int errCode, const Qmy_Error_output *errInfo);
|
||||
void warning(THD *thd, int errCode, ...);
|
||||
|
||||
const char* DB2I_SQL0350 = "\xE2\xD8\xD3\xF0\xF3\xF5\xF0"; // SQL0350 in EBCDIC
|
||||
const char* DB2I_CPF503A = "\xC3\xD7\xC6\xF5\xF0\xF3\xC1"; // CPF503A in EBCDIC
|
||||
const char* DB2I_SQL0538 = "\xE2\xD8\xD3\xF0\xF5\xF3\xF8"; // SQL0538 in EBCDIC
|
||||
|
||||
#endif
|
@ -1,553 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "db2i_file.h"
|
||||
#include "db2i_charsetSupport.h"
|
||||
#include "db2i_collationSupport.h"
|
||||
#include "db2i_misc.h"
|
||||
#include "db2i_errors.h"
|
||||
#include "my_dir.h"
|
||||
|
||||
db2i_table::db2i_table(const TABLE_SHARE* myTable, const char* path) :
|
||||
mysqlTable(myTable),
|
||||
db2StartId(0),
|
||||
blobFieldCount(0),
|
||||
blobFields(NULL),
|
||||
blobFieldActualSizes(NULL),
|
||||
logicalFiles(NULL),
|
||||
physicalFile(NULL),
|
||||
db2TableNameSQLAscii(NULL),
|
||||
db2LibNameSQLAscii(NULL)
|
||||
{
|
||||
char asciiLibName[MAX_DB2_SCHEMANAME_LENGTH + 1];
|
||||
getDB2LibNameFromPath(path, asciiLibName, ASCII_NATIVE);
|
||||
|
||||
char asciiFileName[MAX_DB2_FILENAME_LENGTH + 1];
|
||||
getDB2FileNameFromPath(path, asciiFileName, ASCII_NATIVE);
|
||||
|
||||
size_t libNameLen = strlen(asciiLibName);
|
||||
size_t fileNameLen = strlen(asciiFileName);
|
||||
|
||||
db2LibNameEbcdic=(char *)
|
||||
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
|
||||
&db2LibNameEbcdic, libNameLen+1,
|
||||
&db2LibNameAscii, libNameLen+1,
|
||||
&db2LibNameSQLAscii, libNameLen*2 + 1,
|
||||
&db2TableNameEbcdic, fileNameLen+1,
|
||||
&db2TableNameAscii, fileNameLen+1,
|
||||
&db2TableNameSQLAscii, fileNameLen*2 + 1,
|
||||
NullS);
|
||||
|
||||
if (likely(db2LibNameEbcdic))
|
||||
{
|
||||
memcpy(db2LibNameAscii, asciiLibName, libNameLen);
|
||||
convertNativeToSQLName(db2LibNameAscii, db2LibNameSQLAscii);
|
||||
convToEbcdic(db2LibNameAscii, db2LibNameEbcdic, libNameLen);
|
||||
memcpy(db2TableNameAscii, asciiFileName, fileNameLen);
|
||||
convertNativeToSQLName(db2TableNameAscii, db2TableNameSQLAscii);
|
||||
convToEbcdic(db2TableNameAscii, db2TableNameEbcdic, fileNameLen);
|
||||
}
|
||||
|
||||
conversionDefinitions[toMySQL] = NULL;
|
||||
conversionDefinitions[toDB2] = NULL;
|
||||
|
||||
isTemporaryTable = (strstr(mysqlTable->path.str, mysql_tmpdir) == mysqlTable->path.str);
|
||||
}
|
||||
|
||||
|
||||
int32 db2i_table::initDB2Objects(const char* path)
|
||||
{
|
||||
uint fileObjects = 1 + mysqlTable->keys;
|
||||
ValidatedPointer<ShrDef> fileDefnSpace(sizeof(ShrDef) * fileObjects);
|
||||
|
||||
physicalFile = new db2i_file(this);
|
||||
physicalFile->fillILEDefn(&fileDefnSpace[0], true);
|
||||
|
||||
logicalFileCount = mysqlTable->keys;
|
||||
if (logicalFileCount > 0)
|
||||
{
|
||||
logicalFiles = new db2i_file*[logicalFileCount];
|
||||
for (int k = 0; k < logicalFileCount; k++)
|
||||
{
|
||||
logicalFiles[k] = new db2i_file(this, k);
|
||||
logicalFiles[k]->fillILEDefn(&fileDefnSpace[k+1], false);
|
||||
}
|
||||
}
|
||||
|
||||
ValidatedPointer<FILE_HANDLE> fileDefnHandles(sizeof(FILE_HANDLE) * fileObjects);
|
||||
size_t formatSpaceLen = sizeof(format_hdr_t) + mysqlTable->fields * sizeof(DB2Field);
|
||||
formatSpace.alloc(formatSpaceLen);
|
||||
|
||||
int rc = db2i_ileBridge::getBridgeForThread()->
|
||||
expectErrors(QMY_ERR_RTNFMT)->
|
||||
allocateFileDefn(fileDefnSpace,
|
||||
fileDefnHandles,
|
||||
fileObjects,
|
||||
db2LibNameEbcdic,
|
||||
strlen(db2LibNameEbcdic),
|
||||
formatSpace,
|
||||
formatSpaceLen);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
// We have to handle a format space error as a special case of a FID
|
||||
// mismatch. We should only get the space error if columns have been added
|
||||
// to the DB2 table without MySQL's knowledge, which is effectively a
|
||||
// FID problem.
|
||||
if (rc == QMY_ERR_RTNFMT)
|
||||
{
|
||||
rc = QMY_ERR_LVLID_MISMATCH;
|
||||
getErrTxt(rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
convFromEbcdic(((format_hdr_t*)formatSpace)->FilLvlId, fileLevelID, sizeof(fileLevelID));
|
||||
|
||||
if (!doFileIDsMatch(path))
|
||||
{
|
||||
getErrTxt(QMY_ERR_LVLID_MISMATCH);
|
||||
return QMY_ERR_LVLID_MISMATCH;
|
||||
}
|
||||
|
||||
physicalFile->setMasterDefnHandle(fileDefnHandles[0]);
|
||||
for (int k = 0; k < mysqlTable->keys; k++)
|
||||
{
|
||||
logicalFiles[k]->setMasterDefnHandle(fileDefnHandles[k+1]);
|
||||
}
|
||||
|
||||
db2StartId = (uint64)(((format_hdr_t*)formatSpace)->StartIdVal);
|
||||
db2Fields = (DB2Field*)((char*)(void*)formatSpace + ((format_hdr_t*)formatSpace)->ColDefOff);
|
||||
|
||||
uint fields = mysqlTable->fields;
|
||||
for (int i = 0; i < fields; ++i)
|
||||
{
|
||||
if (db2Field(i).isBlob())
|
||||
{
|
||||
blobFieldCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (blobFieldCount)
|
||||
{
|
||||
blobFieldActualSizes = (uint*)my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
|
||||
&blobFieldActualSizes, blobFieldCount * sizeof(uint),
|
||||
&blobFields, blobFieldCount * sizeof(uint16),
|
||||
NullS);
|
||||
|
||||
int b = 0;
|
||||
for (int i = 0; i < fields; ++i)
|
||||
{
|
||||
if (db2Field(i).isBlob())
|
||||
{
|
||||
blobFields[b++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my_multi_malloc(MYF(MY_WME),
|
||||
&conversionDefinitions[toMySQL], fields * sizeof(iconv_t),
|
||||
&conversionDefinitions[toDB2], fields * sizeof(iconv_t),
|
||||
NullS);
|
||||
for (int i = 0; i < fields; ++i)
|
||||
{
|
||||
conversionDefinitions[toMySQL][i] = (iconv_t)(-1);
|
||||
conversionDefinitions[toDB2][i] = (iconv_t)(-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int db2i_table::fastInitForCreate(const char* path)
|
||||
{
|
||||
ValidatedPointer<ShrDef> fileDefnSpace(sizeof(ShrDef));
|
||||
|
||||
physicalFile = new db2i_file(this);
|
||||
physicalFile->fillILEDefn(fileDefnSpace, true);
|
||||
|
||||
ValidatedPointer<FILE_HANDLE> fileDefnHandles(sizeof(FILE_HANDLE));
|
||||
|
||||
size_t formatSpaceLen = sizeof(format_hdr_t) +
|
||||
mysqlTable->fields * sizeof(DB2Field);
|
||||
formatSpace.alloc(formatSpaceLen);
|
||||
|
||||
int rc = db2i_ileBridge::getBridgeForThread()->allocateFileDefn(fileDefnSpace,
|
||||
fileDefnHandles,
|
||||
1,
|
||||
db2LibNameEbcdic,
|
||||
strlen(db2LibNameEbcdic),
|
||||
formatSpace,
|
||||
formatSpaceLen);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
convFromEbcdic(((format_hdr_t*)formatSpace)->FilLvlId, fileLevelID, sizeof(fileLevelID));
|
||||
doFileIDsMatch(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool db2i_table::doFileIDsMatch(const char* path)
|
||||
{
|
||||
char name_buff[FN_REFLEN];
|
||||
|
||||
fn_format(name_buff, path, "", FID_EXT, (MY_REPLACE_EXT | MY_UNPACK_FILENAME));
|
||||
|
||||
File fd = my_open(name_buff, O_RDONLY, MYF(0));
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
fd = my_create(name_buff, 0, O_WRONLY, MYF(MY_WME));
|
||||
|
||||
if (fd == -1)
|
||||
{
|
||||
// TODO: Report errno here
|
||||
return false;
|
||||
}
|
||||
my_write(fd, (uchar*)fileLevelID, sizeof(fileLevelID), MYF(MY_WME));
|
||||
my_close(fd, MYF(0));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Report errno here
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
char diskFID[sizeof(fileLevelID)];
|
||||
|
||||
bool match = false;
|
||||
|
||||
if (my_read(fd, (uchar*)diskFID, sizeof(diskFID), MYF(MY_WME)) == sizeof(diskFID) &&
|
||||
(memcmp(diskFID, fileLevelID, sizeof(diskFID)) == 0))
|
||||
match = true;
|
||||
|
||||
my_close(fd, MYF(0));
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
void db2i_table::deleteAssocFiles(const char* name)
|
||||
{
|
||||
char name_buff[FN_REFLEN];
|
||||
fn_format(name_buff, name, "", FID_EXT, (MY_REPLACE_EXT | MY_UNPACK_FILENAME));
|
||||
my_delete(name_buff, MYF(0));
|
||||
}
|
||||
|
||||
void db2i_table::renameAssocFiles(const char* from, const char* to)
|
||||
{
|
||||
rename_file_ext(from, to, FID_EXT);
|
||||
}
|
||||
|
||||
|
||||
db2i_table::~db2i_table()
|
||||
{
|
||||
my_free(blobFieldActualSizes);
|
||||
my_free(conversionDefinitions[toMySQL]);
|
||||
|
||||
if (logicalFiles)
|
||||
{
|
||||
for (int k = 0; k < logicalFileCount; ++k)
|
||||
{
|
||||
delete logicalFiles[k];
|
||||
}
|
||||
|
||||
delete[] logicalFiles;
|
||||
}
|
||||
delete physicalFile;
|
||||
|
||||
my_free(db2LibNameEbcdic);
|
||||
}
|
||||
|
||||
void db2i_table::getDB2QualifiedName(char* to)
|
||||
{
|
||||
strcat(to, getDB2LibName(ASCII_SQL));
|
||||
strcat(to, ".");
|
||||
strcat(to, getDB2TableName(ASCII_SQL));
|
||||
}
|
||||
|
||||
|
||||
void db2i_table::getDB2QualifiedNameFromPath(const char* path, char* to)
|
||||
{
|
||||
getDB2LibNameFromPath(path, to);
|
||||
strcat(to, ".");
|
||||
getDB2FileNameFromPath(path, strend(to));
|
||||
}
|
||||
|
||||
|
||||
size_t db2i_table::smartFilenameToTableName(const char *in, char* out, size_t outlen)
|
||||
{
|
||||
if (strchr(in, '@') == NULL)
|
||||
{
|
||||
return filename_to_tablename(in, out, outlen);
|
||||
}
|
||||
|
||||
char* test = (char*) my_malloc(outlen, MYF(MY_WME));
|
||||
|
||||
filename_to_tablename(in, test, outlen);
|
||||
|
||||
char* cur = test;
|
||||
|
||||
while (*cur)
|
||||
{
|
||||
if ((*cur <= 0x20) || (*cur >= 0x80))
|
||||
{
|
||||
strncpy(out, in, outlen);
|
||||
my_free(test);
|
||||
return min(outlen, strlen(out));
|
||||
}
|
||||
++cur;
|
||||
}
|
||||
|
||||
strncpy(out, test, outlen);
|
||||
my_free(test);
|
||||
return min(outlen, strlen(out));
|
||||
}
|
||||
|
||||
void db2i_table::filenameToTablename(const char* in, char* out, size_t outlen)
|
||||
{
|
||||
if (strchr(in, '#') == NULL)
|
||||
{
|
||||
smartFilenameToTableName(in, out, outlen);
|
||||
return;
|
||||
}
|
||||
|
||||
char* temp = (char*)sql_alloc(outlen);
|
||||
|
||||
const char* part1, *part2, *part3, *part4;
|
||||
part1 = in;
|
||||
part2 = strstr(part1, "#P#");
|
||||
if (part2);
|
||||
{
|
||||
part3 = part2 + 3;
|
||||
part4 = strchr(part3, '#');
|
||||
if (!part4)
|
||||
part4 = strend(in);
|
||||
}
|
||||
|
||||
memcpy(temp, part1, min(outlen, part2 - part1));
|
||||
temp[min(outlen-1, part2-part1)] = 0;
|
||||
|
||||
int32 accumLen = smartFilenameToTableName(temp, out, outlen);
|
||||
|
||||
if (part2 && (accumLen + 4 < outlen))
|
||||
{
|
||||
strcat(out, "#P#");
|
||||
accumLen += 4;
|
||||
|
||||
memset(temp, 0, min(outlen, part2-part1));
|
||||
memcpy(temp, part3, min(outlen, part4-part3));
|
||||
temp[min(outlen-1, part4-part3)] = 0;
|
||||
|
||||
accumLen += smartFilenameToTableName(temp, strend(out), outlen-accumLen);
|
||||
|
||||
if (part4 && (accumLen + (strend(in) - part4 + 1) < outlen))
|
||||
{
|
||||
strcat(out, part4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void db2i_table::getDB2LibNameFromPath(const char* path, char* lib, NameFormatFlags format)
|
||||
{
|
||||
if (strstr(path, mysql_tmpdir) == path)
|
||||
{
|
||||
strcpy(lib, DB2I_TEMP_TABLE_SCHEMA);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* c = strend(path) - 1;
|
||||
while (c > path && *c != '\\' && *c != '/')
|
||||
--c;
|
||||
|
||||
if (c != path)
|
||||
{
|
||||
const char* dbEnd = c;
|
||||
do {
|
||||
--c;
|
||||
} while (c >= path && *c != '\\' && *c != '/');
|
||||
|
||||
if (c >= path)
|
||||
{
|
||||
const char* dbStart = c+1;
|
||||
char fileName[FN_REFLEN];
|
||||
memcpy(fileName, dbStart, dbEnd - dbStart);
|
||||
fileName[dbEnd-dbStart] = 0;
|
||||
|
||||
char dbName[MAX_DB2_SCHEMANAME_LENGTH+1];
|
||||
filenameToTablename(fileName, dbName , sizeof(dbName));
|
||||
|
||||
convertMySQLNameToDB2Name(dbName, lib, sizeof(dbName), true, (format==ASCII_SQL) );
|
||||
}
|
||||
else
|
||||
DBUG_ASSERT(0); // This should never happen!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void db2i_table::getDB2FileNameFromPath(const char* path, char* file, NameFormatFlags format)
|
||||
{
|
||||
const char* fileEnd = strend(path);
|
||||
const char* c = fileEnd;
|
||||
while (c > path && *c != '\\' && *c != '/')
|
||||
--c;
|
||||
|
||||
if (c != path)
|
||||
{
|
||||
const char* fileStart = c+1;
|
||||
char fileName[FN_REFLEN];
|
||||
memcpy(fileName, fileStart, fileEnd - fileStart);
|
||||
fileName[fileEnd - fileStart] = 0;
|
||||
char db2Name[MAX_DB2_FILENAME_LENGTH+1];
|
||||
filenameToTablename(fileName, db2Name, sizeof(db2Name));
|
||||
convertMySQLNameToDB2Name(db2Name, file, sizeof(db2Name), true, (format==ASCII_SQL) );
|
||||
}
|
||||
}
|
||||
|
||||
// Generates the DB2 index name when given the MySQL index and table names.
|
||||
int32 db2i_table::appendQualifiedIndexFileName(const char* indexName,
|
||||
const char* tableName,
|
||||
String& to,
|
||||
NameFormatFlags format,
|
||||
enum_DB2I_INDEX_TYPE type)
|
||||
{
|
||||
char generatedName[MAX_DB2_FILENAME_LENGTH+1];
|
||||
strncpy(generatedName, indexName, DB2I_INDEX_NAME_LENGTH_TO_PRESERVE);
|
||||
generatedName[DB2I_INDEX_NAME_LENGTH_TO_PRESERVE] = 0;
|
||||
char* endOfGeneratedName;
|
||||
|
||||
if (type == typeDefault)
|
||||
{
|
||||
strcat(generatedName, DB2I_DEFAULT_INDEX_NAME_DELIMITER);
|
||||
endOfGeneratedName = strend(generatedName);
|
||||
}
|
||||
else if (type != typeNone)
|
||||
{
|
||||
strcat(generatedName, DB2I_ADDL_INDEX_NAME_DELIMITER);
|
||||
endOfGeneratedName = strend(generatedName);
|
||||
*(endOfGeneratedName-2) = char(type);
|
||||
}
|
||||
|
||||
uint lenWithoutFile = endOfGeneratedName - generatedName;
|
||||
|
||||
char strippedTableName[MAX_DB2_FILENAME_LENGTH+1];
|
||||
if (format == ASCII_SQL)
|
||||
{
|
||||
strcpy(strippedTableName, tableName);
|
||||
stripExtraQuotes(strippedTableName+1, sizeof(strippedTableName));
|
||||
tableName = strippedTableName;
|
||||
}
|
||||
|
||||
if (strlen(tableName) > (MAX_DB2_FILENAME_LENGTH-lenWithoutFile))
|
||||
return -1;
|
||||
|
||||
strncat(generatedName,
|
||||
tableName+1,
|
||||
min(strlen(tableName), (MAX_DB2_FILENAME_LENGTH-lenWithoutFile))-2 );
|
||||
|
||||
char finalName[MAX_DB2_FILENAME_LENGTH+1];
|
||||
convertMySQLNameToDB2Name(generatedName, finalName, sizeof(finalName), true, (format==ASCII_SQL));
|
||||
to.append(finalName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void db2i_table::findConversionDefinition(enum_conversionDirection direction, uint16 fieldID)
|
||||
{
|
||||
getConversion(direction,
|
||||
mysqlTable->field[fieldID]->charset(),
|
||||
db2Field(fieldID).getCCSID(),
|
||||
conversionDefinitions[direction][fieldID]);
|
||||
}
|
||||
|
||||
|
||||
db2i_file::db2i_file(db2i_table* table) : db2Table(table)
|
||||
{
|
||||
commonCtorInit();
|
||||
|
||||
DBUG_ASSERT(table->getMySQLTable()->table_name.length <= MAX_DB2_FILENAME_LENGTH-2);
|
||||
|
||||
db2FileName = (char*)table->getDB2TableName(db2i_table::EBCDIC_NATIVE);
|
||||
}
|
||||
|
||||
db2i_file::db2i_file(db2i_table* table, int index) : db2Table(table)
|
||||
{
|
||||
commonCtorInit();
|
||||
|
||||
if ((index == table->getMySQLTable()->primary_key) && !table->isTemporary())
|
||||
{
|
||||
db2FileName = (char*)table->getDB2TableName(db2i_table::EBCDIC_NATIVE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate the index name (in index___table form); quote and EBCDICize it.
|
||||
String qualifiedPath;
|
||||
qualifiedPath.length(0);
|
||||
|
||||
const char* asciiFileName = table->getDB2TableName(db2i_table::ASCII_NATIVE);
|
||||
|
||||
db2i_table::appendQualifiedIndexFileName(table->getMySQLTable()->key_info[index].name,
|
||||
asciiFileName,
|
||||
qualifiedPath,
|
||||
db2i_table::ASCII_NATIVE,
|
||||
typeDefault);
|
||||
|
||||
db2FileName = (char*)my_malloc(qualifiedPath.length()+1, MYF(MY_WME | MY_ZEROFILL));
|
||||
convToEbcdic(qualifiedPath.ptr(), db2FileName, qualifiedPath.length());
|
||||
}
|
||||
}
|
||||
|
||||
void db2i_file::commonCtorInit()
|
||||
{
|
||||
masterDefn = 0;
|
||||
memset(&formats, 0, maxRowFormats*sizeof(RowFormat));
|
||||
}
|
||||
|
||||
|
||||
void db2i_file::fillILEDefn(ShrDef* defn, bool readInArrivalSeq)
|
||||
{
|
||||
defn->ObjNamLen = strlen(db2FileName);
|
||||
DBUG_ASSERT(defn->ObjNamLen <= sizeof(defn->ObjNam));
|
||||
memcpy(defn->ObjNam, db2FileName, defn->ObjNamLen);
|
||||
defn->ArrSeq[0] = (readInArrivalSeq ? QMY_YES : QMY_NO);
|
||||
}
|
||||
|
@ -1,446 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DB2I_FILE_H
|
||||
#define DB2I_FILE_H
|
||||
|
||||
#include "db2i_global.h"
|
||||
#include "db2i_ileBridge.h"
|
||||
#include "db2i_validatedPointer.h"
|
||||
#include "my_atomic.h"
|
||||
#include "db2i_iconv.h"
|
||||
#include "db2i_charsetSupport.h"
|
||||
|
||||
const char FID_EXT[] = ".FID";
|
||||
|
||||
class db2i_file;
|
||||
|
||||
#pragma pack(1)
|
||||
struct DB2LobField
|
||||
{
|
||||
char reserved1;
|
||||
uint32 length;
|
||||
char reserved2[4];
|
||||
uint32 ordinal;
|
||||
ILEMemHandle dataHandle;
|
||||
char reserved3[8];
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
class DB2Field
|
||||
{
|
||||
public:
|
||||
uint16 getType() const { return *(uint16*)(&definition.ColType); }
|
||||
uint16 getByteLengthInRecord() const { return definition.ColLen; }
|
||||
uint16 getDataLengthInRecord() const
|
||||
{
|
||||
return (getType() == QMY_VARCHAR || getType() == QMY_VARGRAPHIC ? definition.ColLen - 2 : definition.ColLen);
|
||||
}
|
||||
uint16 getCCSID() const { return *(uint16*)(&definition.ColCCSID); }
|
||||
bool isBlob() const
|
||||
{
|
||||
uint16 type = getType();
|
||||
return (type == QMY_BLOBCLOB || type == QMY_DBCLOB);
|
||||
}
|
||||
uint16 getBufferOffset() const { return definition.ColBufOff; }
|
||||
uint16 calcBlobPad() const
|
||||
{
|
||||
DBUG_ASSERT(isBlob());
|
||||
return getByteLengthInRecord() - sizeof (DB2LobField);
|
||||
}
|
||||
DB2LobField* asBlobField(char* buf) const
|
||||
{
|
||||
DBUG_ASSERT(isBlob());
|
||||
return (DB2LobField*)(buf + getBufferOffset() + calcBlobPad());
|
||||
}
|
||||
private:
|
||||
col_def_t definition;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class db2i_table
|
||||
|
||||
@details
|
||||
This class describes the logical SQL table provided by DB2.
|
||||
It stores "table-scoped" information such as the name of the
|
||||
DB2 schema, BLOB descriptions, and the corresponding MySQL table definition.
|
||||
Only one instance exists per SQL table.
|
||||
*/
|
||||
class db2i_table
|
||||
{
|
||||
public:
|
||||
enum NameFormatFlags
|
||||
{
|
||||
ASCII_SQL,
|
||||
ASCII_NATIVE,
|
||||
EBCDIC_NATIVE
|
||||
};
|
||||
|
||||
db2i_table(const TABLE_SHARE* myTable, const char* path = NULL);
|
||||
|
||||
~db2i_table();
|
||||
|
||||
int32 initDB2Objects(const char* path);
|
||||
|
||||
const TABLE_SHARE* getMySQLTable() const
|
||||
{
|
||||
return mysqlTable;
|
||||
}
|
||||
|
||||
uint64 getStartId() const
|
||||
{
|
||||
return db2StartId;
|
||||
}
|
||||
|
||||
void updateStartId(uint64 newStartId)
|
||||
{
|
||||
db2StartId = newStartId;
|
||||
}
|
||||
|
||||
bool hasBlobs() const
|
||||
{
|
||||
return (blobFieldCount > 0);
|
||||
}
|
||||
|
||||
uint16 getBlobCount() const
|
||||
{
|
||||
return blobFieldCount;
|
||||
}
|
||||
|
||||
uint getBlobFieldActualSize(uint fieldIndex) const
|
||||
{
|
||||
return blobFieldActualSizes[getBlobIdFromField(fieldIndex)];
|
||||
}
|
||||
|
||||
void updateBlobFieldActualSize(uint fieldIndex, uint32 newSize)
|
||||
{
|
||||
// It's OK that this isn't threadsafe, since this is just an advisory
|
||||
// value. If a race condition causes the lesser of two values to be stored,
|
||||
// that's OK.
|
||||
uint16 blobID = getBlobIdFromField(fieldIndex);
|
||||
DBUG_ASSERT(blobID < blobFieldCount);
|
||||
|
||||
if (blobFieldActualSizes[blobID] < newSize)
|
||||
{
|
||||
blobFieldActualSizes[blobID] = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* getDB2LibName(NameFormatFlags format = EBCDIC_NATIVE)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case EBCDIC_NATIVE:
|
||||
return db2LibNameEbcdic; break;
|
||||
case ASCII_NATIVE:
|
||||
return db2LibNameAscii; break;
|
||||
case ASCII_SQL:
|
||||
return db2LibNameSQLAscii; break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* getDB2TableName(NameFormatFlags format = EBCDIC_NATIVE) const
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case EBCDIC_NATIVE:
|
||||
return db2TableNameEbcdic; break;
|
||||
case ASCII_NATIVE:
|
||||
return db2TableNameAscii; break;
|
||||
case ASCII_SQL:
|
||||
return db2TableNameAscii; break;
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DB2Field& db2Field(int fieldID) const { return db2Fields[fieldID]; }
|
||||
DB2Field& db2Field(const Field* field) const { return db2Field(field->field_index); }
|
||||
|
||||
void processFormatSpace();
|
||||
|
||||
void* getFormatSpace(size_t& spaceNeeded)
|
||||
{
|
||||
DBUG_ASSERT(formatSpace == NULL);
|
||||
spaceNeeded = sizeof(format_hdr_t) + mysqlTable->fields * sizeof(DB2Field);
|
||||
formatSpace.alloc(spaceNeeded);
|
||||
return (void*)formatSpace;
|
||||
}
|
||||
|
||||
bool isTemporary() const
|
||||
{
|
||||
return isTemporaryTable;
|
||||
}
|
||||
|
||||
void getDB2QualifiedName(char* to);
|
||||
static void getDB2LibNameFromPath(const char* path, char* lib, NameFormatFlags format=ASCII_SQL);
|
||||
static void getDB2FileNameFromPath(const char* path, char* file, NameFormatFlags format=ASCII_SQL);
|
||||
static void getDB2QualifiedNameFromPath(const char* path, char* to);
|
||||
static int32 appendQualifiedIndexFileName(const char* indexName,
|
||||
const char* tableName,
|
||||
String& to,
|
||||
NameFormatFlags format=ASCII_SQL,
|
||||
enum_DB2I_INDEX_TYPE type=typeDefault);
|
||||
|
||||
uint16 getBlobIdFromField(uint16 fieldID) const
|
||||
{
|
||||
for (int i = 0; i < blobFieldCount; ++i)
|
||||
{
|
||||
if (blobFields[i] == fieldID)
|
||||
return i;
|
||||
}
|
||||
DBUG_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
iconv_t& getConversionDefinition(enum_conversionDirection direction,
|
||||
uint16 fieldID)
|
||||
{
|
||||
if (conversionDefinitions[direction][fieldID] == (iconv_t)(-1))
|
||||
findConversionDefinition(direction, fieldID);
|
||||
|
||||
return conversionDefinitions[direction][fieldID];
|
||||
}
|
||||
|
||||
const db2i_file* dataFile() const
|
||||
{
|
||||
return physicalFile;
|
||||
}
|
||||
|
||||
const db2i_file* indexFile(uint idx) const
|
||||
{
|
||||
return logicalFiles[idx];
|
||||
}
|
||||
|
||||
const char* getFileLevelID() const
|
||||
{
|
||||
return fileLevelID;
|
||||
}
|
||||
|
||||
static void deleteAssocFiles(const char* name);
|
||||
static void renameAssocFiles(const char* from, const char* to);
|
||||
|
||||
int fastInitForCreate(const char* path);
|
||||
int initDiscoveredTable(const char* path);
|
||||
|
||||
uint16* blobFields;
|
||||
|
||||
private:
|
||||
|
||||
void findConversionDefinition(enum_conversionDirection direction, uint16 fieldID);
|
||||
static void filenameToTablename(const char* in, char* out, size_t outlen);
|
||||
static size_t smartFilenameToTableName(const char *in, char* out, size_t outlen);
|
||||
void convertNativeToSQLName(const char* input,
|
||||
char* output)
|
||||
{
|
||||
|
||||
output[0] = input[0];
|
||||
|
||||
uint o = 1;
|
||||
uint i = 1;
|
||||
do
|
||||
{
|
||||
output[o++] = input[i];
|
||||
if (input[i] == '"' && input[i+1])
|
||||
output[o++] = '"';
|
||||
} while (input[++i]);
|
||||
|
||||
output[o] = 0; // This isn't the most user-friendly way to handle overflows,
|
||||
// but at least its safe.
|
||||
}
|
||||
|
||||
bool doFileIDsMatch(const char* path);
|
||||
|
||||
ValidatedPointer<format_hdr_t> formatSpace;
|
||||
DB2Field* db2Fields;
|
||||
uint64 db2StartId; // Starting value for identity column
|
||||
uint16 blobFieldCount; // Count of LOB fields in the DB2 table
|
||||
uint* blobFieldActualSizes; // Array of LOB field lengths (actual vs. allocated).
|
||||
// This is updated as LOBs are read and will contain
|
||||
// the length of the longest known LOB in that field.
|
||||
iconv_t* conversionDefinitions[2];
|
||||
|
||||
const TABLE_SHARE* mysqlTable;
|
||||
uint16 logicalFileCount;
|
||||
char* db2LibNameEbcdic; // Quoted and in EBCDIC
|
||||
char* db2LibNameAscii;
|
||||
char* db2TableNameEbcdic;
|
||||
char* db2TableNameAscii;
|
||||
char* db2TableNameSQLAscii;
|
||||
char* db2LibNameSQLAscii;
|
||||
|
||||
db2i_file* physicalFile;
|
||||
db2i_file** logicalFiles;
|
||||
|
||||
bool isTemporaryTable;
|
||||
char fileLevelID[13];
|
||||
};
|
||||
|
||||
/**
|
||||
@class db2i_file
|
||||
|
||||
@details This class describes a file object underlaying a particular SQL
|
||||
table. Both "physical files" (data) and "logical files" (indices) are
|
||||
described by this class. Only one instance of the class exists per DB2 file
|
||||
object. The single instance is responsible for de/allocating the multiple
|
||||
handles used by the handlers.
|
||||
*/
|
||||
class db2i_file
|
||||
{
|
||||
|
||||
public:
|
||||
struct RowFormat
|
||||
{
|
||||
uint16 readRowLen;
|
||||
uint16 readRowNullOffset;
|
||||
uint16 writeRowLen;
|
||||
uint16 writeRowNullOffset;
|
||||
char inited;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
// Construct an instance for a physical file.
|
||||
db2i_file(db2i_table* table);
|
||||
|
||||
// Construct an instance for a logical file.
|
||||
db2i_file(db2i_table* table, int index);
|
||||
|
||||
~db2i_file()
|
||||
{
|
||||
if (masterDefn)
|
||||
db2i_ileBridge::getBridgeForThread()->deallocateFile(masterDefn);
|
||||
|
||||
if (db2FileName != (char*)db2Table->getDB2TableName(db2i_table::EBCDIC_NATIVE))
|
||||
my_free(db2FileName);
|
||||
}
|
||||
|
||||
// This is roughly equivalent to an "open". It tells ILE to allocate a descriptor
|
||||
// for the file. The associated handle is returned to the caller.
|
||||
int allocateNewInstance(FILE_HANDLE* newHandle, ILEMemHandle inuseSpace) const
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = db2i_ileBridge::getBridgeForThread()->allocateFileInstance(masterDefn,
|
||||
inuseSpace,
|
||||
newHandle);
|
||||
|
||||
if (rc) *newHandle = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
// This obtains the row layout associated with a particular access intent for
|
||||
// an open instance of the file.
|
||||
int obtainRowFormat(FILE_HANDLE instanceHandle,
|
||||
char intent,
|
||||
char commitLevel,
|
||||
const RowFormat** activeFormat) const
|
||||
{
|
||||
DBUG_ENTER("db2i_file::obtainRowFormat");
|
||||
RowFormat* rowFormat;
|
||||
|
||||
if (intent == QMY_UPDATABLE)
|
||||
rowFormat = &(formats[readWrite]);
|
||||
else if (intent == QMY_READ_ONLY)
|
||||
rowFormat = &(formats[readOnly]);
|
||||
|
||||
if (unlikely(!rowFormat->inited))
|
||||
{
|
||||
int rc = db2i_ileBridge::getBridgeForThread()->
|
||||
initFileForIO(instanceHandle,
|
||||
intent,
|
||||
commitLevel,
|
||||
&(rowFormat->writeRowLen),
|
||||
&(rowFormat->writeRowNullOffset),
|
||||
&(rowFormat->readRowLen),
|
||||
&(rowFormat->readRowNullOffset));
|
||||
if (rc) DBUG_RETURN(rc);
|
||||
rowFormat->inited = 1;
|
||||
}
|
||||
|
||||
*activeFormat = rowFormat;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
const char* getDB2FileName() const
|
||||
{
|
||||
return db2FileName;
|
||||
}
|
||||
|
||||
void fillILEDefn(ShrDef* defn, bool readInArrivalSeq);
|
||||
|
||||
void setMasterDefnHandle(FILE_HANDLE handle)
|
||||
{
|
||||
masterDefn = handle;
|
||||
}
|
||||
|
||||
FILE_HANDLE getMasterDefnHandle() const
|
||||
{
|
||||
return masterDefn;
|
||||
}
|
||||
|
||||
private:
|
||||
enum RowFormats
|
||||
{
|
||||
readOnly = 0,
|
||||
readWrite,
|
||||
maxRowFormats
|
||||
};
|
||||
|
||||
mutable RowFormat formats[maxRowFormats];
|
||||
|
||||
void commonCtorInit();
|
||||
|
||||
char* db2FileName; // Quoted and in EBCDIC
|
||||
|
||||
db2i_table* db2Table; // The logical SQL table contained by this file.
|
||||
|
||||
bool db2CanSort;
|
||||
|
||||
FILE_HANDLE masterDefn;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -1,138 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DB2I_GLOBAL_H
|
||||
#define DB2I_GLOBAL_H
|
||||
|
||||
#define MYSQL_SERVER 1
|
||||
|
||||
#include "my_global.h"
|
||||
#include "my_sys.h"
|
||||
|
||||
const uint MAX_DB2_KEY_PARTS=120;
|
||||
const int MAX_DB2_V5R4_LIBNAME_LENGTH = 10;
|
||||
const int MAX_DB2_V6R1_LIBNAME_LENGTH = 30;
|
||||
const int MAX_DB2_SCHEMANAME_LENGTH=258;
|
||||
const int MAX_DB2_FILENAME_LENGTH=258;
|
||||
const int MAX_DB2_COLNAME_LENGTH=128;
|
||||
const int MAX_DB2_SAVEPOINTNAME_LENGTH=128;
|
||||
const int MAX_DB2_QUALIFIEDNAME_LENGTH=MAX_DB2_V6R1_LIBNAME_LENGTH + 1 + MAX_DB2_FILENAME_LENGTH;
|
||||
const uint32 MAX_CHAR_LENGTH = 32765;
|
||||
const uint32 MAX_VARCHAR_LENGTH = 32739;
|
||||
const uint32 MAX_DEC_PRECISION = 63;
|
||||
const uint32 MAX_BLOB_LENGTH = 2147483646;
|
||||
const uint32 MAX_BINARY_LENGTH = MAX_CHAR_LENGTH;
|
||||
const uint32 MAX_VARBINARY_LENGTH = MAX_VARCHAR_LENGTH;
|
||||
const uint32 MAX_FULL_ALLOCATE_BLOB_LENGTH = 65536;
|
||||
const uint32 MAX_FOREIGN_LEN = 64000;
|
||||
const char* DB2I_TEMP_TABLE_SCHEMA = "QTEMP";
|
||||
const char DB2I_ADDL_INDEX_NAME_DELIMITER[5] = {'_','_','_','_','_'};
|
||||
const char DB2I_DEFAULT_INDEX_NAME_DELIMITER[3] = {'_','_','_'};
|
||||
const int DB2I_INDEX_NAME_LENGTH_TO_PRESERVE = 110;
|
||||
|
||||
enum enum_DB2I_INDEX_TYPE
|
||||
{
|
||||
typeNone = 0,
|
||||
typeDefault = 'D',
|
||||
typeHex = 'H',
|
||||
typeAscii = 'A'
|
||||
};
|
||||
|
||||
void* roundToQuadWordBdy(void* ptr)
|
||||
{
|
||||
return (void*)(((uint64)(ptr)+0xf) & ~0xf);
|
||||
}
|
||||
|
||||
typedef uint64_t ILEMemHandle;
|
||||
|
||||
struct OSVersion
|
||||
{
|
||||
uint8 v;
|
||||
uint8 r;
|
||||
};
|
||||
extern OSVersion osVersion;
|
||||
|
||||
|
||||
/**
|
||||
Allocate 16-byte aligned space using the MySQL heap allocator
|
||||
|
||||
@details Many of the spaces used by the QMY_* APIS are required to be
|
||||
aligned on 16 byte boundaries. The standard system malloc will do this
|
||||
alignment by default. However, in order to use the heap debug and tracking
|
||||
features of the mysql allocator, we chose to implement an aligning wrapper
|
||||
around my_malloc. Essentially, we overallocate the storage space, find the
|
||||
first aligned address in the space, store a pointer to the true malloc
|
||||
allocation in the bytes immediately preceding the aligned address, and return
|
||||
the aligned address to the caller.
|
||||
|
||||
@parm size The size of heap storage needed
|
||||
|
||||
@return A 16-byte aligned pointer to the storage requested.
|
||||
*/
|
||||
void* malloc_aligned(size_t size)
|
||||
{
|
||||
char* p;
|
||||
char* base;
|
||||
base = (char*)my_malloc(size + sizeof(void*) + 15, MYF(MY_WME));
|
||||
if (likely(base))
|
||||
{
|
||||
p = (char*)roundToQuadWordBdy(base + sizeof(void*));
|
||||
char** p2 = (char**)(p - sizeof(void*));
|
||||
*p2 = base;
|
||||
}
|
||||
else
|
||||
p = NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
Free a 16-byte aligned space alloced by malloc_aligned
|
||||
|
||||
@details We know that a pointer to the true malloced storage immediately
|
||||
precedes the aligned address, so we pull that out and call my_free().
|
||||
|
||||
@parm p A 16-byte aligned pointer generated by malloc_aligned
|
||||
*/
|
||||
void free_aligned(void* p)
|
||||
{
|
||||
if (likely(p))
|
||||
{
|
||||
my_free(*(char**)((char*)p-sizeof(void*)));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@file
|
||||
|
||||
@brief Used to redefine iconv symbols to the optimized "myconv" ones
|
||||
*/
|
||||
|
||||
#ifndef DB2I_ICONV_H
|
||||
#define DB2I_ICONV_H
|
||||
|
||||
#include "db2i_myconv.h"
|
||||
#define iconv_open(A, B) myconv_open(A, B, CONVERTER_DMAP)
|
||||
#define iconv_close myconv_close
|
||||
#define iconv myconv_dmap
|
||||
#define iconv_t myconv_t
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,499 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DB2I_ILEBRIDGE_H
|
||||
#define DB2I_ILEBRIDGE_H
|
||||
|
||||
#include "db2i_global.h"
|
||||
#include "mysql_priv.h"
|
||||
#include "as400_types.h"
|
||||
#include "as400_protos.h"
|
||||
#include "qmyse.h"
|
||||
#include "db2i_errors.h"
|
||||
|
||||
typedef uint64_t FILE_HANDLE;
|
||||
typedef my_thread_id CONNECTION_HANDLE;
|
||||
const char SAVEPOINT_NAME[] = {0xD4,0xE2,0xD7,0xC9,0xD5,0xE3,0xC5,0xD9,0xD5,0x0};
|
||||
const uint32 TACIT_ERRORS_SIZE=2;
|
||||
|
||||
enum db2i_InfoRequestSpec
|
||||
{
|
||||
objLength = 1,
|
||||
rowCount = 2,
|
||||
deletedRowCount = 4,
|
||||
rowsPerKey = 8,
|
||||
meanRowLen = 16,
|
||||
lastModTime = 32,
|
||||
createTime = 64,
|
||||
ioCount = 128
|
||||
};
|
||||
|
||||
extern handlerton *ibmdb2i_hton;
|
||||
struct IBMDB2I_SHARE;
|
||||
|
||||
const uint32 db2i_ileBridge_MAX_INPARM_SIZE = 512;
|
||||
const uint32 db2i_ileBridge_MAX_OUTPARM_SIZE = 512;
|
||||
|
||||
extern pthread_key(IleParms*, THR_ILEPARMS);
|
||||
struct IleParms
|
||||
{
|
||||
char inParms[db2i_ileBridge_MAX_INPARM_SIZE];
|
||||
char outParms[db2i_ileBridge_MAX_OUTPARM_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
@class db2i_ileBridge
|
||||
|
||||
Implements a connection-based interface to the QMY_* APIs
|
||||
|
||||
@details Each client connection that touches an IBMDB2I table has a "bridge"
|
||||
associated with it. This bridge is constructed on first use and provides a
|
||||
more C-like interface to the APIs. As well, it is reponsible for tracking
|
||||
connection scoped information such as statement transaction state and error
|
||||
message text. The bridge is destroyed when the connection ends.
|
||||
*/
|
||||
class db2i_ileBridge
|
||||
{
|
||||
enum ileFuncs
|
||||
{
|
||||
funcRegisterParameterSpaces,
|
||||
funcRegisterSpace,
|
||||
funcUnregisterSpace,
|
||||
funcProcessRequest,
|
||||
funcListEnd
|
||||
};
|
||||
|
||||
static db2i_ileBridge* globalBridge;
|
||||
public:
|
||||
|
||||
|
||||
static int setup();
|
||||
static void takedown();
|
||||
|
||||
/**
|
||||
Obtain a pointer to the bridge for the current connection.
|
||||
|
||||
If a MySQL client connection is on the stack, we get the associated brideg.
|
||||
Otherwise, we use the globalBridge.
|
||||
*/
|
||||
static db2i_ileBridge* getBridgeForThread()
|
||||
{
|
||||
THD* thd = current_thd;
|
||||
if (likely(thd))
|
||||
return getBridgeForThread(thd);
|
||||
|
||||
return globalBridge;
|
||||
}
|
||||
|
||||
/**
|
||||
Obtain a pointer to the bridge for the specified connection.
|
||||
|
||||
If a bridge exists already, we return it immediately. Otherwise, prepare
|
||||
a new bridge for the connection.
|
||||
*/
|
||||
static db2i_ileBridge* getBridgeForThread(const THD* thd)
|
||||
{
|
||||
void* thdData = *thd_ha_data(thd, ibmdb2i_hton);
|
||||
if (likely(thdData != NULL))
|
||||
return (db2i_ileBridge*)(thdData);
|
||||
|
||||
db2i_ileBridge* newBridge = createNewBridge(thd->thread_id);
|
||||
*thd_ha_data(thd, ibmdb2i_hton) = (void*)newBridge;
|
||||
return newBridge;
|
||||
}
|
||||
|
||||
static void destroyBridgeForThread(const THD* thd);
|
||||
static void registerPtr(const void* ptr, ILEMemHandle* receiver);
|
||||
static void unregisterPtr(ILEMemHandle handle);
|
||||
int32 allocateFileDefn(ILEMemHandle definitionSpace,
|
||||
ILEMemHandle handleSpace,
|
||||
uint16 fileCount,
|
||||
const char* schemaName,
|
||||
uint16 schemaNameLength,
|
||||
ILEMemHandle formatSpace,
|
||||
uint32 formatSpaceLen);
|
||||
int32 allocateFileInstance(FILE_HANDLE defnHandle,
|
||||
ILEMemHandle inuseSpace,
|
||||
FILE_HANDLE* instance);
|
||||
int32 deallocateFile(FILE_HANDLE fileHandle,
|
||||
bool postDropTable=FALSE);
|
||||
int32 read(FILE_HANDLE rfileHandle,
|
||||
ILEMemHandle buf,
|
||||
char accessIntent,
|
||||
char commitLevel,
|
||||
char orientation,
|
||||
bool asyncRead = FALSE,
|
||||
ILEMemHandle rrn = 0,
|
||||
ILEMemHandle key = 0,
|
||||
uint32 keylen = 0,
|
||||
uint16 keyParts = 0,
|
||||
int pipeFD = -1);
|
||||
int32 readByRRN(FILE_HANDLE rfileHandle,
|
||||
ILEMemHandle buf,
|
||||
uint32 inRRN,
|
||||
char accessIntent,
|
||||
char commitLevel);
|
||||
int32 writeRows(FILE_HANDLE rfileHandle,
|
||||
ILEMemHandle buf,
|
||||
char commitLevel,
|
||||
int64* outIdVal,
|
||||
bool* outIdGen,
|
||||
uint32* dupKeyRRN,
|
||||
char** dupKeyName,
|
||||
uint32* dupKeyNameLen,
|
||||
uint32* outIdIncrement);
|
||||
uint32 execSQL(const char* statement,
|
||||
uint32 statementCount,
|
||||
uint8 commitLevel,
|
||||
bool autoCreateSchema = FALSE,
|
||||
bool dropSchema = FALSE,
|
||||
bool noCommit = FALSE,
|
||||
FILE_HANDLE fileHandle = 0);
|
||||
int32 prepOpen(const char* statement,
|
||||
FILE_HANDLE* rfileHandle,
|
||||
uint32* recLength);
|
||||
int32 deleteRow(FILE_HANDLE rfileHandle,
|
||||
uint32 rrn);
|
||||
int32 updateRow(FILE_HANDLE rfileHandle,
|
||||
uint32 rrn,
|
||||
ILEMemHandle buf,
|
||||
uint32* dupKeyRRN,
|
||||
char** dupKeyName,
|
||||
uint32* dupKeyNameLen);
|
||||
int32 commitmentControl(uint8 function);
|
||||
int32 savepoint(uint8 function,
|
||||
const char* savepointName);
|
||||
int32 recordsInRange(FILE_HANDLE rfileHandle,
|
||||
ILEMemHandle inSpc,
|
||||
uint32 inKeyCnt,
|
||||
uint32 inLiteralCnt,
|
||||
uint32 inBoundsOff,
|
||||
uint32 inLitDefOff,
|
||||
uint32 inLiteralsOff,
|
||||
uint32 inCutoff,
|
||||
uint32 inSpcLen,
|
||||
uint16 inEndByte,
|
||||
uint64* outRecCnt,
|
||||
uint16* outRtnCode);
|
||||
int32 rrlslck(FILE_HANDLE rfileHandle,
|
||||
char accessIntent);
|
||||
int32 lockObj(FILE_HANDLE rfileHandle,
|
||||
uint64 inTimeoutVal,
|
||||
char inAction,
|
||||
char inLockType,
|
||||
char inTimeout);
|
||||
int32 constraints(FILE_HANDLE rfileHandle,
|
||||
ILEMemHandle inSpc,
|
||||
uint32 inSpcLen,
|
||||
uint32* outLen,
|
||||
uint32* outCnt);
|
||||
int32 optimizeTable(FILE_HANDLE rfileHandle);
|
||||
static int32 initILE(const char* aspName,
|
||||
uint16* traceCtlPtr);
|
||||
int32 initFileForIO(FILE_HANDLE rfileHandle,
|
||||
char accessIntent,
|
||||
char commitLevel,
|
||||
uint16* inRecSize,
|
||||
uint16* inRecNullOffset,
|
||||
uint16* outRecSize,
|
||||
uint16* outRecNullOffset);
|
||||
int32 readInterrupt(FILE_HANDLE fileHandle);
|
||||
static int32 exitILE();
|
||||
|
||||
int32 objectOverride(FILE_HANDLE rfileHandle,
|
||||
ILEMemHandle buf,
|
||||
uint32 recordWidth = 0);
|
||||
|
||||
int32 retrieveTableInfo(FILE_HANDLE rfileHandle,
|
||||
uint16 dataRequested,
|
||||
ha_statistics& stats,
|
||||
ILEMemHandle inSpc = NULL);
|
||||
|
||||
int32 retrieveIndexInfo(FILE_HANDLE rfileHandle,
|
||||
uint64* outPageCnt);
|
||||
|
||||
int32 closeConnection(CONNECTION_HANDLE conn);
|
||||
int32 quiesceFileInstance(FILE_HANDLE rfileHandle);
|
||||
|
||||
/**
|
||||
Mark the beginning of a "statement transaction"
|
||||
|
||||
@detail MySQL "statement transactions" (see sql/handler.cc) are implemented
|
||||
as DB2 savepoints having a predefined name.
|
||||
|
||||
@return 0 if successful; error otherwise
|
||||
*/
|
||||
uint32 beginStmtTx()
|
||||
{
|
||||
DBUG_ENTER("db2i_ileBridge::beginStmtTx");
|
||||
if (stmtTxActive)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
stmtTxActive = true;
|
||||
|
||||
DBUG_RETURN(savepoint(QMY_SET_SAVEPOINT, SAVEPOINT_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
Commit a "statement transaction"
|
||||
|
||||
@return 0 if successful; error otherwise
|
||||
*/
|
||||
uint32 commitStmtTx()
|
||||
{
|
||||
DBUG_ENTER("db2i_ileBridge::commitStmtTx");
|
||||
DBUG_ASSERT(stmtTxActive);
|
||||
stmtTxActive = false;
|
||||
DBUG_RETURN(savepoint(QMY_RELEASE_SAVEPOINT, SAVEPOINT_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
Roll back a "statement transaction"
|
||||
|
||||
@return 0 if successful; error otherwise
|
||||
*/
|
||||
uint32 rollbackStmtTx()
|
||||
{
|
||||
DBUG_ENTER("db2i_ileBridge::rollbackStmtTx");
|
||||
DBUG_ASSERT(stmtTxActive);
|
||||
stmtTxActive = false;
|
||||
DBUG_RETURN(savepoint(QMY_ROLLBACK_SAVEPOINT, SAVEPOINT_NAME));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Provide storage for generating error messages.
|
||||
|
||||
This storage must persist until the error message is retrieved from the
|
||||
handler instance. It is for this reason that we associate it with the bridge.
|
||||
|
||||
@return Pointer to heap storage of MYSQL_ERRMSG_SIZE bytes
|
||||
*/
|
||||
char* getErrorStorage()
|
||||
{
|
||||
if (!connErrText)
|
||||
{
|
||||
connErrText = (char*)my_malloc(MYSQL_ERRMSG_SIZE, MYF(MY_WME));
|
||||
if (connErrText) connErrText[0] = 0;
|
||||
}
|
||||
|
||||
return connErrText;
|
||||
}
|
||||
|
||||
/**
|
||||
Free storage for generating error messages.
|
||||
*/
|
||||
void freeErrorStorage()
|
||||
{
|
||||
if (likely(connErrText))
|
||||
{
|
||||
my_free(connErrText);
|
||||
connErrText = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Store a file handle for later retrieval.
|
||||
|
||||
If deallocateFile encounters a lock when trying to perform its operation,
|
||||
the file remains allocated but must be deallocated later. This function
|
||||
provides a way for the connection to "remember" that this deallocation is
|
||||
still needed.
|
||||
|
||||
@param newname The name of the file to be added
|
||||
@param newhandle The handle associated with newname
|
||||
|
||||
*/
|
||||
void preserveHandle(const char* newname, FILE_HANDLE newhandle, IBMDB2I_SHARE* share)
|
||||
{
|
||||
pendingLockedHandles.add(newname, newhandle, share);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieve a file handle stored by preserveHandle().
|
||||
|
||||
@param name The name of the file to be retrieved.
|
||||
|
||||
@return The handle associated with name
|
||||
*/
|
||||
FILE_HANDLE findAndRemovePreservedHandle(const char* name, IBMDB2I_SHARE** share)
|
||||
{
|
||||
FILE_HANDLE hdl = pendingLockedHandles.findAndRemove(name, share);
|
||||
return hdl;
|
||||
}
|
||||
|
||||
/**
|
||||
Indicate which error messages should be suppressed on the next API call
|
||||
|
||||
These functions are useful for ensuring that the provided error numbers
|
||||
are returned if a failure occurs but do not cause a spurious error message
|
||||
to be returned.
|
||||
|
||||
@return A pointer to this instance
|
||||
*/
|
||||
db2i_ileBridge* expectErrors(int32 er1)
|
||||
{
|
||||
tacitErrors[0]=er1;
|
||||
return this;
|
||||
}
|
||||
|
||||
db2i_ileBridge* expectErrors(int32 er1, int32 er2)
|
||||
{
|
||||
tacitErrors[0]=er1;
|
||||
tacitErrors[1]=er2;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
Obtain the IBM i system message that accompanied the last API failure.
|
||||
|
||||
@return A pointer to the 7 character message ID.
|
||||
*/
|
||||
static const char* getErrorMsgID()
|
||||
{
|
||||
return ((Qmy_Error_output_t*)parms()->outParms)->MsgId;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert an API error code into the equivalent MySQL error code (if any)
|
||||
|
||||
@param rc The QMYSE API error code
|
||||
|
||||
@return If an equivalent exists, the MySQL error code; else rc
|
||||
*/
|
||||
static int32 translateErrorCode(int32 rc)
|
||||
{
|
||||
if (likely(rc == 0))
|
||||
return 0;
|
||||
|
||||
switch (rc)
|
||||
{
|
||||
case QMY_ERR_KEY_NOT_FOUND:
|
||||
return HA_ERR_KEY_NOT_FOUND;
|
||||
case QMY_ERR_DUP_KEY:
|
||||
return HA_ERR_FOUND_DUPP_KEY;
|
||||
case QMY_ERR_END_OF_FILE:
|
||||
return HA_ERR_END_OF_FILE;
|
||||
case QMY_ERR_LOCK_TIMEOUT:
|
||||
return HA_ERR_LOCK_WAIT_TIMEOUT;
|
||||
case QMY_ERR_CST_VIOLATION:
|
||||
return HA_ERR_NO_REFERENCED_ROW;
|
||||
case QMY_ERR_TABLE_NOT_FOUND:
|
||||
return HA_ERR_NO_SUCH_TABLE;
|
||||
case QMY_ERR_NON_UNIQUE_KEY:
|
||||
return ER_DUP_ENTRY;
|
||||
case QMY_ERR_MSGID:
|
||||
{
|
||||
if (memcmp(getErrorMsgID(), DB2I_CPF503A, 7) == 0)
|
||||
return HA_ERR_ROW_IS_REFERENCED;
|
||||
if (memcmp(getErrorMsgID(), DB2I_SQL0538, 7) == 0)
|
||||
return HA_ERR_CANNOT_ADD_FOREIGN;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static db2i_ileBridge* createNewBridge(CONNECTION_HANDLE connID);
|
||||
static void destroyBridge(db2i_ileBridge* bridge);
|
||||
static int registerParmSpace(char* in, char* out);
|
||||
static int32 doIt();
|
||||
int32 doItWithLog();
|
||||
|
||||
static _ILEpointer *functionSymbols; ///< Array of ILE function pointers
|
||||
CONNECTION_HANDLE cachedConnectionID; ///< The associated connection
|
||||
bool stmtTxActive; ///< Inside statement transaction
|
||||
char *connErrText; ///< Storage for error message
|
||||
int32 tacitErrors[TACIT_ERRORS_SIZE]; ///< List of errors to be suppressed
|
||||
|
||||
static IleParms* initParmsForThread();
|
||||
|
||||
/**
|
||||
Get space for passing parameters to the QMY_* APIs
|
||||
|
||||
@details A fixed-length parameter passing space is associated with each
|
||||
pthread. This space is allocated and registered by initParmsForThread()
|
||||
the first time a pthread works with a bridge. The space is cached away
|
||||
and remains available until the pthread ends. It became necessary to
|
||||
disassociate the parameter space from the bridge in order to support
|
||||
future enhancements to MySQL that sever the one-to-one relationship between
|
||||
pthreads and user connections. The QMY_* APIs scope a registered parameter
|
||||
space to the thread that executes the register operation.
|
||||
*/
|
||||
static IleParms* parms()
|
||||
{
|
||||
IleParms* p = my_pthread_getspecific_ptr(IleParms*, THR_ILEPARMS);
|
||||
if (likely(p))
|
||||
return p;
|
||||
|
||||
return initParmsForThread();
|
||||
}
|
||||
|
||||
class PreservedHandleList
|
||||
{
|
||||
friend db2i_ileBridge* db2i_ileBridge::createNewBridge(CONNECTION_HANDLE);
|
||||
public:
|
||||
void add(const char* newname, FILE_HANDLE newhandle, IBMDB2I_SHARE* share);
|
||||
FILE_HANDLE findAndRemove(const char* fileName, IBMDB2I_SHARE** share);
|
||||
|
||||
private:
|
||||
struct NameHandlePair
|
||||
{
|
||||
char name[FN_REFLEN];
|
||||
FILE_HANDLE handle;
|
||||
IBMDB2I_SHARE* share;
|
||||
NameHandlePair* next;
|
||||
}* head;
|
||||
} pendingLockedHandles;
|
||||
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
bool cachedStateIsCoherent()
|
||||
{
|
||||
return (current_thd->thread_id == cachedConnectionID);
|
||||
}
|
||||
|
||||
friend void db2i_ileBridge::unregisterPtr(ILEMemHandle);
|
||||
friend void db2i_ileBridge::registerPtr(const void*, ILEMemHandle*);
|
||||
static uint32 registeredPtrs;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -1,332 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "db2i_ioBuffers.h"
|
||||
|
||||
/**
|
||||
Request another block of rows
|
||||
|
||||
Request the next set of rows from DB2. This must only be called after
|
||||
newReadRequest().
|
||||
|
||||
@param orientation The direction to use when reading through the table.
|
||||
*/
|
||||
void IOAsyncReadBuffer::loadNewRows(char orientation)
|
||||
{
|
||||
rewind();
|
||||
maxRows() = rowsToBlock;
|
||||
|
||||
DBUG_PRINT("db2i_ioBuffers::loadNewRows", ("Requesting %d rows, async = %d", rowsToBlock, readIsAsync));
|
||||
|
||||
rc = getBridge()->expectErrors(QMY_ERR_END_OF_BLOCK, QMY_ERR_LOB_SPACE_TOO_SMALL)
|
||||
->read(file,
|
||||
ptr(),
|
||||
accessIntent,
|
||||
commitLevel,
|
||||
orientation,
|
||||
readIsAsync,
|
||||
rrnList,
|
||||
0,
|
||||
0,
|
||||
0);
|
||||
|
||||
DBUG_PRINT("db2i_ioBuffers::loadNewRows", ("recordsRead: %d, rc: %d", (uint32)rowCount(), rc));
|
||||
|
||||
|
||||
*releaseRowNeeded = true;
|
||||
|
||||
if (rc == QMY_ERR_END_OF_BLOCK)
|
||||
{
|
||||
// This is really just an informational error, so we ignore it.
|
||||
rc = 0;
|
||||
DBUG_PRINT("db2i_ioBuffers::loadNewRows", ("End of block signalled"));
|
||||
}
|
||||
else if (rc == QMY_ERR_END_OF_FILE)
|
||||
{
|
||||
// If we reach EOF or end-of-key, DB2 guarantees that no rows will be locked.
|
||||
rc = HA_ERR_END_OF_FILE;
|
||||
*releaseRowNeeded = false;
|
||||
}
|
||||
else if (rc == QMY_ERR_KEY_NOT_FOUND)
|
||||
{
|
||||
rc = HA_ERR_KEY_NOT_FOUND;
|
||||
*releaseRowNeeded = false;
|
||||
}
|
||||
|
||||
if (rc) closePipe();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Empty the message pipe to prepare for another read.
|
||||
*/
|
||||
void IOAsyncReadBuffer::drainPipe()
|
||||
{
|
||||
DBUG_ASSERT(pipeState == PendingFullBufferMsg);
|
||||
PipeRpy_t msg[32];
|
||||
int bytes;
|
||||
PipeRpy_t* lastMsg;
|
||||
while ((bytes = read(msgPipe, msg, sizeof(msg))) > 0)
|
||||
{
|
||||
DBUG_PRINT("db2i_ioBuffers::drainPipe",("Pipe returned %d bytes", bytes));
|
||||
lastMsg = &msg[bytes / (sizeof(msg[0]))-1];
|
||||
if (lastMsg->CumRowCnt == maxRows() ||
|
||||
lastMsg->RtnCod != 0)
|
||||
{
|
||||
pipeState = ConsumedFullBufferMsg;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
DBUG_PRINT("db2i_ioBuffers::drainPipe",("rc = %d, rows = %d, max = %d", lastMsg->RtnCod, lastMsg->CumRowCnt, (uint32)maxRows()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Poll the message pipe for async read messages
|
||||
|
||||
Only valid in async
|
||||
|
||||
@param orientation The direction to use when reading through the table.
|
||||
*/
|
||||
void IOAsyncReadBuffer::pollNextRow(char orientation)
|
||||
{
|
||||
DBUG_ASSERT(readIsAsync);
|
||||
|
||||
// Handle the case in which the buffer is full.
|
||||
if (rowCount() == maxRows())
|
||||
{
|
||||
// If we haven't read to the end, exit here.
|
||||
if (readCursor < rowCount())
|
||||
return;
|
||||
|
||||
if (pipeState == PendingFullBufferMsg)
|
||||
drainPipe();
|
||||
if (pipeState == ConsumedFullBufferMsg)
|
||||
loadNewRows(orientation);
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
PipeRpy_t* lastMsg = NULL;
|
||||
while (true)
|
||||
{
|
||||
PipeRpy_t msg[32];
|
||||
int bytes = read(msgPipe, msg, sizeof(msg));
|
||||
DBUG_PRINT("db2i_ioBuffers::pollNextRow",("Pipe returned %d bytes", bytes));
|
||||
|
||||
if (unlikely(bytes < 0))
|
||||
{
|
||||
DBUG_PRINT("db2i_ioBuffers::pollNextRow", ("Error"));
|
||||
rc = errno;
|
||||
break;
|
||||
}
|
||||
else if (bytes == 0)
|
||||
break;
|
||||
|
||||
DBUG_ASSERT(bytes % sizeof(msg[0]) == 0);
|
||||
lastMsg = &msg[bytes / (sizeof(msg[0]))-1];
|
||||
|
||||
if (lastMsg->RtnCod || (lastMsg->CumRowCnt == usedRows()))
|
||||
{
|
||||
rc = lastMsg->RtnCod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*releaseRowNeeded = true;
|
||||
|
||||
if (rc == QMY_ERR_END_OF_BLOCK)
|
||||
rc = 0;
|
||||
else if (rc == QMY_ERR_END_OF_FILE)
|
||||
{
|
||||
// If we reach EOF or end-of-key, DB2 guarantees that no rows will be locked.
|
||||
rc = HA_ERR_END_OF_FILE;
|
||||
*releaseRowNeeded = false;
|
||||
}
|
||||
else if (rc == QMY_ERR_KEY_NOT_FOUND)
|
||||
{
|
||||
rc = HA_ERR_KEY_NOT_FOUND;
|
||||
*releaseRowNeeded = false;
|
||||
}
|
||||
|
||||
if (lastMsg)
|
||||
DBUG_PRINT("db2i_ioBuffers::pollNextRow", ("Good data: rc=%d; rows=%d; usedRows=%d", lastMsg->RtnCod, lastMsg->CumRowCnt, (uint32)usedRows()));
|
||||
if (lastMsg && likely(!rc))
|
||||
{
|
||||
if (lastMsg->CumRowCnt < maxRows())
|
||||
pipeState = PendingFullBufferMsg;
|
||||
else
|
||||
pipeState = ConsumedFullBufferMsg;
|
||||
|
||||
DBUG_ASSERT(lastMsg->CumRowCnt <= usedRows());
|
||||
|
||||
}
|
||||
DBUG_ASSERT(rowCount() <= getRowCapacity());
|
||||
}
|
||||
DBUG_PRINT("db2i_ioBuffers::pollNextRow", ("filledRows: %d, rc: %d", rowCount(), rc));
|
||||
if (rc) closePipe();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Prepare for the destruction of the row buffer storage.
|
||||
*/
|
||||
void IOAsyncReadBuffer::prepForFree()
|
||||
{
|
||||
interruptRead();
|
||||
rewind();
|
||||
IORowBuffer::prepForFree();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Initialize the newly allocated storage.
|
||||
|
||||
@param sizeChanged Indicates whether the storage capacity is being changed.
|
||||
*/
|
||||
void IOAsyncReadBuffer::initAfterAllocate(bool sizeChanged)
|
||||
{
|
||||
rewind();
|
||||
|
||||
if (sizeChanged || ((void*)rrnList == NULL))
|
||||
rrnList.realloc(getRowCapacity() * sizeof(uint32));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Send an initial read request
|
||||
|
||||
@param infile The file (table/index) being read from
|
||||
@param orientation The orientation to use for this read request
|
||||
@param rowsToBuffer The number of rows to request each time
|
||||
@param useAsync Whether reads should be performed asynchronously.
|
||||
@param key The key to use (if any)
|
||||
@param keyLength The length of key (if any)
|
||||
@param keyParts The number of columns in the key (if any)
|
||||
|
||||
*/
|
||||
void IOAsyncReadBuffer::newReadRequest(FILE_HANDLE infile,
|
||||
char orientation,
|
||||
uint32 rowsToBuffer,
|
||||
bool useAsync,
|
||||
ILEMemHandle key,
|
||||
int keyLength,
|
||||
int keyParts)
|
||||
{
|
||||
DBUG_ENTER("db2i_ioBuffers::newReadRequest");
|
||||
DBUG_ASSERT(rowsToBuffer <= getRowCapacity());
|
||||
#ifndef DBUG_OFF
|
||||
if (readCursor < rowCount())
|
||||
DBUG_PRINT("PERF:",("Wasting %d buffered rows!\n", rowCount() - readCursor));
|
||||
#endif
|
||||
|
||||
int fildes[2];
|
||||
int ileDescriptor = QMY_REUSE;
|
||||
|
||||
interruptRead();
|
||||
|
||||
if (likely(useAsync))
|
||||
{
|
||||
if (rowsToBuffer == 1)
|
||||
{
|
||||
// Async provides little or no benefit for single row reads, so we turn it off
|
||||
DBUG_PRINT("db2i_ioBuffers::newReadRequest", ("Disabling async"));
|
||||
useAsync = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = pipe(fildes);
|
||||
if (rc) DBUG_VOID_RETURN;
|
||||
|
||||
// Translate the pipe write descriptor into the equivalent ILE descriptor
|
||||
rc = fstatx(fildes[1], (struct stat*)&ileDescriptor, sizeof(ileDescriptor), STX_XPFFD_PASE);
|
||||
if (rc)
|
||||
{
|
||||
close(fildes[0]);
|
||||
close(fildes[1]);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
pipeState = Untouched;
|
||||
msgPipe = fildes[0];
|
||||
|
||||
DBUG_PRINT("db2i_ioBuffers::newReadRequest", ("Opened pipe %d", fildes[0]));
|
||||
}
|
||||
}
|
||||
|
||||
file = infile;
|
||||
readIsAsync = useAsync;
|
||||
rowsToBlock = rowsToBuffer;
|
||||
|
||||
rewind();
|
||||
maxRows() = 1;
|
||||
rc = getBridge()->expectErrors(QMY_ERR_END_OF_BLOCK, QMY_ERR_LOB_SPACE_TOO_SMALL)
|
||||
->read(file,
|
||||
ptr(),
|
||||
accessIntent,
|
||||
commitLevel,
|
||||
orientation,
|
||||
useAsync,
|
||||
rrnList,
|
||||
key,
|
||||
keyLength,
|
||||
keyParts,
|
||||
ileDescriptor);
|
||||
|
||||
// Having shared the pipe with ILE, we relinquish our claim on the write end
|
||||
// of the pipe.
|
||||
if (useAsync)
|
||||
close(fildes[1]);
|
||||
|
||||
// If we reach EOF or end-of-key, DB2 guarantees that no rows will be locked.
|
||||
if (rc == QMY_ERR_END_OF_FILE)
|
||||
{
|
||||
rc = HA_ERR_END_OF_FILE;
|
||||
*releaseRowNeeded = false;
|
||||
}
|
||||
else if (rc == QMY_ERR_KEY_NOT_FOUND)
|
||||
{
|
||||
if (rowCount())
|
||||
rc = HA_ERR_END_OF_FILE;
|
||||
else
|
||||
rc = HA_ERR_KEY_NOT_FOUND;
|
||||
*releaseRowNeeded = false;
|
||||
}
|
||||
else
|
||||
*releaseRowNeeded = true;
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
@ -1,416 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
@file db2i_ioBuffers.h
|
||||
|
||||
@brief Buffer classes used for interacting with QMYSE read/write buffers.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "db2i_validatedPointer.h"
|
||||
#include "mysql_priv.h"
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <as400_types.h>
|
||||
|
||||
// Needed for compilers which do not include fstatx in standard headers.
|
||||
extern "C" int fstatx(int, struct stat *, int, int);
|
||||
|
||||
/**
|
||||
Basic row buffer
|
||||
|
||||
Provides the basic structure and methods needed for communicating
|
||||
with QMYSE I/O APIs.
|
||||
|
||||
@details All QMYSE I/O apis use a buffer that is structured as two integer
|
||||
row counts (max and used) and storage for some number of rows. The row counts
|
||||
are both input and output for the API, and their usage depends on the
|
||||
particular API invoked. This class encapsulates that buffer definition.
|
||||
*/
|
||||
class IORowBuffer
|
||||
{
|
||||
public:
|
||||
IORowBuffer() : allocSize(0), rowLength(0) {;}
|
||||
~IORowBuffer() { freeBuf(); }
|
||||
ValidatedPointer<char>& ptr() { return data; }
|
||||
|
||||
/**
|
||||
Sets up the buffer to hold the size indicated.
|
||||
|
||||
@param rowLen length of the rows that will be stored in this buffer
|
||||
@param nullMapOffset position of null map within each row
|
||||
@param size buffer size requested
|
||||
*/
|
||||
void allocBuf(uint32 rowLen, uint16 nullMapOffset, uint32 size)
|
||||
{
|
||||
nullOffset = nullMapOffset;
|
||||
uint32 newSize = size + sizeof(BufferHdr_t);
|
||||
// If the internal structure of the row is changing, we need to
|
||||
// remember this and notify the subclasses via initAfterAllocate();
|
||||
bool formatChanged = ((size/rowLen) != rowCapacity);
|
||||
|
||||
if (newSize > allocSize)
|
||||
{
|
||||
this->freeBuf();
|
||||
data.alloc(newSize);
|
||||
if (likely((void*)data))
|
||||
allocSize = newSize;
|
||||
}
|
||||
|
||||
if (likely((void*)data))
|
||||
{
|
||||
DBUG_ASSERT((uint64)(void*)data % 16 == 0);
|
||||
rowLength = rowLen;
|
||||
rowCapacity = size / rowLength;
|
||||
initAfterAllocate(formatChanged);
|
||||
}
|
||||
else
|
||||
{
|
||||
allocSize = 0;
|
||||
rowCapacity = 0;
|
||||
}
|
||||
|
||||
DBUG_PRINT("db2i_ioBuffers::allocBuf",("rowCapacity = %d", rowCapacity));
|
||||
}
|
||||
|
||||
void zeroBuf()
|
||||
{
|
||||
memset(data, 0, allocSize);
|
||||
}
|
||||
|
||||
void freeBuf()
|
||||
{
|
||||
if (likely(allocSize))
|
||||
{
|
||||
prepForFree();
|
||||
DBUG_PRINT("IORowBuffer::freeBuf",("Freeing 0x%p", (char*)data));
|
||||
data.dealloc();
|
||||
}
|
||||
}
|
||||
|
||||
char* getRowN(uint32 n)
|
||||
{
|
||||
if (unlikely(n >= getRowCapacity()))
|
||||
return NULL;
|
||||
return (char*)data + sizeof(BufferHdr_t) + (rowLength * n);
|
||||
};
|
||||
|
||||
uint32 getRowCapacity() const {return rowCapacity;}
|
||||
uint32 getRowNullOffset() const {return nullOffset;}
|
||||
uint32 getRowLength() const {return rowLength;}
|
||||
|
||||
protected:
|
||||
/**
|
||||
Called prior to freeing buffer storage so that subclasses can do
|
||||
any required cleanup
|
||||
*/
|
||||
virtual void prepForFree()
|
||||
{
|
||||
allocSize = 0;
|
||||
rowCapacity = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Called after buffer storage so that subclasses can do any required setup.
|
||||
*/
|
||||
virtual void initAfterAllocate(bool sizeChanged) { return;}
|
||||
|
||||
ValidatedPointer<char> data;
|
||||
uint32 allocSize;
|
||||
uint32 rowCapacity;
|
||||
uint32 rowLength;
|
||||
uint16 nullOffset;
|
||||
uint32& usedRows() const { return ((BufferHdr_t*)(char*)data)->UsedRowCnt; }
|
||||
uint32& maxRows() const {return ((BufferHdr_t*)(char*)data)->MaxRowCnt; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Write buffer
|
||||
|
||||
Implements methods for inserting data into a row buffer for use with the
|
||||
QMY_WRITE and QMY_UPDATE APIs.
|
||||
|
||||
@details The max row count defines how many rows are in the buffer. The used
|
||||
row count is updated by QMYSE to indicate how many rows have been
|
||||
successfully written.
|
||||
*/
|
||||
class IOWriteBuffer : public IORowBuffer
|
||||
{
|
||||
public:
|
||||
bool endOfBuffer() const {return (maxRows() == getRowCapacity());}
|
||||
|
||||
char* addRow()
|
||||
{
|
||||
return getRowN(maxRows()++);
|
||||
}
|
||||
|
||||
void resetAfterWrite()
|
||||
{
|
||||
maxRows() = 0;
|
||||
}
|
||||
|
||||
void deleteRow()
|
||||
{
|
||||
--maxRows();
|
||||
}
|
||||
|
||||
uint32 rowCount() const {return maxRows();}
|
||||
|
||||
uint32 rowsWritten() const {return usedRows()-1;}
|
||||
|
||||
private:
|
||||
void initAfterAllocate(bool sizeChanged) {maxRows() = 0; usedRows() = 0;}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Read buffer
|
||||
|
||||
Implements methods for reading data from and managing a row buffer for use
|
||||
with the QMY_READ APIs. This is primarily for use with metainformation queries.
|
||||
*/
|
||||
class IOReadBuffer : public IORowBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
IOReadBuffer() {;}
|
||||
IOReadBuffer(uint32 rows, uint32 rowLength)
|
||||
{
|
||||
allocBuf(rows, 0, rows * rowLength);
|
||||
maxRows() = rows;
|
||||
}
|
||||
|
||||
uint32 rowCount() {return usedRows();}
|
||||
void setRowsToProcess(uint32 rows) { maxRows() = rows; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
Read buffer
|
||||
|
||||
Implements methods for reading data from and managing a row buffer for use
|
||||
with the QMY_READ APIs.
|
||||
|
||||
@details This class supports both sync and async read modes. The max row
|
||||
count defines the number of rows that are requested to be read. The used row
|
||||
count defines how many rows have been read. Sync mode is reasonably
|
||||
straightforward, but async mode has a complex system of communicating with
|
||||
QMYSE that is optimized for low latency. In async mode, the used row count is
|
||||
updated continuously by QMYSE as rows are read. At the same time, messages are
|
||||
sent to the associated pipe indicating that a row has been read. As long as
|
||||
the internal read cursor lags behind the used row count, the pipe is never
|
||||
consulted. But if the internal read cursor "catches up to" the used row count,
|
||||
then we block on the pipe until we find a message indicating that a new row
|
||||
has been read or that an error has occurred.
|
||||
*/
|
||||
class IOAsyncReadBuffer : public IOReadBuffer
|
||||
{
|
||||
public:
|
||||
IOAsyncReadBuffer() :
|
||||
file(0), readIsAsync(false), msgPipe(QMY_REUSE), bridge(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~IOAsyncReadBuffer()
|
||||
{
|
||||
interruptRead();
|
||||
rrnList.dealloc();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Signal read operation complete
|
||||
|
||||
Indicates that the storage engine requires no more data from the table.
|
||||
Must be called between calls to newReadRequest().
|
||||
*/
|
||||
void endRead()
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
if (readCursor < rowCount())
|
||||
DBUG_PRINT("PERF:",("Wasting %d buffered rows!\n", rowCount() - readCursor));
|
||||
#endif
|
||||
interruptRead();
|
||||
|
||||
file = 0;
|
||||
bridge = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Update data that may change on each read operation
|
||||
*/
|
||||
void update(char newAccessIntent,
|
||||
bool* newReleaseRowNeeded,
|
||||
char commitLvl)
|
||||
{
|
||||
accessIntent = newAccessIntent;
|
||||
releaseRowNeeded = newReleaseRowNeeded;
|
||||
commitLevel = commitLvl;
|
||||
}
|
||||
|
||||
/**
|
||||
Read the next row in the table.
|
||||
|
||||
Return a pointer to the next row in the table, where "next" is defined
|
||||
by the orientation.
|
||||
|
||||
@param orientaton
|
||||
@param[out] rrn The relative record number of the row returned. Not reliable
|
||||
if NULL is returned by this function.
|
||||
|
||||
@return Pointer to the row. Null if no more rows are available or an error
|
||||
occurred.
|
||||
*/
|
||||
char* readNextRow(char orientation, uint32& rrn)
|
||||
{
|
||||
DBUG_PRINT("db2i_ioBuffers::readNextRow", ("readCursor: %d, filledRows: %d, rc: %d", readCursor, rowCount(), rc));
|
||||
|
||||
while (readCursor >= rowCount() && !rc)
|
||||
{
|
||||
if (!readIsAsync)
|
||||
loadNewRows(orientation);
|
||||
else
|
||||
pollNextRow(orientation);
|
||||
}
|
||||
|
||||
if (readCursor >= rowCount())
|
||||
return NULL;
|
||||
|
||||
rrn = rrnList[readCursor];
|
||||
return getRowN(readCursor++);
|
||||
}
|
||||
|
||||
/**
|
||||
Retrieve the return code generated by the last operation.
|
||||
|
||||
@return The return code, translated to the appropriate HA_ERR_*
|
||||
value if possible.
|
||||
*/
|
||||
int32 lastrc()
|
||||
{
|
||||
return db2i_ileBridge::translateErrorCode(rc);
|
||||
}
|
||||
|
||||
void rewind()
|
||||
{
|
||||
readCursor = 0;
|
||||
rc = 0;
|
||||
usedRows() = 0;
|
||||
}
|
||||
|
||||
bool reachedEOD() { return EOD; }
|
||||
|
||||
void newReadRequest(FILE_HANDLE infile,
|
||||
char orientation,
|
||||
uint32 rowsToBuffer,
|
||||
bool useAsync,
|
||||
ILEMemHandle key,
|
||||
int keyLength,
|
||||
int keyParts);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
End any running async read operation.
|
||||
*/
|
||||
void interruptRead()
|
||||
{
|
||||
closePipe();
|
||||
if (file && readIsAsync && (rc == 0) && (rowCount() < getRowCapacity()))
|
||||
{
|
||||
DBUG_PRINT("IOReadBuffer::interruptRead", ("PERF: Interrupting %d", (uint32)file));
|
||||
getBridge()->readInterrupt(file);
|
||||
}
|
||||
}
|
||||
|
||||
void closePipe()
|
||||
{
|
||||
if (msgPipe != QMY_REUSE)
|
||||
{
|
||||
DBUG_PRINT("db2i_ioBuffers::closePipe", ("Closing pipe %d", msgPipe));
|
||||
close(msgPipe);
|
||||
msgPipe = QMY_REUSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Get a pointer to the active ILE bridge.
|
||||
|
||||
Getting the bridge pointer is (relatively) expensive, so we cache
|
||||
it off for each operation.
|
||||
*/
|
||||
db2i_ileBridge* getBridge()
|
||||
{
|
||||
if (unlikely(bridge == NULL))
|
||||
{
|
||||
bridge = db2i_ileBridge::getBridgeForThread();
|
||||
}
|
||||
return bridge;
|
||||
}
|
||||
|
||||
void drainPipe();
|
||||
void pollNextRow(char orientation);
|
||||
void prepForFree();
|
||||
void initAfterAllocate(bool sizeChanged);
|
||||
void loadNewRows(char orientation);
|
||||
|
||||
|
||||
uint32 readCursor; // Read position within buffer
|
||||
int32 rc; // Last return code received
|
||||
ValidatedPointer<uint32> rrnList; // Receiver for list of rrns
|
||||
char accessIntent; // The access intent for this read
|
||||
char commitLevel; // What isolation level should be used
|
||||
char EOD; // Whether end-of-data was hit
|
||||
char readIsAsync; // Are reads to be done asynchronously?
|
||||
bool* releaseRowNeeded;
|
||||
/* Does the caller need to release the current row when finished reading */
|
||||
FILE_HANDLE file; // The file to be read
|
||||
int msgPipe;
|
||||
/* The read descriptor of the pipe used to pass messages during async reads */
|
||||
db2i_ileBridge* bridge; // Cached pointer to bridge
|
||||
uint32 rowsToBlock; // Number of rows to request
|
||||
enum
|
||||
{
|
||||
ConsumedFullBufferMsg,
|
||||
PendingFullBufferMsg,
|
||||
Untouched
|
||||
} pipeState;
|
||||
/* The state of the async read message pipe */
|
||||
};
|
||||
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DB2I_MISC_H
|
||||
#define DB2I_MISC_H
|
||||
|
||||
/**
|
||||
Undelimit quote-delimited DB2 names in-place
|
||||
*/
|
||||
void stripExtraQuotes(char* name, uint maxLen)
|
||||
{
|
||||
char* oldName = (char*)sql_strdup(name);
|
||||
uint i = 0;
|
||||
uint j = 0;
|
||||
do
|
||||
{
|
||||
name[j] = oldName[i];
|
||||
if (oldName[i] == '"' && oldName[i+1] == '"')
|
||||
++i;
|
||||
} while (++j < maxLen && oldName[++i]);
|
||||
|
||||
if (j == maxLen)
|
||||
--j;
|
||||
name[j] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert a MySQL identifier name into a DB2 compatible format
|
||||
|
||||
@parm input The MySQL name
|
||||
@parm output The DB2 name
|
||||
@parm outlen The amount of space allocated for output
|
||||
@parm delimit Should delimiting quotes be placed around the converted name?
|
||||
@parm delimitQuotes Should quotes in the MySQL be delimited with additional quotes?
|
||||
|
||||
@return FALSE if output was too small and name was truncated; TRUE otherwise
|
||||
*/
|
||||
bool convertMySQLNameToDB2Name(const char* input,
|
||||
char* output,
|
||||
size_t outlen,
|
||||
bool delimit = true,
|
||||
bool delimitQuotes = true)
|
||||
{
|
||||
uint o = 0;
|
||||
if (delimit)
|
||||
output[o++] = '"';
|
||||
|
||||
uint i = 0;
|
||||
do
|
||||
{
|
||||
output[o] = input[i];
|
||||
if (delimitQuotes && input[i] == '"')
|
||||
output[++o] = '"';
|
||||
} while (++o < outlen-2 && input[++i]);
|
||||
|
||||
if (delimit)
|
||||
output[o++] = '"';
|
||||
output[min(o, outlen-1)] = 0; // This isn't the most user-friendly way to handle overflows,
|
||||
// but at least its safe.
|
||||
return (o <= outlen-1);
|
||||
}
|
||||
|
||||
bool isOrdinaryIdentifier(const char* s)
|
||||
{
|
||||
while (*s)
|
||||
{
|
||||
if (my_isupper(system_charset_info, *s) ||
|
||||
my_isdigit(system_charset_info, *s) ||
|
||||
(*s == '_') ||
|
||||
(*s == '@') ||
|
||||
(*s == '$') ||
|
||||
(*s == '#') ||
|
||||
(*s == '"'))
|
||||
++s;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Fill memory with a 16-bit word.
|
||||
|
||||
@param p Pointer to space to fill.
|
||||
@param v Value to fill
|
||||
@param l Length of space (in 16-bit words)
|
||||
*/
|
||||
void memset16(void* p, uint16 v, size_t l)
|
||||
{
|
||||
uint16* p2=(uint16*)p;
|
||||
while (l--)
|
||||
{
|
||||
*(p2++) = v;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,686 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "ha_ibmdb2i.h"
|
||||
|
||||
/* Helper function for records_in_range.
|
||||
Input: Bitmap of used key parts.
|
||||
Output: Number of used key parts. */
|
||||
|
||||
static inline int getKeyCntFromMap(key_part_map keypart_map)
|
||||
{
|
||||
int cnt = 0;
|
||||
while (keypart_map)
|
||||
{
|
||||
keypart_map = keypart_map >> 1;
|
||||
cnt++;
|
||||
}
|
||||
return (cnt);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief
|
||||
Given a starting key and an ending key, estimate the number of rows that
|
||||
will exist between the two keys.
|
||||
|
||||
INPUT
|
||||
inx Index to use
|
||||
min_key Min key. Is NULL if no min range
|
||||
max_key Max key. Is NULL if no max range
|
||||
|
||||
NOTES
|
||||
min_key.flag can have one of the following values:
|
||||
HA_READ_KEY_EXACT Include the key in the range
|
||||
HA_READ_AFTER_KEY Don't include key in range
|
||||
|
||||
max_key.flag can have one of the following values:
|
||||
HA_READ_BEFORE_KEY Don't include key in range
|
||||
HA_READ_AFTER_KEY Include all 'end_key' values in the range
|
||||
|
||||
RETURN
|
||||
HA_POS_ERROR Error or the storage engine cannot estimate the number of rows
|
||||
1 There are no matching keys in the given range
|
||||
n > 0 There are approximately n rows in the range
|
||||
*/
|
||||
ha_rows ha_ibmdb2i::records_in_range(uint inx,
|
||||
key_range *min_key,
|
||||
key_range *max_key)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::records_in_range");
|
||||
int rc = 0; // Return code
|
||||
ha_rows rows = 0; // Row count returned to caller of this method
|
||||
uint32 spcLen; // Length of space passed to DB2
|
||||
uint32 keyCnt; // Number of fields in the key composite
|
||||
uint32 literalCnt = 0; // Number of literals
|
||||
uint32 boundsOff; // Offset from beginning of space to range bounds
|
||||
uint32 litDefOff; // Offset from beginning of space to literal definitions
|
||||
uint32 literalsOff; // Offset from beginning of space to literal values
|
||||
uint32 cutoff = 0; // Early exit cutoff (currently not used)
|
||||
uint64 recCnt; // Row count from DB2
|
||||
uint16 rtnCode; // Return code from DB2
|
||||
Bounds* boundsPtr; // Pointer to a pair of range bounds
|
||||
Bound* boundPtr; // Pointer to a single (high or low) range bound
|
||||
LitDef* litDefPtr; // Pointer to a literal definition
|
||||
char* literalsPtr; // Pointer to the start of all literal values
|
||||
char* literalPtr; // Pointer to the start of this literal value
|
||||
char* tempPtr; // Temporary pointer
|
||||
char* tempMinPtr; // Temporary pointer into min_key
|
||||
int minKeyCnt = 0; // Number of fields in the min_key composite
|
||||
int maxKeyCnt = 0; // Number of fields in the max_key composite
|
||||
size_t tempLen = 0; // Temporary length
|
||||
uint16 DB2FieldWidth = 0; // DB2 field width
|
||||
uint32 workFieldLen = 0; // Length of workarea needed for CCSID conversions
|
||||
bool overrideInclusion; // Indicator for inclusion/exclusion
|
||||
char* endOfLiteralPtr; // Pointer to the end of this literal
|
||||
char* endOfMinPtr; // Pointer to end of min_key
|
||||
uint16 endByte = 0; // End byte of char or graphic literal (padding not included)
|
||||
bool reuseLiteral; // Indicator that hi and lo bounds use same literal
|
||||
char* minPtr = NULL; // Work pointer for traversing min_key
|
||||
char* maxPtr = NULL; // Work pointer for traversing max_key
|
||||
/*
|
||||
Handle the special case of 'x < null' anywhere in the key range. There are
|
||||
no values less than null, but return 1 so that MySQL does not assume
|
||||
the empty set for the query.
|
||||
*/
|
||||
if (min_key != NULL && max_key != NULL &&
|
||||
min_key->flag == HA_READ_AFTER_KEY && max_key->flag == HA_READ_BEFORE_KEY &&
|
||||
min_key->length == max_key->length &&
|
||||
(memcmp((uchar*)min_key->key,(uchar*)max_key->key,min_key->length)==0))
|
||||
{
|
||||
DBUG_PRINT("ha_ibmdb2i::records_in_range",("Estimate 1 row for key %d; special case: < null", inx));
|
||||
DBUG_RETURN((ha_rows) 1 );
|
||||
}
|
||||
/*
|
||||
Determine the number of fields in the key composite.
|
||||
*/
|
||||
|
||||
if (min_key)
|
||||
{
|
||||
minKeyCnt = getKeyCntFromMap(min_key->keypart_map);
|
||||
minPtr = (char*)min_key->key;
|
||||
}
|
||||
if (max_key)
|
||||
{
|
||||
maxKeyCnt = getKeyCntFromMap(max_key->keypart_map);
|
||||
maxPtr = (char*)max_key->key;
|
||||
}
|
||||
keyCnt = maxKeyCnt >= minKeyCnt ? maxKeyCnt : minKeyCnt;
|
||||
|
||||
/*
|
||||
Handle the special case where MySQL does not pass either a min or max
|
||||
key range. In this case, set the key count to 1 (knowing that there
|
||||
is at least one key field) to flow through and create one bounds structure.
|
||||
When both the min and max key ranges are nil, the bounds structure will
|
||||
specify positive and negative infinity and DB2 will estimate the total
|
||||
number of rows. */
|
||||
|
||||
if (keyCnt == 0)
|
||||
keyCnt = 1;
|
||||
|
||||
/*
|
||||
Allocate the space needed to pass range information to DB2. The
|
||||
space must be large enough to store the following:
|
||||
- one pair of bounds (high and low) per field in the key composite
|
||||
- one literal definition per literal value
|
||||
- the literal values
|
||||
- work area for literal CCSID conversions
|
||||
Since we don't know yet how many of these structures are needed,
|
||||
allocate enough space for the maximum that we will possibly need.
|
||||
The workarea for the literal conversion must be big enough to hold the
|
||||
largest of the DB2 key fields.
|
||||
*/
|
||||
KEY& curKey = table->key_info[inx];
|
||||
|
||||
for (int i = 0; i < keyCnt; i++)
|
||||
{
|
||||
DB2FieldWidth =
|
||||
db2Table->db2Field(curKey.key_part[i].field->field_index).getByteLengthInRecord();
|
||||
if (DB2FieldWidth > workFieldLen)
|
||||
workFieldLen = DB2FieldWidth; // Get length of largest DB2 field
|
||||
tempLen = tempLen + DB2FieldWidth; // Tally the DB2 field lengths
|
||||
}
|
||||
spcLen = (sizeof(Bounds)*keyCnt) + (sizeof(LitDef)*keyCnt*2) + (tempLen*2) + workFieldLen;
|
||||
|
||||
ValidatedPointer<char> spcPtr(spcLen); // Pointer to space passed to DB2
|
||||
memset(spcPtr, 0, spcLen); // Clear the allocated space
|
||||
/*
|
||||
Set addressability to the various sections of the DB2 interface space.
|
||||
*/
|
||||
boundsOff = 0; // Range bounds are at the start of the space
|
||||
litDefOff = sizeof(Bounds) * keyCnt; // Literal defs follow all the range bounds
|
||||
literalsOff = litDefOff + (sizeof(LitDef) * keyCnt * 2); // Literal values are last
|
||||
boundsPtr = (Bounds_t*)(void*)spcPtr; // Address first bounds structure
|
||||
tempPtr = (char*)((char*)spcPtr + litDefOff);
|
||||
litDefPtr = (LitDef_t*)tempPtr; // Address first literal definition
|
||||
tempPtr = (char*)((char*)spcPtr + literalsOff);
|
||||
literalsPtr = (char*)tempPtr; // Address start of literal values
|
||||
literalPtr = literalsPtr; // Address first literal value
|
||||
/*
|
||||
For each key part, build the low (min) and high (max) DB2 range bounds.
|
||||
If literals are specified in the MySQL range, build DB2 literal
|
||||
definitions and store the literal values for access by DB2.
|
||||
|
||||
If no value is specified for a key part, assume infinity. Negative
|
||||
infinity will cause processing to start at the first index entry.
|
||||
Positive infinity will cause processing to end at the last index entry.
|
||||
When infinity is specified in a bound, inclusion/exclusion and position
|
||||
are ignored, and there is no literal definition or literal value for
|
||||
the bound.
|
||||
|
||||
If the keypart value is null, the null indicator is set in the range
|
||||
bound and the other fields in the bound are ignored. When the bound is
|
||||
null, only index entries with the null value will be included in the
|
||||
estimate. If one bound is null, both bounds must be null. When the bound
|
||||
is not null, the data offset and length must be set, and the literal
|
||||
value stored for access by DB2.
|
||||
*/
|
||||
for (int partsInUse = 0; partsInUse < keyCnt; ++partsInUse)
|
||||
{
|
||||
Field *field= curKey.key_part[partsInUse].field;
|
||||
overrideInclusion = false;
|
||||
reuseLiteral = false;
|
||||
endOfLiteralPtr = NULL;
|
||||
/*
|
||||
Build the low bound for the key range.
|
||||
*/
|
||||
if ((partsInUse + 1) > minKeyCnt) // if no min_key info for this part
|
||||
boundsPtr->LoBound.Infinity[0] = QMY_NEG_INFINITY; // select...where 3 between x and y
|
||||
else
|
||||
{
|
||||
if ((curKey.key_part[partsInUse].null_bit) && (char*)minPtr[0])
|
||||
{ // min_key is null
|
||||
if (max_key == NULL ||
|
||||
((partsInUse + 1) > maxKeyCnt)) // select...where x='ab' and y=null and z != 'c'
|
||||
boundsPtr->LoBound.Infinity[0] = QMY_NEG_INFINITY; // select...where x not null or
|
||||
// select...where x > null
|
||||
else // max_key is not null
|
||||
{
|
||||
if (min_key->flag == HA_READ_KEY_EXACT)
|
||||
boundsPtr->LoBound.IsNull[0] = QMY_YES; // select...where x is null
|
||||
else
|
||||
{
|
||||
if ((char*)maxPtr[0])
|
||||
boundsPtr->LoBound.IsNull[0] = QMY_YES; // select...where a = null and b < 5 (max-before)
|
||||
// select...where a='a' and b is null and c !='a' (max-after)
|
||||
else
|
||||
boundsPtr->LoBound.Infinity[0] = QMY_NEG_INFINITY; // select...where x < y
|
||||
}
|
||||
} // end min_key is null
|
||||
}
|
||||
else // min_key is not null
|
||||
{
|
||||
if (literalCnt) litDefPtr = litDefPtr + 1;
|
||||
literalCnt = literalCnt + 1;
|
||||
boundsPtr->LoBound.Position = literalCnt;
|
||||
/*
|
||||
Determine inclusion or exclusion.
|
||||
*/
|
||||
if (min_key->flag == HA_READ_KEY_EXACT || //select...where a like 'this%'
|
||||
|
||||
/* An example for the following conditions is 'select...where a = 5 and b > null'. */
|
||||
|
||||
(max_key &&
|
||||
(memcmp((uchar*)minPtr,(uchar*)maxPtr,
|
||||
curKey.key_part[partsInUse].store_length)==0)))
|
||||
|
||||
{
|
||||
if ((min_key->flag != HA_READ_KEY_EXACT) ||
|
||||
(max_key &&
|
||||
(memcmp((uchar*)minPtr,(uchar*)maxPtr,
|
||||
curKey.key_part[partsInUse].store_length)==0)))
|
||||
overrideInclusion = true; // Need inclusion for both min and max
|
||||
}
|
||||
else
|
||||
boundsPtr->LoBound.Embodiment[0] = QMY_EXCLUSION;
|
||||
litDefPtr->FieldNbr = field->field_index + 1;
|
||||
DB2Field& db2Field = db2Table->db2Field(field->field_index);
|
||||
litDefPtr->DataType = db2Field.getType();
|
||||
/*
|
||||
Convert the literal to DB2 format
|
||||
*/
|
||||
if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
|
||||
(field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
|
||||
(litDefPtr->DataType == QMY_CHAR ||
|
||||
litDefPtr->DataType == QMY_VARCHAR ||
|
||||
litDefPtr->DataType == QMY_GRAPHIC ||
|
||||
litDefPtr->DataType == QMY_VARGRAPHIC))
|
||||
{
|
||||
// Most of the code is required by the considerable wrangling needed
|
||||
// to prepare partial keys for use by DB2
|
||||
// 1. UTF8 (CCSID 1208) data can be copied across unmodified if it is
|
||||
// utf8_bin. Otherwise, we need to convert the min and max
|
||||
// characters into the min and max characters employed
|
||||
// by the DB2 sort sequence. This is complicated by the fact that
|
||||
// the character widths are not always equal.
|
||||
// 2. Likewise, UCS2 (CCSID 13488) data can be copied across unmodified
|
||||
// if it is ucs2_bin or ucs2_general_ci. Otherwise, we need to
|
||||
// convert the min and max characters into the min and max characters
|
||||
// employed by the DB2 sort sequence.
|
||||
// 3. All other data will use standard iconv conversions. If an
|
||||
// unconvertible character is encountered, we assume it is the min
|
||||
// char and fill the remainder of the DB2 key with 0s. This may not
|
||||
// always be accurate, but it is probably sufficient for range
|
||||
// estimations.
|
||||
const char* keyData = minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
|
||||
char* db2Data = literalPtr;
|
||||
uint16 outLen = db2Field.getByteLengthInRecord();
|
||||
uint16 inLen;
|
||||
if (litDefPtr->DataType == QMY_VARCHAR ||
|
||||
litDefPtr->DataType == QMY_VARGRAPHIC)
|
||||
{
|
||||
inLen = *(uint8*)keyData + ((*(uint8*)(keyData+1)) << 8);
|
||||
keyData += 2;
|
||||
outLen -= sizeof(uint16);
|
||||
db2Data += sizeof(uint16);
|
||||
}
|
||||
else
|
||||
{
|
||||
inLen = field->max_display_length();
|
||||
}
|
||||
|
||||
size_t convertedBytes = 0;
|
||||
if (db2Field.getCCSID() == 1208)
|
||||
{
|
||||
DBUG_ASSERT(inLen <= outLen);
|
||||
if (strcmp(field->charset()->name, "utf8_bin"))
|
||||
{
|
||||
const char* end = keyData+inLen;
|
||||
const char* curKey = keyData;
|
||||
char* curDB2 = db2Data;
|
||||
uint32 min = field->charset()->min_sort_char;
|
||||
while ((curKey < end) && (curDB2 < db2Data+outLen-3))
|
||||
{
|
||||
my_wc_t temp;
|
||||
int len = field->charset()->cset->mb_wc(field->charset(),
|
||||
&temp,
|
||||
(const uchar*)curKey,
|
||||
(const uchar*)end);
|
||||
if (temp != min)
|
||||
{
|
||||
DBUG_ASSERT(len <= 3);
|
||||
switch (len)
|
||||
{
|
||||
case 3: *(curDB2+2) = *(curKey+2);
|
||||
case 2: *(curDB2+1) = *(curKey+1);
|
||||
case 1: *(curDB2) = *(curKey);
|
||||
}
|
||||
curDB2 += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(curDB2++) = 0xEF;
|
||||
*(curDB2++) = 0xBF;
|
||||
*(curDB2++) = 0xBF;
|
||||
}
|
||||
curKey += len;
|
||||
}
|
||||
convertedBytes = curDB2 - db2Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(db2Data, keyData, inLen);
|
||||
convertedBytes = inLen;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
else if (db2Field.getCCSID() == 13488)
|
||||
{
|
||||
DBUG_ASSERT(inLen <= outLen);
|
||||
if (strcmp(field->charset()->name, "ucs2_bin") &&
|
||||
strcmp(field->charset()->name, "ucs2_general_ci"))
|
||||
{
|
||||
const char* end = keyData+inLen;
|
||||
const uint16* curKey = (uint16*)keyData;
|
||||
uint16* curDB2 = (uint16*)db2Data;
|
||||
uint16 min = field->charset()->min_sort_char;
|
||||
while (curKey < (uint16*)end)
|
||||
{
|
||||
if (*curKey != min)
|
||||
*curDB2 = *curKey;
|
||||
else
|
||||
*curDB2 = 0xFFFF;
|
||||
++curKey;
|
||||
++curDB2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(db2Data, keyData, inLen);
|
||||
}
|
||||
convertedBytes = inLen;
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = convertFieldChars(toDB2,
|
||||
field->field_index,
|
||||
keyData,
|
||||
db2Data,
|
||||
inLen,
|
||||
outLen,
|
||||
&convertedBytes,
|
||||
true);
|
||||
|
||||
if (rc == DB2I_ERR_ILL_CHAR)
|
||||
{
|
||||
// If an illegal character is encountered, we fill the remainder
|
||||
// of the key with 0x00. This was implemented as a corollary to
|
||||
// Bug#45012, though it should probably remain even after that
|
||||
// bug is fixed.
|
||||
memset(db2Data+convertedBytes, 0x00, outLen-convertedBytes);
|
||||
convertedBytes = outLen;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rc &&
|
||||
(litDefPtr->DataType == QMY_VARGRAPHIC ||
|
||||
litDefPtr->DataType == QMY_VARCHAR))
|
||||
{
|
||||
*(uint16*)(db2Data-sizeof(uint16)) =
|
||||
convertedBytes / (litDefPtr->DataType == QMY_VARGRAPHIC ? 2 : 1);
|
||||
}
|
||||
|
||||
}
|
||||
else // Non-character fields
|
||||
{
|
||||
rc = convertMySQLtoDB2(field,
|
||||
db2Field,
|
||||
literalPtr,
|
||||
(uchar*)minPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
|
||||
}
|
||||
|
||||
if (rc != 0) break;
|
||||
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
|
||||
litDefPtr->Length = db2Field.getByteLengthInRecord();
|
||||
literalPtr = literalPtr + litDefPtr->Length; // Bump pointer for next literal
|
||||
}
|
||||
/* If there is a max_key value for this field, and if the max_key value is
|
||||
the same as the min_key value, then the low bound literal can be reused
|
||||
for the high bound literal. This eliminates the overhead of copying and
|
||||
converting the same value twice. */
|
||||
if (max_key && ((partsInUse + 1) <= maxKeyCnt) &&
|
||||
(memcmp((uchar*)minPtr,(uchar*)maxPtr,
|
||||
curKey.key_part[partsInUse].store_length)==0 || endOfLiteralPtr))
|
||||
reuseLiteral = true;
|
||||
minPtr += curKey.key_part[partsInUse].store_length;
|
||||
}
|
||||
/*
|
||||
Build the high bound for the key range.
|
||||
*/
|
||||
if (max_key == NULL || ((partsInUse + 1) > maxKeyCnt))
|
||||
boundsPtr->HiBound.Infinity[0] = QMY_POS_INFINITY;
|
||||
else
|
||||
{
|
||||
if ((curKey.key_part[partsInUse].null_bit) && (char*)maxPtr[0])
|
||||
{
|
||||
if (min_key == NULL)
|
||||
boundsPtr->HiBound.Infinity[0] = QMY_POS_INFINITY;
|
||||
else
|
||||
boundsPtr->HiBound.IsNull[0] = QMY_YES; // select...where x is null
|
||||
}
|
||||
else // max_key field is not null
|
||||
{
|
||||
if (boundsPtr->LoBound.IsNull[0] == QMY_YES) // select where x < 10 or x is null
|
||||
{
|
||||
rc = HA_POS_ERROR;
|
||||
break;
|
||||
}
|
||||
if (!reuseLiteral)
|
||||
{
|
||||
if (literalCnt)
|
||||
litDefPtr = litDefPtr + 1;
|
||||
literalCnt = literalCnt + 1;
|
||||
litDefPtr->FieldNbr = field->field_index + 1;
|
||||
DB2Field& db2Field = db2Table->db2Field(field->field_index);
|
||||
litDefPtr->DataType = db2Field.getType();
|
||||
/*
|
||||
Convert the literal to DB2 format
|
||||
*/
|
||||
if ((field->type() != MYSQL_TYPE_BIT) && // Don't do conversion on BIT data
|
||||
(field->charset() != &my_charset_bin) && // Don't do conversion on BINARY data
|
||||
(litDefPtr->DataType == QMY_CHAR ||
|
||||
litDefPtr->DataType == QMY_VARCHAR ||
|
||||
litDefPtr->DataType == QMY_GRAPHIC ||
|
||||
litDefPtr->DataType == QMY_VARGRAPHIC))
|
||||
{
|
||||
// We need to handle char fields in a special way in order to account
|
||||
// for partial keys. Refer to the note above for a description of the
|
||||
// basic design.
|
||||
char* keyData = maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0);
|
||||
char* db2Data = literalPtr;
|
||||
uint16 outLen = db2Field.getByteLengthInRecord();
|
||||
uint16 inLen;
|
||||
if (litDefPtr->DataType == QMY_VARCHAR ||
|
||||
litDefPtr->DataType == QMY_VARGRAPHIC)
|
||||
{
|
||||
inLen = *(uint8*)keyData + ((*(uint8*)(keyData+1)) << 8);
|
||||
keyData += 2;
|
||||
outLen -= sizeof(uint16);
|
||||
db2Data += sizeof(uint16);
|
||||
}
|
||||
else
|
||||
{
|
||||
inLen = field->max_display_length();
|
||||
}
|
||||
|
||||
size_t convertedBytes;
|
||||
if (db2Field.getCCSID() == 1208)
|
||||
{
|
||||
if (strcmp(field->charset()->name, "utf8_bin"))
|
||||
{
|
||||
const char* end = keyData+inLen;
|
||||
const char* curKey = keyData;
|
||||
char* curDB2 = db2Data;
|
||||
uint32 max = field->charset()->max_sort_char;
|
||||
while (curKey < end && (curDB2 < db2Data+outLen-3))
|
||||
{
|
||||
my_wc_t temp;
|
||||
int len = field->charset()->cset->mb_wc(field->charset(), &temp, (const uchar*)curKey, (const uchar*)end);
|
||||
if (temp != max)
|
||||
{
|
||||
DBUG_ASSERT(len <= 3);
|
||||
switch (len)
|
||||
{
|
||||
case 3: *(curDB2+2) = *(curKey+2);
|
||||
case 2: *(curDB2+1) = *(curKey+1);
|
||||
case 1: *(curDB2) = *(curKey);
|
||||
}
|
||||
curDB2 += len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(curDB2++) = 0xE4;
|
||||
*(curDB2++) = 0xB6;
|
||||
*(curDB2++) = 0xBF;
|
||||
}
|
||||
curKey += len;
|
||||
}
|
||||
convertedBytes = curDB2 - db2Data;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(inLen <= outLen);
|
||||
memcpy(db2Data, keyData, inLen);
|
||||
convertedBytes = inLen;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
else if (db2Field.getCCSID() == 13488)
|
||||
{
|
||||
if (strcmp(field->charset()->name, "ucs2_bin") &&
|
||||
strcmp(field->charset()->name, "ucs2_general_ci"))
|
||||
{
|
||||
char* end = keyData+inLen;
|
||||
uint16* curKey = (uint16*)keyData;
|
||||
uint16* curDB2 = (uint16*)db2Data;
|
||||
uint16 max = field->charset()->max_sort_char;
|
||||
while (curKey < (uint16*)end)
|
||||
{
|
||||
if (*curKey != max)
|
||||
*curDB2 = *curKey;
|
||||
else
|
||||
*curDB2 = 0x4DBF;
|
||||
++curKey;
|
||||
++curDB2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(db2Data, keyData, outLen);
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t substituteChars = 0;
|
||||
rc = convertFieldChars(toDB2,
|
||||
field->field_index,
|
||||
keyData,
|
||||
db2Data,
|
||||
inLen,
|
||||
outLen,
|
||||
&convertedBytes,
|
||||
true,
|
||||
&substituteChars);
|
||||
|
||||
if (rc == DB2I_ERR_ILL_CHAR)
|
||||
{
|
||||
// If an illegal character is encountered, we fill the remainder
|
||||
// of the key with 0xFF. This was implemented to work around
|
||||
// Bug#45012, though it should probably remain even after that
|
||||
// bug is fixed.
|
||||
memset(db2Data+convertedBytes, 0xFF, outLen-convertedBytes);
|
||||
rc = 0;
|
||||
}
|
||||
else if ((substituteChars &&
|
||||
(litDefPtr->DataType == QMY_VARCHAR ||
|
||||
litDefPtr->DataType == QMY_CHAR)) ||
|
||||
strcmp(field->charset()->name, "cp1251_bulgarian_ci") == 0)
|
||||
{
|
||||
// When iconv translates the max_sort_char with a substitute
|
||||
// character, we have no way to know whether this affects
|
||||
// the sort order of the key. Therefore, to be safe, when
|
||||
// we know that substitute characters have been used in a
|
||||
// single-byte string, we traverse the translated key
|
||||
// in reverse, replacing substitue characters with 0xFF, which
|
||||
// always sorts with the greatest weight in DB2 sort sequences.
|
||||
// cp1251_bulgarian_ci is also handled this way because the
|
||||
// max_sort_char is a control character which does not sort
|
||||
// equivalently in DB2.
|
||||
DBUG_ASSERT(inLen == outLen);
|
||||
char* tmpKey = keyData + inLen - 1;
|
||||
char* tmpDB2 = db2Data + outLen - 1;
|
||||
while (*tmpKey == field->charset()->max_sort_char &&
|
||||
*tmpDB2 != 0xFF)
|
||||
{
|
||||
*tmpDB2 = 0xFF;
|
||||
--tmpKey;
|
||||
--tmpDB2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!rc &&
|
||||
(litDefPtr->DataType == QMY_VARGRAPHIC ||
|
||||
litDefPtr->DataType == QMY_VARCHAR))
|
||||
{
|
||||
*(uint16*)(db2Data-sizeof(uint16)) =
|
||||
outLen / (litDefPtr->DataType == QMY_VARGRAPHIC ? 2 : 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = convertMySQLtoDB2(field,
|
||||
db2Field,
|
||||
literalPtr,
|
||||
(uchar*)maxPtr+((curKey.key_part[partsInUse].null_bit)? 1 : 0));
|
||||
}
|
||||
if (rc != 0) break;
|
||||
litDefPtr->Offset = (uint32_t)(literalPtr - literalsPtr);
|
||||
litDefPtr->Length = db2Field.getByteLengthInRecord();
|
||||
literalPtr = literalPtr + litDefPtr->Length; // Bump pointer for next literal
|
||||
}
|
||||
boundsPtr->HiBound.Position = literalCnt;
|
||||
if (max_key->flag == HA_READ_BEFORE_KEY && !overrideInclusion)
|
||||
boundsPtr->HiBound.Embodiment[0] = QMY_EXCLUSION;
|
||||
}
|
||||
maxPtr += curKey.key_part[partsInUse].store_length;
|
||||
}
|
||||
/*
|
||||
Bump to the next field in the key composite.
|
||||
*/
|
||||
|
||||
if ((partsInUse+1) < keyCnt)
|
||||
boundsPtr = boundsPtr + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Call DB2 to estimate the number of rows in the key range.
|
||||
*/
|
||||
if (rc == 0)
|
||||
{
|
||||
rc = db2i_ileBridge::getBridgeForThread()->recordsInRange((indexHandles[inx] ? indexHandles[inx] : db2Table->indexFile(inx)->getMasterDefnHandle()),
|
||||
spcPtr,
|
||||
keyCnt,
|
||||
literalCnt,
|
||||
boundsOff,
|
||||
litDefOff,
|
||||
literalsOff,
|
||||
cutoff,
|
||||
(uint32_t)(literalPtr - (char*)spcPtr),
|
||||
endByte,
|
||||
&recCnt,
|
||||
&rtnCode);
|
||||
}
|
||||
/*
|
||||
Set the row count and return.
|
||||
Beware that if this method returns a zero row count, MySQL assumes the
|
||||
result set for the query is zero; never return a zero row count.
|
||||
*/
|
||||
if ((rc == 0) && (rtnCode == QMY_SUCCESS || rtnCode == QMY_EARLY_EXIT))
|
||||
{
|
||||
rows = recCnt ? (ha_rows)recCnt : 1;
|
||||
}
|
||||
|
||||
rows = (rows > 0 ? rows : HA_POS_ERROR);
|
||||
|
||||
setIndexReadEstimate(inx, rows);
|
||||
|
||||
DBUG_PRINT("ha_ibmdb2i::recordsInRange",("Estimate %d rows for key %d", uint32(rows), inx));
|
||||
|
||||
DBUG_RETURN(rows);
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef DB2I_SAFESTRING_H
|
||||
#define DB2I_SAFESTRING_H
|
||||
|
||||
|
||||
#include <my_global.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
@class SafeString
|
||||
|
||||
This class was designed to provide safe, but lightweight, concatenation
|
||||
operations C strings inside pre-allocated buffers.
|
||||
*/
|
||||
class SafeString
|
||||
{
|
||||
public:
|
||||
SafeString(char* buffer, size_t size) :
|
||||
allocSize(size), curPos(0), buf(buffer)
|
||||
{
|
||||
DBUG_ASSERT(size > 0);
|
||||
buf[allocSize - 1] = 0xFF; // Set an overflow indicator
|
||||
}
|
||||
|
||||
char* ptr() { return buf; }
|
||||
operator char*() { return buf; }
|
||||
|
||||
SafeString& strcat(const char* str)
|
||||
{
|
||||
return this->strncat(str, strlen(str));
|
||||
}
|
||||
|
||||
SafeString& strcat(char one)
|
||||
{
|
||||
if (curPos < allocSize - 2)
|
||||
{
|
||||
buf[curPos++] = one;
|
||||
}
|
||||
buf[curPos] = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SafeString& strncat(const char* str, size_t len)
|
||||
{
|
||||
uint64 amountToCopy = min((allocSize-1) - curPos, len);
|
||||
memcpy(buf + curPos, str, amountToCopy);
|
||||
curPos += amountToCopy;
|
||||
buf[curPos] = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool overflowed() const { return (buf[allocSize - 1] == 0);}
|
||||
|
||||
private:
|
||||
char* buf;
|
||||
uint64 curPos;
|
||||
size_t allocSize;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "db2i_sqlStatementStream.h"
|
||||
#include "as400_types.h"
|
||||
|
||||
/**
|
||||
Add a statement to the statement stream, allocating additional memory as needed.
|
||||
|
||||
@parm stmt The statement text
|
||||
@parm length The length of the statement text
|
||||
@parm fileSortSequence The DB2 sort sequence identifier, in EBCDIC
|
||||
@parm fileSortSequenceLibrary The DB2 sort sequence library, in EBCDIC
|
||||
|
||||
@return Reference to this object
|
||||
*/
|
||||
SqlStatementStream& SqlStatementStream::addStatementInternal(const char* stmt,
|
||||
uint32 length,
|
||||
const char* fileSortSequence,
|
||||
const char* fileSortSequenceLibrary)
|
||||
{
|
||||
uint32 storageNeeded = length + sizeof(StmtHdr_t);
|
||||
storageNeeded = (storageNeeded + 3) & ~3; // We have to be 4-byte aligned.
|
||||
if (storageNeeded > storageRemaining())
|
||||
{
|
||||
// We overallocate new storage to reduce number of times reallocation is
|
||||
// needed.
|
||||
int newSize = curSize + 2 * storageNeeded;
|
||||
DBUG_PRINT("SqlStatementStream::addStatementInternal",
|
||||
("PERF: Had to realloc! Old size=%d. New size=%d", curSize, newSize));
|
||||
char* old_space = block;
|
||||
char* new_space = (char*)getNewSpace(newSize);
|
||||
memcpy(new_space, old_space, curSize);
|
||||
ptr = new_space + (ptr - old_space);
|
||||
curSize = newSize;
|
||||
}
|
||||
|
||||
DBUG_ASSERT((address64_t)ptr % 4 == 0);
|
||||
|
||||
memcpy(((StmtHdr_t*)ptr)->SrtSeqNam,
|
||||
fileSortSequence,
|
||||
sizeof(((StmtHdr_t*)ptr)->SrtSeqNam));
|
||||
memcpy(((StmtHdr_t*)ptr)->SrtSeqSch,
|
||||
fileSortSequenceLibrary,
|
||||
sizeof(((StmtHdr_t*)ptr)->SrtSeqSch));
|
||||
((StmtHdr_t*)ptr)->Length = length;
|
||||
memcpy(ptr + sizeof(StmtHdr_t), stmt, length);
|
||||
|
||||
ptr += storageNeeded;
|
||||
++statements;
|
||||
|
||||
return *this;
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DB2I_SQLSTATEMENTSTREAM_H
|
||||
#define DB2I_SQLSTATEMENTSTREAM_H
|
||||
|
||||
#include "db2i_charsetSupport.h"
|
||||
#include "qmyse.h"
|
||||
|
||||
/**
|
||||
@class SqlStatementStream
|
||||
|
||||
This class handles building the stream of SQL statements expected by the
|
||||
QMY_EXECUTE_IMMEDIATE and QMY_PREPARE_OPEN_CURSOR APIs.
|
||||
Memory allocation is handled internally.
|
||||
*/
|
||||
class SqlStatementStream
|
||||
{
|
||||
public:
|
||||
/**
|
||||
ctor to be used when multiple strings may be appended.
|
||||
*/
|
||||
SqlStatementStream(uint32 firstStringSize) : statements(0)
|
||||
{
|
||||
curSize = firstStringSize + sizeof(StmtHdr_t);
|
||||
curSize = (curSize + 3) & ~3;
|
||||
ptr = (char*) getNewSpace(curSize);
|
||||
if (ptr == NULL)
|
||||
curSize = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
ctor to be used when only a single statement will be executed.
|
||||
*/
|
||||
SqlStatementStream(const String& statement) : statements(0), block(NULL), curSize(0), ptr(0)
|
||||
{
|
||||
addStatement(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
ctor to be used when only a single statement will be executed.
|
||||
*/
|
||||
SqlStatementStream(const char* statement) : statements(0), block(NULL), curSize(0), ptr(0)
|
||||
{
|
||||
addStatement(statement);
|
||||
}
|
||||
|
||||
/**
|
||||
Append an SQL statement, specifiying the DB2 sort sequence under which
|
||||
the statement should be executed. This is important for CREATE TABLE
|
||||
and CREATE INDEX statements.
|
||||
*/
|
||||
SqlStatementStream& addStatement(const String& append, const char* fileSortSequence, const char* fileSortSequenceLibrary)
|
||||
{
|
||||
char sortSeqEbcdic[10];
|
||||
char sortSeqLibEbcdic[10];
|
||||
|
||||
DBUG_ASSERT(strlen(fileSortSequence) <= 10 &&
|
||||
strlen(fileSortSequenceLibrary) <= 10);
|
||||
memset(sortSeqEbcdic, 0x40, 10);
|
||||
memset(sortSeqLibEbcdic, 0x40, 10);
|
||||
convToEbcdic(fileSortSequence, sortSeqEbcdic, strlen(fileSortSequence));
|
||||
convToEbcdic(fileSortSequenceLibrary, sortSeqLibEbcdic, strlen(fileSortSequenceLibrary));
|
||||
|
||||
return addStatementInternal(append.ptr(), append.length(), sortSeqEbcdic, sortSeqLibEbcdic);
|
||||
}
|
||||
|
||||
/**
|
||||
Append an SQL statement using default (*HEX) sort sequence.
|
||||
*/
|
||||
SqlStatementStream& addStatement(const String& append)
|
||||
{
|
||||
const char splatHEX[] = {0x5C, 0xC8, 0xC5, 0xE7, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; // *HEX
|
||||
const char blanks[] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; //
|
||||
|
||||
return addStatementInternal(append.ptr(), append.length(), splatHEX, blanks);
|
||||
}
|
||||
|
||||
/**
|
||||
Append an SQL statement using default (*HEX) sort sequence.
|
||||
*/
|
||||
SqlStatementStream& addStatement(const char* stmt)
|
||||
{
|
||||
const char splatHEX[] = {0x5C, 0xC8, 0xC5, 0xE7, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; // *HEX
|
||||
const char blanks[] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; //
|
||||
|
||||
return addStatementInternal(stmt, strlen(stmt), splatHEX, blanks);
|
||||
}
|
||||
|
||||
char* getPtrToData() const { return block; }
|
||||
uint32 getStatementCount() const { return statements; }
|
||||
private:
|
||||
SqlStatementStream& addStatementInternal(const char* stmt,
|
||||
uint32 length,
|
||||
const char* fileSortSequence,
|
||||
const char* fileSortSequenceLibrary);
|
||||
|
||||
uint32 storageRemaining() const
|
||||
{
|
||||
return (block == NULL ? 0 : curSize - (ptr - block));
|
||||
}
|
||||
|
||||
char* getNewSpace(size_t size)
|
||||
{
|
||||
allocBase = (char*)sql_alloc(size + 15);
|
||||
block = (char*)roundToQuadWordBdy(allocBase);
|
||||
return block;
|
||||
}
|
||||
|
||||
uint32 curSize; // The size of the usable memory.
|
||||
char* allocBase; // The allocated memory (with padding for aligment)
|
||||
char* block; // The usable memory chunck (aligned for ILE)
|
||||
char* ptr; // The current position within block.
|
||||
uint32 statements; // The number of statements that have been appended.
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,162 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef DB2I_VALIDATEDPOINTER_H
|
||||
#define DB2I_VALIDATEDPOINTER_H
|
||||
|
||||
#include "db2i_ileBridge.h"
|
||||
|
||||
/**
|
||||
@class ValidatedPointer
|
||||
@brief Encapsulates a pointer registered for usage by the QMYSE APIs
|
||||
|
||||
@details As a performance optimization, to prevent pointer validation each
|
||||
time a particular pointer is thunked across to ILE, QMYSE allows us to
|
||||
"register" a pointer such that it is validated once and then subsequently
|
||||
referenced on QMYSE APIs by means of a handle value. This class should be
|
||||
used to manage memory allocation/registration/unregistration of these
|
||||
pointers. Using the alloc function guarantees that the resulting storage is
|
||||
16-byte aligned, a requirement for many pointers passed to QMYSE.
|
||||
*/
|
||||
template <class T>
|
||||
class ValidatedPointer
|
||||
{
|
||||
public:
|
||||
ValidatedPointer<T>() : address(NULL), handle(NULL) {;}
|
||||
|
||||
ValidatedPointer<T>(size_t size)
|
||||
{
|
||||
alloc(size);
|
||||
}
|
||||
|
||||
ValidatedPointer<T>(T* ptr)
|
||||
{
|
||||
assign(ptr);
|
||||
}
|
||||
|
||||
operator T*()
|
||||
{
|
||||
return address;
|
||||
};
|
||||
|
||||
operator T*() const
|
||||
{
|
||||
return address;
|
||||
};
|
||||
|
||||
operator void*()
|
||||
{
|
||||
return address;
|
||||
};
|
||||
|
||||
operator ILEMemHandle()
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
|
||||
void alloc(size_t size)
|
||||
{
|
||||
address = (T*)malloc_aligned(size);
|
||||
if (address)
|
||||
db2i_ileBridge::registerPtr(address, &handle);
|
||||
mallocedHere = 1;
|
||||
}
|
||||
|
||||
void assign(T* ptr)
|
||||
{
|
||||
address = ptr;
|
||||
db2i_ileBridge::registerPtr((void*)ptr, &handle);
|
||||
mallocedHere = 0;
|
||||
}
|
||||
|
||||
void realloc(size_t size)
|
||||
{
|
||||
dealloc();
|
||||
alloc(size);
|
||||
}
|
||||
|
||||
void reassign(T* ptr)
|
||||
{
|
||||
dealloc();
|
||||
assign(ptr);
|
||||
}
|
||||
|
||||
void dealloc()
|
||||
{
|
||||
if (address)
|
||||
{
|
||||
db2i_ileBridge::unregisterPtr(handle);
|
||||
|
||||
if (mallocedHere)
|
||||
free_aligned((void*)address);
|
||||
}
|
||||
address = NULL;
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
~ValidatedPointer()
|
||||
{
|
||||
dealloc();
|
||||
}
|
||||
|
||||
private:
|
||||
// Disable copy ctor and assignment operator, as these would break
|
||||
// the registration guarantees provided by the class.
|
||||
ValidatedPointer& operator= (const ValidatedPointer newVal);
|
||||
ValidatedPointer(ValidatedPointer& newCopy);
|
||||
|
||||
ILEMemHandle handle;
|
||||
T* address;
|
||||
char mallocedHere;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@class ValidatedObject
|
||||
@brief This class allows users to instantiate and register a particular
|
||||
object in a single step.
|
||||
*/
|
||||
template<class T>
|
||||
class ValidatedObject : public ValidatedPointer<T>
|
||||
{
|
||||
public:
|
||||
ValidatedObject<T>() : ValidatedPointer<T>(&value) {;}
|
||||
|
||||
T& operator= (const T newVal) { value = newVal; return value; }
|
||||
|
||||
private:
|
||||
T value;
|
||||
};
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,822 +0,0 @@
|
||||
/*
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
(a) Redistributions of source code must retain this list of conditions, the
|
||||
copyright notice in section {d} below, and the disclaimer following this
|
||||
list of conditions.
|
||||
(b) Redistributions in binary form must reproduce this list of conditions, the
|
||||
copyright notice in section (d) below, and the disclaimer following this
|
||||
list of conditions, in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
(c) The name of IBM may not be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
(d) The text of the required copyright notice is:
|
||||
Licensed Materials - Property of IBM
|
||||
DB2 Storage Engine Enablement
|
||||
Copyright IBM Corporation 2007,2008
|
||||
All rights reserved
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY IBM CORPORATION "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
||||
SHALL IBM CORPORATION BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/** @file ha_ibmdb2i.h
|
||||
|
||||
@brief
|
||||
|
||||
@note
|
||||
|
||||
@see
|
||||
*/
|
||||
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
#include "as400_types.h"
|
||||
#include "as400_protos.h"
|
||||
#include "db2i_global.h"
|
||||
#include "db2i_ileBridge.h"
|
||||
#include "builtins.h"
|
||||
#include "db2i_misc.h"
|
||||
#include "db2i_file.h"
|
||||
#include "db2i_blobCollection.h"
|
||||
#include "db2i_collationSupport.h"
|
||||
#include "db2i_validatedPointer.h"
|
||||
#include "db2i_ioBuffers.h"
|
||||
#include "db2i_errors.h"
|
||||
#include "db2i_sqlStatementStream.h"
|
||||
|
||||
/** @brief
|
||||
IBMDB2I_SHARE is a structure that will be shared among all open handlers.
|
||||
It is used to describe the underlying table definition, and it caches
|
||||
table statistics.
|
||||
*/
|
||||
struct IBMDB2I_SHARE {
|
||||
char *table_name;
|
||||
uint table_name_length,use_count;
|
||||
pthread_mutex_t mutex;
|
||||
THR_LOCK lock;
|
||||
|
||||
db2i_table* db2Table;
|
||||
|
||||
class CStats
|
||||
{
|
||||
public:
|
||||
void cacheUpdateTime(time_t time)
|
||||
{update_time = time; initFlag |= lastModTime;}
|
||||
time_t getUpdateTime() const
|
||||
{return update_time;}
|
||||
void cacheRowCount(ha_rows rows)
|
||||
{records = rows; initFlag |= rowCount;}
|
||||
ha_rows getRowCount() const
|
||||
{return records;}
|
||||
void cacheDelRowCount(ha_rows rows)
|
||||
{deleted = rows; initFlag |= deletedRowCount;}
|
||||
ha_rows getDelRowCount() const
|
||||
{return deleted;}
|
||||
void cacheMeanLength(ulong len)
|
||||
{mean_rec_length = len; initFlag |= meanRowLen;}
|
||||
ulong getMeanLength()
|
||||
{return mean_rec_length;}
|
||||
void cacheAugmentedDataLength(ulong len)
|
||||
{data_file_length = len; initFlag |= ioCount;}
|
||||
ulong getAugmentedDataLength()
|
||||
{return data_file_length;}
|
||||
bool isInited(uint flags)
|
||||
{return initFlag & flags;}
|
||||
void invalidate(uint flags)
|
||||
{initFlag &= ~flags;}
|
||||
|
||||
private:
|
||||
uint initFlag;
|
||||
time_t update_time;
|
||||
ha_rows records;
|
||||
ha_rows deleted;
|
||||
ulong mean_rec_length;
|
||||
ulong data_file_length;
|
||||
} cachedStats;
|
||||
|
||||
};
|
||||
|
||||
class ha_ibmdb2i: public handler
|
||||
{
|
||||
THR_LOCK_DATA lock; ///< MySQL lock
|
||||
IBMDB2I_SHARE *share; ///< Shared lock info
|
||||
|
||||
// The record we are positioned on, together with the handle used to get
|
||||
// i.
|
||||
uint32 currentRRN;
|
||||
uint32 rrnAssocHandle;
|
||||
|
||||
// Dup key values needed by info()
|
||||
uint32 lastDupKeyRRN;
|
||||
uint32 lastDupKeyID;
|
||||
|
||||
bool returnDupKeysImmediately;
|
||||
|
||||
// Dup key value need by update()
|
||||
bool onDupUpdate;
|
||||
|
||||
|
||||
db2i_table* db2Table;
|
||||
|
||||
// The file handle of the PF or LF being accessed by the current operation.
|
||||
FILE_HANDLE activeHandle;
|
||||
|
||||
// The file handle of the underlying PF
|
||||
FILE_HANDLE dataHandle;
|
||||
|
||||
// Array of file handles belonging to the underlying LFs
|
||||
FILE_HANDLE* indexHandles;
|
||||
|
||||
// Flag to indicate whether a call needs to be made to unlock a row when
|
||||
// a read operation has ended. DB2 will handle row unlocking as we move
|
||||
// through rows, but if an operation ends before we reach the end of a file,
|
||||
// DB2 needs to know to unlock the last row read.
|
||||
bool releaseRowNeeded;
|
||||
|
||||
// Pointer to a definition of the layout of the row buffer for the file
|
||||
// described by activeHandle
|
||||
const db2i_file::RowFormat* activeFormat;
|
||||
|
||||
IORowBuffer keyBuf;
|
||||
uint32 keyLen;
|
||||
|
||||
IOWriteBuffer multiRowWriteBuf;
|
||||
IOAsyncReadBuffer multiRowReadBuf;
|
||||
|
||||
IOAsyncReadBuffer* activeReadBuf;
|
||||
IOWriteBuffer* activeWriteBuf;
|
||||
|
||||
BlobCollection* blobReadBuffers; // Dynamically allocated per query and used
|
||||
// to manage the buffers used for reading LOBs
|
||||
ValidatedPointer<char>* blobWriteBuffers;
|
||||
|
||||
// Return codes are not used/honored by rnd_init and start_bulk_insert
|
||||
// so we need a way to signal the failure "downstream" to subsequent
|
||||
// functions.
|
||||
int last_rnd_init_rc;
|
||||
int last_index_init_rc;
|
||||
int last_start_bulk_insert_rc;
|
||||
|
||||
// end_bulk_insert may get called twice for a single start_bulk_insert
|
||||
// This is our way to do cleanup only once.
|
||||
bool outstanding_start_bulk_insert;
|
||||
|
||||
// Auto_increment 'increment by' value needed by write_row()
|
||||
uint32 incrementByValue;
|
||||
bool default_identity_value;
|
||||
|
||||
// Flags and values used during write operations for auto_increment processing
|
||||
bool autoIncLockAcquired;
|
||||
bool got_auto_inc_values;
|
||||
uint64 next_identity_value;
|
||||
|
||||
// The access intent indicated by the last external_locks() call.
|
||||
// May be either QMY_READ or QMY_UPDATABLE
|
||||
char accessIntent;
|
||||
char readAccessIntent;
|
||||
|
||||
ha_rows* indexReadSizeEstimates;
|
||||
|
||||
MEM_ROOT conversionBufferMemroot;
|
||||
|
||||
bool forceSingleRowRead;
|
||||
|
||||
bool readAllColumns;
|
||||
|
||||
bool invalidDataFound;
|
||||
|
||||
db2i_ileBridge* cachedBridge;
|
||||
|
||||
ValidatedObject<volatile uint32> curConnection;
|
||||
uint16 activeReferences;
|
||||
|
||||
public:
|
||||
|
||||
ha_ibmdb2i(handlerton *hton, TABLE_SHARE *table_arg);
|
||||
~ha_ibmdb2i();
|
||||
|
||||
const char *table_type() const { return "IBMDB2I"; }
|
||||
const char *index_type(uint inx) { return "RADIX"; }
|
||||
const key_map *keys_to_use_for_scanning() { return &key_map_full; }
|
||||
const char **bas_ext() const;
|
||||
|
||||
ulonglong table_flags() const
|
||||
{
|
||||
return HA_NULL_IN_KEY | HA_REC_NOT_IN_SEQ | HA_AUTO_PART_KEY |
|
||||
HA_PARTIAL_COLUMN_READ |
|
||||
HA_DUPLICATE_POS | HA_NO_PREFIX_CHAR_KEYS |
|
||||
HA_HAS_RECORDS | HA_BINLOG_ROW_CAPABLE | HA_REQUIRES_KEY_COLUMNS_FOR_DELETE |
|
||||
HA_CAN_INDEX_BLOBS;
|
||||
}
|
||||
|
||||
ulong index_flags(uint inx, uint part, bool all_parts) const;
|
||||
|
||||
// Note that we do not implement max_supported_record_length.
|
||||
// We'll let create fail accordingly if the row is
|
||||
// too long. This allows us to hide the fact that varchars > 32K are being
|
||||
// implemented as DB2 LOBs.
|
||||
|
||||
uint max_supported_keys() const { return 4000; }
|
||||
uint max_supported_key_parts() const { return MAX_DB2_KEY_PARTS; }
|
||||
uint max_supported_key_length() const { return 32767; }
|
||||
uint max_supported_key_part_length() const { return 32767; }
|
||||
double read_time(uint index, uint ranges, ha_rows rows);
|
||||
double scan_time();
|
||||
int open(const char *name, int mode, uint test_if_locked);
|
||||
int close(void);
|
||||
int write_row(uchar * buf);
|
||||
int update_row(const uchar * old_data, uchar * new_data);
|
||||
int delete_row(const uchar * buf);
|
||||
int index_init(uint idx, bool sorted);
|
||||
int index_read(uchar * buf, const uchar * key,
|
||||
uint key_len, enum ha_rkey_function find_flag);
|
||||
int index_next(uchar * buf);
|
||||
int index_read_last(uchar * buf, const uchar * key, uint key_len);
|
||||
int index_next_same(uchar *buf, const uchar *key, uint keylen);
|
||||
int index_prev(uchar * buf);
|
||||
int index_first(uchar * buf);
|
||||
int index_last(uchar * buf);
|
||||
int rnd_init(bool scan);
|
||||
int rnd_end();
|
||||
int rnd_next(uchar *buf);
|
||||
int rnd_pos(uchar * buf, uchar *pos);
|
||||
void position(const uchar *record);
|
||||
int info(uint);
|
||||
ha_rows records();
|
||||
int extra(enum ha_extra_function operation);
|
||||
int external_lock(THD *thd, int lock_type);
|
||||
int delete_all_rows(void);
|
||||
ha_rows records_in_range(uint inx, key_range *min_key,
|
||||
key_range *max_key);
|
||||
int delete_table(const char *from);
|
||||
int rename_table(const char * from, const char * to);
|
||||
int create(const char *name, TABLE *form,
|
||||
HA_CREATE_INFO *create_info);
|
||||
int updateFrm(TABLE *table_def, File file);
|
||||
int openTableDef(TABLE *table_def);
|
||||
int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
|
||||
int prepare_drop_index(TABLE *table_arg, uint *key_num, uint num_of_keys);
|
||||
int final_drop_index(TABLE *table_arg) {return 0;}
|
||||
void get_auto_increment(ulonglong offset, ulonglong increment,
|
||||
ulonglong nb_desired_values,
|
||||
ulonglong *first_value,
|
||||
ulonglong *nb_reserved_values);
|
||||
int reset_auto_increment(ulonglong value);
|
||||
void restore_auto_increment(ulonglong prev_insert_id) {return;}
|
||||
void update_create_info(HA_CREATE_INFO *create_info);
|
||||
int getNextIdVal(ulonglong *value);
|
||||
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
|
||||
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
|
||||
bool can_switch_engines();
|
||||
void free_foreign_key_create_info(char* str);
|
||||
char* get_foreign_key_create_info();
|
||||
int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
|
||||
uint referenced_by_foreign_key();
|
||||
bool check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes);
|
||||
virtual bool get_error_message(int error, String *buf);
|
||||
|
||||
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
|
||||
enum thr_lock_type lock_type);
|
||||
|
||||
bool low_byte_first() const { return 0; }
|
||||
void unlock_row();
|
||||
int index_end();
|
||||
int reset();
|
||||
static int doCommit(handlerton *hton, THD *thd, bool all);
|
||||
static int doRollback(handlerton *hton, THD *thd, bool all);
|
||||
void start_bulk_insert(ha_rows rows);
|
||||
int end_bulk_insert();
|
||||
int start_stmt(THD *thd, thr_lock_type lock_type);
|
||||
|
||||
void initBridge(THD* thd = NULL)
|
||||
{
|
||||
if (thd == NULL) thd = ha_thd();
|
||||
DBUG_PRINT("ha_ibmdb2i::initBridge",("Initing bridge. Conn ID=%d", thd->thread_id));
|
||||
cachedBridge = db2i_ileBridge::getBridgeForThread(thd);
|
||||
}
|
||||
|
||||
db2i_ileBridge* bridge() {DBUG_ASSERT(cachedBridge); return cachedBridge;}
|
||||
|
||||
static uint8 autoCommitIsOn(THD* thd)
|
||||
{ return (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ? QMY_NO : QMY_YES); }
|
||||
|
||||
uint8 getCommitLevel();
|
||||
uint8 getCommitLevel(THD* thd);
|
||||
|
||||
static int doSavepointSet(THD* thd, char* name)
|
||||
{
|
||||
return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_SET_SAVEPOINT,
|
||||
name);
|
||||
}
|
||||
|
||||
static int doSavepointRollback(THD* thd, char* name)
|
||||
{
|
||||
return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_ROLLBACK_SAVEPOINT,
|
||||
name);
|
||||
}
|
||||
|
||||
static int doSavepointRelease(THD* thd, char* name)
|
||||
{
|
||||
return db2i_ileBridge::getBridgeForThread(thd)->savepoint(QMY_RELEASE_SAVEPOINT,
|
||||
name);
|
||||
}
|
||||
|
||||
// We can't guarantee that the rows we know about when this is called
|
||||
// will be the same number of rows that read returns (since DB2 activity
|
||||
// may insert additional rows). Therefore, we do as the Federated SE and
|
||||
// return the max possible.
|
||||
ha_rows estimate_rows_upper_bound()
|
||||
{
|
||||
return HA_POS_ERROR;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
enum enum_TimeFormat
|
||||
{
|
||||
TIME_OF_DAY,
|
||||
DURATION
|
||||
};
|
||||
|
||||
enum enum_BlobMapping
|
||||
{
|
||||
AS_BLOB,
|
||||
AS_VARCHAR
|
||||
};
|
||||
|
||||
enum enum_ZeroDate
|
||||
{
|
||||
NO_SUBSTITUTE,
|
||||
SUBSTITUTE_0001_01_01
|
||||
};
|
||||
|
||||
enum enum_YearFormat
|
||||
{
|
||||
CHAR4,
|
||||
SMALLINT
|
||||
};
|
||||
|
||||
enum_ZeroDate cachedZeroDateOption;
|
||||
|
||||
IBMDB2I_SHARE *get_share(const char *table_name, TABLE *table);
|
||||
int free_share(IBMDB2I_SHARE *share);
|
||||
int32 mungeDB2row(uchar* record, const char* dataPtr, const char* nullMapPtr, bool skipLOBs);
|
||||
int prepareRowForWrite(char* data, char* nulls, bool honorIdentCols);
|
||||
int prepareReadBufferForLobs();
|
||||
int32 prepareWriteBufferForLobs();
|
||||
uint32 adjustLobBuffersForRead();
|
||||
bool lobFieldsRequested();
|
||||
int convertFieldChars(enum_conversionDirection direction,
|
||||
uint16 fieldID,
|
||||
const char* input,
|
||||
char* output,
|
||||
size_t ilen,
|
||||
size_t olen,
|
||||
size_t* outDataLen,
|
||||
bool tacitErrors=FALSE,
|
||||
size_t* substChars=NULL);
|
||||
|
||||
/**
|
||||
Fast integer log2 function
|
||||
*/
|
||||
uint64 log_2(uint64 val)
|
||||
{
|
||||
uint64 exp = 0;
|
||||
while( (val >> exp) != 0)
|
||||
{
|
||||
exp++;
|
||||
}
|
||||
DBUG_ASSERT(exp-1 == (uint64)log2(val));
|
||||
return exp-1;
|
||||
}
|
||||
|
||||
void bumpInUseCounter(uint16 amount)
|
||||
{
|
||||
activeReferences += amount;
|
||||
DBUG_PRINT("ha_ibmdb2i::bumpInUseCounter", ("activeReferences = %d", activeReferences));
|
||||
if (activeReferences)
|
||||
curConnection = (uint32)(ha_thd()->thread_id);
|
||||
else
|
||||
curConnection = 0;
|
||||
}
|
||||
|
||||
|
||||
int useDataFile()
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::useDataFile");
|
||||
|
||||
int rc = 0;
|
||||
if (!dataHandle)
|
||||
rc = db2Table->dataFile()->allocateNewInstance(&dataHandle, curConnection);
|
||||
else if (activeHandle == dataHandle)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
DBUG_ASSERT(activeHandle == 0);
|
||||
|
||||
if (likely(rc == 0))
|
||||
{
|
||||
activeHandle = dataHandle;
|
||||
bumpInUseCounter(1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
void releaseAnyLockedRows()
|
||||
{
|
||||
if (releaseRowNeeded)
|
||||
{
|
||||
DBUG_PRINT("ha_ibmdb2i::releaseAnyLockedRows", ("Releasing rows"));
|
||||
db2i_ileBridge::getBridgeForThread()->rrlslck(activeHandle, accessIntent);
|
||||
releaseRowNeeded = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void releaseDataFile()
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::releaseDataFile");
|
||||
releaseAnyLockedRows();
|
||||
bumpInUseCounter(-1);
|
||||
DBUG_ASSERT((volatile int)activeReferences >= 0);
|
||||
activeHandle = 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
int useIndexFile(int idx);
|
||||
|
||||
void releaseIndexFile(int idx)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::releaseIndexFile");
|
||||
releaseAnyLockedRows();
|
||||
bumpInUseCounter(-1);
|
||||
DBUG_ASSERT((volatile int)activeReferences >= 0);
|
||||
activeHandle = 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
FILE_HANDLE allocateFileHandle(char* database, char* table, int* activityReference, bool hasBlobs);
|
||||
|
||||
int updateBuffers(const db2i_file::RowFormat* format, uint rowsToRead, uint rowsToWrite);
|
||||
|
||||
int flushWrite(FILE_HANDLE fileHandle, uchar* buf = NULL);
|
||||
|
||||
int alterStartWith();
|
||||
|
||||
int buildDB2ConstraintString(LEX* lex,
|
||||
String& appendHere,
|
||||
const char* database,
|
||||
Field** fields,
|
||||
char* fileSortSequenceType,
|
||||
char* fileSortSequence,
|
||||
char* fileSortSequenceLibrary);
|
||||
|
||||
void releaseWriteBuffer();
|
||||
|
||||
void setIndexReadEstimate(uint index, ha_rows rows)
|
||||
{
|
||||
if (!indexReadSizeEstimates)
|
||||
{
|
||||
indexReadSizeEstimates = (ha_rows*)my_malloc(sizeof(ha_rows) * table->s->keys, MYF(MY_WME | MY_ZEROFILL));
|
||||
}
|
||||
indexReadSizeEstimates[index] = rows;
|
||||
}
|
||||
|
||||
ha_rows getIndexReadEstimate(uint index)
|
||||
{
|
||||
if (indexReadSizeEstimates)
|
||||
return max(indexReadSizeEstimates[index], 1);
|
||||
|
||||
return 10000; // Assume index scan if no estimate exists.
|
||||
}
|
||||
|
||||
|
||||
void quiesceAllFileHandles()
|
||||
{
|
||||
db2i_ileBridge* bridge = db2i_ileBridge::getBridgeForThread();
|
||||
if (dataHandle)
|
||||
{
|
||||
bridge->quiesceFileInstance(dataHandle);
|
||||
}
|
||||
|
||||
for (int idx = 0; idx < table_share->keys; ++idx)
|
||||
{
|
||||
if (indexHandles[idx] != 0)
|
||||
{
|
||||
bridge->quiesceFileInstance(indexHandles[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32 buildCreateIndexStatement(SqlStatementStream& sqlStream,
|
||||
KEY& key,
|
||||
bool isPrimary,
|
||||
const char* db2LibName,
|
||||
const char* db2FileName);
|
||||
|
||||
int32 buildIndexFieldList(String& appendHere,
|
||||
const KEY& key,
|
||||
bool isPrimary,
|
||||
char* fileSortSequenceType,
|
||||
char* fileSortSequence,
|
||||
char* fileSortSequenceLibrary);
|
||||
|
||||
// Specify NULL for data when using the data pointed to by field
|
||||
int32 convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char* db2Buf, const uchar* data = NULL);
|
||||
|
||||
int32 convertDB2toMySQL(const DB2Field& db2Field, Field* field, const char* buf);
|
||||
int getFieldTypeMapping(Field* field,
|
||||
String& mapping,
|
||||
enum_TimeFormat timeFormate,
|
||||
enum_BlobMapping blobMapping,
|
||||
enum_ZeroDate zeroDateHandling,
|
||||
bool propagateDefaults,
|
||||
enum_YearFormat yearFormat);
|
||||
|
||||
int getKeyFromName(const char* name, size_t len);
|
||||
|
||||
void releaseActiveHandle()
|
||||
{
|
||||
if (activeHandle == dataHandle)
|
||||
releaseDataFile();
|
||||
else
|
||||
releaseIndexFile(active_index);
|
||||
}
|
||||
|
||||
|
||||
int32 finishBulkInsert();
|
||||
|
||||
void doInitialRead(char orientation,
|
||||
uint32 rowsToBuffer,
|
||||
ILEMemHandle key = 0,
|
||||
int keyLength = 0,
|
||||
int keyParts = 0);
|
||||
|
||||
|
||||
int32 readFromBuffer(uchar* destination, char orientation)
|
||||
{
|
||||
char* row;
|
||||
int32 rc = 0;
|
||||
row = activeReadBuf->readNextRow(orientation, currentRRN);
|
||||
|
||||
if (unlikely(!row))
|
||||
{
|
||||
rc = activeReadBuf->lastrc();
|
||||
if (rc == QMY_ERR_LOB_SPACE_TOO_SMALL)
|
||||
{
|
||||
rc = handleLOBReadOverflow();
|
||||
if (rc == 0)
|
||||
{
|
||||
DBUG_ASSERT(activeReadBuf->rowCount() == 1);
|
||||
row = activeReadBuf->readNextRow(orientation, currentRRN);
|
||||
|
||||
if (unlikely(!row))
|
||||
rc = activeReadBuf->lastrc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(rc == 0))
|
||||
{
|
||||
rrnAssocHandle = activeHandle;
|
||||
rc = mungeDB2row(destination, row, row+activeReadBuf->getRowNullOffset(), false);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int32 handleLOBReadOverflow();
|
||||
|
||||
char* getCharacterConversionBuffer(int fieldId, int length)
|
||||
{
|
||||
if (unlikely(!alloc_root_inited(&conversionBufferMemroot)))
|
||||
init_alloc_root(&conversionBufferMemroot, 8192, 0);
|
||||
|
||||
return (char*)alloc_root(&conversionBufferMemroot, length);;
|
||||
}
|
||||
|
||||
void resetCharacterConversionBuffers()
|
||||
{
|
||||
if (alloc_root_inited(&conversionBufferMemroot))
|
||||
{
|
||||
free_root(&conversionBufferMemroot, MYF(MY_MARK_BLOCKS_FREE));
|
||||
}
|
||||
}
|
||||
|
||||
void tweakReadSet()
|
||||
{
|
||||
THD* thd = ha_thd();
|
||||
int command = thd_sql_command(thd);
|
||||
if ((command == SQLCOM_UPDATE ||
|
||||
command == SQLCOM_UPDATE_MULTI) ||
|
||||
((command == SQLCOM_DELETE ||
|
||||
command == SQLCOM_DELETE_MULTI) &&
|
||||
thd->options & OPTION_BIN_LOG))
|
||||
readAllColumns = TRUE;
|
||||
else
|
||||
readAllColumns = FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
*/
|
||||
int useFileByHandle(char intent,
|
||||
FILE_HANDLE handle)
|
||||
{
|
||||
DBUG_ENTER("ha_ibmdb2i::useFileByHandle");
|
||||
|
||||
const db2i_file* file;
|
||||
if (handle == dataHandle)
|
||||
file = db2Table->dataFile();
|
||||
else
|
||||
{
|
||||
for (uint i = 0; i < table_share->keys; ++i)
|
||||
{
|
||||
if (indexHandles[i] == handle)
|
||||
{
|
||||
file = db2Table->indexFile(i);
|
||||
active_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int rc = file->obtainRowFormat(handle, intent, getCommitLevel(), &activeFormat);
|
||||
if (likely(rc == 0))
|
||||
{
|
||||
activeHandle = handle;
|
||||
bumpInUseCounter(1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
const db2i_file* getFileForActiveHandle() const
|
||||
{
|
||||
if (activeHandle == dataHandle)
|
||||
return db2Table->dataFile();
|
||||
else
|
||||
for (uint i = 0; i < table_share->keys; ++i)
|
||||
if (indexHandles[i] == activeHandle)
|
||||
return db2Table->indexFile(i);
|
||||
DBUG_ASSERT(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int prepReadBuffer(ha_rows rowsToRead, const db2i_file* file, char intent);
|
||||
int prepWriteBuffer(ha_rows rowsToWrite, const db2i_file* file);
|
||||
|
||||
void invalidateCachedStats()
|
||||
{
|
||||
share->cachedStats.invalidate(rowCount | deletedRowCount | objLength |
|
||||
meanRowLen | ioCount);
|
||||
}
|
||||
|
||||
void warnIfInvalidData()
|
||||
{
|
||||
if (unlikely(invalidDataFound))
|
||||
{
|
||||
warning(ha_thd(), DB2I_ERR_INVALID_DATA, table->alias);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Calculate the maximum value that a particular field can hold.
|
||||
|
||||
This is used to anticipate overflows in the auto_increment processing.
|
||||
|
||||
@param field The Field to be analyzed
|
||||
|
||||
@return The maximum value
|
||||
*/
|
||||
static uint64 maxValueForField(const Field* field)
|
||||
{
|
||||
uint64 maxValue=0;
|
||||
switch (field->type())
|
||||
{
|
||||
case MYSQL_TYPE_TINY:
|
||||
if (((const Field_num*)field)->unsigned_flag)
|
||||
maxValue = (1 << 8) - 1;
|
||||
else
|
||||
maxValue = (1 << 7) - 1;
|
||||
break;
|
||||
case MYSQL_TYPE_SHORT:
|
||||
if (((const Field_num*)field)->unsigned_flag)
|
||||
maxValue = (1 << 16) - 1;
|
||||
else
|
||||
maxValue = (1 << 15) - 1;
|
||||
break;
|
||||
case MYSQL_TYPE_INT24:
|
||||
if (((const Field_num*)field)->unsigned_flag)
|
||||
maxValue = (1 << 24) - 1;
|
||||
else
|
||||
maxValue = (1 << 23) - 1;
|
||||
break;
|
||||
case MYSQL_TYPE_LONG:
|
||||
if (((const Field_num*)field)->unsigned_flag)
|
||||
maxValue = (1LL << 32) - 1;
|
||||
else
|
||||
maxValue = (1 << 31) - 1;
|
||||
break;
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
if (((const Field_num*)field)->unsigned_flag)
|
||||
maxValue = ~(0LL);
|
||||
else
|
||||
maxValue = 1 << 63 - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
void cleanupBuffers()
|
||||
{
|
||||
if (blobReadBuffers)
|
||||
{
|
||||
delete blobReadBuffers;
|
||||
blobReadBuffers = NULL;
|
||||
}
|
||||
if (blobWriteBuffers)
|
||||
{
|
||||
delete[] blobWriteBuffers;
|
||||
blobWriteBuffers = NULL;
|
||||
}
|
||||
if (alloc_root_inited(&conversionBufferMemroot))
|
||||
{
|
||||
free_root(&conversionBufferMemroot, MYF(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Generate a valid RCDFMT name based on the name of the table.
|
||||
|
||||
The RCDFMT name is devised by munging the name of the table,
|
||||
uppercasing all ascii alpha-numeric characters and replacing all other
|
||||
characters with underscores until up to ten characters have been generated.
|
||||
|
||||
@param tableName The name of the table, as given on the MySQL
|
||||
CREATE TABLE statement
|
||||
@param[out] query The string to receive the generated RCDFMT name
|
||||
*/
|
||||
static void generateAndAppendRCDFMT(const char* tableName, String& query)
|
||||
{
|
||||
char rcdfmt[11];
|
||||
|
||||
// The RCDFMT name must begin with an alpha character.
|
||||
// We enforce this by skipping to the first alpha character in the table
|
||||
// name. If no alpha character exists, we use 'X' for the RCDFMT name;
|
||||
|
||||
while (*tableName &&
|
||||
(!my_isascii(*tableName) ||
|
||||
!my_isalpha(system_charset_info, *tableName)))
|
||||
{
|
||||
tableName += my_mbcharlen(system_charset_info, *tableName);
|
||||
}
|
||||
|
||||
if (unlikely(!(*tableName)))
|
||||
{
|
||||
rcdfmt[0]= 'X';
|
||||
rcdfmt[1]= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int r= 0;
|
||||
while ((r < sizeof(rcdfmt)-1) && *tableName)
|
||||
{
|
||||
if (my_isascii(*tableName) &&
|
||||
my_isalnum(system_charset_info, *tableName))
|
||||
rcdfmt[r] = my_toupper(system_charset_info, *tableName);
|
||||
else
|
||||
rcdfmt[r] = '_';
|
||||
|
||||
++r;
|
||||
tableName += my_mbcharlen(system_charset_info, *tableName);
|
||||
}
|
||||
rcdfmt[r]= 0;
|
||||
}
|
||||
query.append(STRING_WITH_LEN(" RCDFMT "));
|
||||
query.append(rcdfmt);
|
||||
}
|
||||
|
||||
int32 generateShadowIndex(SqlStatementStream& stream,
|
||||
const KEY& key,
|
||||
const char* libName,
|
||||
const char* fileName,
|
||||
const String& fieldDefinition);
|
||||
};
|
@ -1,12 +0,0 @@
|
||||
MYSQL_STORAGE_ENGINE([ibmdb2i], [], [IBM DB2 for i Storage Engine],
|
||||
[IBM DB2 for i Storage Engine], [max,max-no-ndb])
|
||||
MYSQL_PLUGIN_DYNAMIC([ibmdb2i], [ha_ibmdb2i.la])
|
||||
|
||||
AC_CHECK_HEADER([qlgusr.h],
|
||||
# qlgusr.h is just one of the headers from the i5/OS PASE environment; the
|
||||
# EBCDIC headers are in /QIBM/include, and have to be converted to ASCII
|
||||
# before cpp gets to them
|
||||
[:],
|
||||
# Missing PASE environment, can't build this engine
|
||||
[mysql_plugin_ibmdb2i=no
|
||||
with_plugin_ibmdb2i=no])
|
110
win/README
110
win/README
@ -1,114 +1,8 @@
|
||||
Windows building readme
|
||||
======================================
|
||||
|
||||
----------------IMPORTANT----------------------------
|
||||
This readme outlines the instructions for building
|
||||
MySQL for Windows staring from version 5.1.
|
||||
This readme does not apply to MySQL versions 5.0
|
||||
or ealier.
|
||||
-----------------------------------------------------
|
||||
|
||||
The Windows build system uses a tool named CMake to generate build files for
|
||||
a variety of project systems. This tool is combined with a set of jscript
|
||||
files to enable building of MySQL for Windows directly out of a bzr clone.
|
||||
For relevant information, please refer to http://forge.mysql.com/wiki/CMake
|
||||
The steps required are below.
|
||||
|
||||
Step 1:
|
||||
-------
|
||||
|
||||
Install a Windows C++ compiler. If you don't have one, you can use
|
||||
the free compiler "Visual C++ 2005 express edition", which from Cmake
|
||||
point of view is same as Visual studio 8:
|
||||
http://msdn.microsoft.com/vstudio/express/
|
||||
|
||||
Step 2
|
||||
------
|
||||
Download and install CMake. It can be downloaded from http://www.cmake.org.
|
||||
Once it is installed, modify your path to make sure you can execute
|
||||
the cmake binary.
|
||||
|
||||
Step 3
|
||||
------
|
||||
Download and install bison for Windows. It can be downloaded from
|
||||
http://gnuwin32.sourceforge.net/packages/bison.htm. Please download using
|
||||
the link named "Complete package, excluding sources". This includes an
|
||||
installer that will install bison. After the installer finishes, modify
|
||||
your path so that you can execute bison.
|
||||
|
||||
(As an alternative you can take the sql_yacc.yy and sql_yacc.h files from a
|
||||
matching mysql tar distribution and drop them into the sql directory just
|
||||
before you start the build)
|
||||
|
||||
Step 4
|
||||
------
|
||||
One of the nice CMake features is "out-of-source" build support, which
|
||||
means not building in the source directory, but in dedicated build
|
||||
directory. This keeps the source directory clean and allows for more than
|
||||
single build tree for the same source tree (e.g debug and release, 32 and
|
||||
64 bit etc). We'll create subdirectory "bld" in the source directory for
|
||||
this purpose. Clone your bzr tree to any location you like.
|
||||
|
||||
Step 5
|
||||
------
|
||||
From the root of your installation directory use cmake . -L to see the
|
||||
various configuration parameters.
|
||||
|
||||
So the command line could look like:
|
||||
|
||||
cmake .. -G "target" -DWITH_INNOBASE_STORAGE_ENGINE=1
|
||||
|
||||
The recommended way of configuring would be to use -DBUILD_CONFIG=mysql_release
|
||||
to build binaries exactly the same as the official MySQL releases.
|
||||
|
||||
Step 6
|
||||
------
|
||||
|
||||
From the root of your installation directory/bzr clone, you can
|
||||
use cmake to compile the sources. Use cmake --help when necessary.
|
||||
Before you start building the sources, please remove the old build area
|
||||
created from an earlier run and start afresh.
|
||||
|
||||
C:\> del bld
|
||||
C:\> md bld
|
||||
C:\> cd bld
|
||||
C:\> cmake .. -G "target name" -DBUILD_CONFIG=mysql_release
|
||||
|
||||
|
||||
For Example:
|
||||
To generate the Win64 project files using Visual Studio 9, you would run
|
||||
cmake .. -G "Visual Studio 9 2008 Win64"
|
||||
|
||||
Other target names supported using CMake 2.6 patch 4 are:
|
||||
|
||||
Visual Studio 7 "Visual Studio 7 .NET 2003"
|
||||
Visual Studio 8 "Visual Studio 8 2005"
|
||||
Visual Studio 8 (64 bit) "Visual Studio 8 2005 Win64"
|
||||
Visual Studio 9 "Visual Studio 9 2008"
|
||||
Visual Studio 9 (64 bit) "Visual Studio 9 2008 Win64"
|
||||
|
||||
For generating project files using Visual Studio 10, you need CMake 2.8
|
||||
or higher and corresponding target names are
|
||||
Visual Studio 10 "Visual Studio 10"
|
||||
Visual Studio 10 (64 bit) "Visual Studio 10 Win64"
|
||||
|
||||
Step 7
|
||||
------
|
||||
From the root of your bzr clone, start your build.
|
||||
|
||||
For Visual Studio, execute mysql.sln. This will start the IDE
|
||||
and you can click the build solution menu option.
|
||||
|
||||
Alternatively, you could start the build from command line as follows
|
||||
|
||||
devenv mysql.sln /build relwithdebinfo
|
||||
|
||||
Current issues
|
||||
--------------
|
||||
1. After changing configuration (eg. adding or removing a storage engine), it
|
||||
may be necessary to clean the build tree to remove any stale objects.
|
||||
|
||||
2. To use Visual C++ Express Edition you also need to install the Platform SDK.
|
||||
Please see this link: http://msdn.microsoft.com/vstudio/express/visualc/usingpsdk/
|
||||
At step 5 you only need to add the libraries advapi32.lib and user32.lib to
|
||||
the file "corewin_express.vsprops" in order to avoid link errors.
|
||||
For relevant information and/or for building binaries from source distribution,
|
||||
please refer to http://forge.mysql.com/wiki/CMake
|
||||
|
Loading…
x
Reference in New Issue
Block a user