merge
This commit is contained in:
commit
5a8b8b6493
@ -75,4 +75,40 @@ CALL p1 ();
|
|||||||
ERROR HY000: Trigger does not exist
|
ERROR HY000: Trigger does not exist
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
DROP PROCEDURE p1;
|
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
|
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 TABLE t1;
|
||||||
DROP PROCEDURE p1;
|
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
|
--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
|
If the DB has changed, the pointer has changed too, but the
|
||||||
original thd->db will then have been freed
|
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
|
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
|
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
|
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
|
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.
|
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
|
For relevant information and/or for building binaries from source distribution,
|
||||||
The steps required are below.
|
please refer to http://forge.mysql.com/wiki/CMake
|
||||||
|
|
||||||
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.
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user